Auto merge of #16778 - emilio:snapshots, r=bholley

Take all the snapshots into account in the style system

See [bug 1355343](https://bugzilla.mozilla.org/show_bug.cgi?id=1355343).

The servo part of this patch presumably needs some polishing, let's see.

<!-- 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/16778)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-05-10 15:08:59 -05:00 committed by GitHub
commit c8171ed5d7
22 changed files with 2194 additions and 1137 deletions

View file

@ -37,6 +37,7 @@ use gecko_bindings::structs::GeckoFontMetrics;
use gecko_bindings::structs::Keyframe;
use gecko_bindings::structs::ServoBundledURI;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::ServoElementSnapshotTable;
use gecko_bindings::structs::SheetParsingMode;
use gecko_bindings::structs::StyleBasicShape;
use gecko_bindings::structs::StyleBasicShapeType;
@ -902,8 +903,9 @@ extern "C" {
-> nsChangeHint;
}
extern "C" {
pub fn Gecko_CreateElementSnapshot(element: RawGeckoElementBorrowed)
-> ServoElementSnapshotOwned;
pub fn Gecko_GetElementSnapshot(table: *const ServoElementSnapshotTable,
element: RawGeckoElementBorrowed)
-> *const ServoElementSnapshot;
}
extern "C" {
pub fn Gecko_DropElementSnapshot(snapshot: ServoElementSnapshotOwned);
@ -2171,10 +2173,6 @@ extern "C" {
extern "C" {
pub fn Servo_Shutdown();
}
extern "C" {
pub fn Servo_Element_GetSnapshot(element: RawGeckoElementBorrowed)
-> *mut ServoElementSnapshot;
}
extern "C" {
pub fn Servo_Element_GetStyleRuleList(element: RawGeckoElementBorrowed,
rules:
@ -2215,12 +2213,15 @@ extern "C" {
extern "C" {
pub fn Servo_ResolveStyleLazily(element: RawGeckoElementBorrowed,
pseudo_tag: *mut nsIAtom,
snapshots:
*const ServoElementSnapshotTable,
set: RawServoStyleSetBorrowed)
-> ServoComputedValuesStrong;
}
extern "C" {
pub fn Servo_TraverseSubtree(root: RawGeckoElementBorrowed,
set: RawServoStyleSetBorrowed,
snapshots: *const ServoElementSnapshotTable,
root_behavior: TraversalRootBehavior,
restyle_behavior: TraversalRestyleBehavior)
-> bool;
@ -2233,6 +2234,8 @@ extern "C" {
RawServoStyleSetBorrowed,
element:
RawGeckoElementBorrowed,
snapshots:
*const ServoElementSnapshotTable,
pseudo_tag:
*mut nsIAtom)
-> ServoComputedValuesStrong;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -16,6 +16,8 @@ use std::fmt;
use std::ptr;
use string_cache::{Atom, Namespace, WeakAtom, WeakNamespace};
pub use gecko::snapshot::SnapshotMap;
/// A representation of a CSS pseudo-element.
///
/// In Gecko, we represent pseudo-elements as plain `Atom`s.

View file

@ -5,61 +5,60 @@
//! A gecko snapshot, that stores the element attributes and state before they
//! change in order to properly calculate restyle hints.
use dom::TElement;
use element_state::ElementState;
use gecko::snapshot_helpers;
use gecko::wrapper::{AttrSelectorHelpers, GeckoElement};
use gecko_bindings::bindings;
use gecko_bindings::structs::ServoElementSnapshot;
use gecko_bindings::structs::ServoElementSnapshotFlags as Flags;
use gecko_bindings::structs::ServoElementSnapshotTable;
use restyle_hints::ElementSnapshot;
use selector_parser::SelectorImpl;
use selectors::parser::AttrSelector;
use std::ptr;
use string_cache::Atom;
/// A snapshot of a Gecko element.
///
/// This is really a Gecko type (see `ServoElementSnapshot.h` in Gecko) we wrap
/// here.
#[derive(Debug)]
pub struct GeckoElementSnapshot(bindings::ServoElementSnapshotOwned);
pub type GeckoElementSnapshot = ServoElementSnapshot;
// FIXME(bholley): Add support for *OwnedConst type, and then we get Sync
// automatically.
unsafe impl Sync for GeckoElementSnapshot {}
/// A map from elements to snapshots for Gecko's style back-end.
pub type SnapshotMap = ServoElementSnapshotTable;
impl SnapshotMap {
/// Gets the snapshot for this element, if any.
///
/// FIXME(emilio): The transmute() business we do here is kind of nasty, but
/// it's a consequence of the map being a OpaqueNode -> Snapshot table in
/// Servo and an Element -> Snapshot table in Gecko.
///
/// We should be able to make this a more type-safe with type annotations by
/// making SnapshotMap a trait and moving the implementations outside, but
/// that's a pain because it implies parameterizing SharedStyleContext.
pub fn get<E: TElement>(&self, element: &E) -> Option<&GeckoElementSnapshot> {
debug_assert!(element.has_snapshot());
impl Drop for GeckoElementSnapshot {
fn drop(&mut self) {
unsafe {
bindings::Gecko_DropElementSnapshot(ptr::read(&self.0 as *const _));
let element =
unsafe { ::std::mem::transmute::<&E, &GeckoElement>(element) };
bindings::Gecko_GetElementSnapshot(self, element.0).as_ref()
}
}
}
impl GeckoElementSnapshot {
/// Create a new snapshot of the given element.
pub fn new<'le>(el: GeckoElement<'le>) -> Self {
unsafe { GeckoElementSnapshot(bindings::Gecko_CreateElementSnapshot(el.0)) }
}
/// Get a mutable reference to the snapshot.
pub fn borrow_mut_raw(&mut self) -> bindings::ServoElementSnapshotBorrowedMut {
&mut *self.0
}
/// Get the pointer to the actual snapshot.
pub fn ptr(&self) -> *const ServoElementSnapshot {
&*self.0
}
#[inline]
fn is_html_element_in_html_document(&self) -> bool {
unsafe { (*self.0).mIsHTMLElementInHTMLDocument }
self.mIsHTMLElementInHTMLDocument
}
#[inline]
fn has_any(&self, flags: Flags) -> bool {
unsafe { ((*self.0).mContains as u8 & flags as u8) != 0 }
(self.mContains as u8 & flags as u8) != 0
}
fn as_ptr(&self) -> *const Self {
self
}
}
@ -68,7 +67,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
fn match_attr_has(&self, attr: &AttrSelector<SelectorImpl>) -> bool {
unsafe {
bindings::Gecko_SnapshotHasAttr(self.ptr(),
bindings::Gecko_SnapshotHasAttr(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()))
}
@ -76,7 +75,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
fn match_attr_equals(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrEquals(self.ptr(),
bindings::Gecko_SnapshotAttrEquals(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
@ -86,7 +85,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
fn match_attr_equals_ignore_ascii_case(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrEquals(self.ptr(),
bindings::Gecko_SnapshotAttrEquals(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr(),
@ -95,7 +94,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
}
fn match_attr_includes(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrIncludes(self.ptr(),
bindings::Gecko_SnapshotAttrIncludes(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
@ -103,7 +102,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
}
fn match_attr_dash(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrDashEquals(self.ptr(),
bindings::Gecko_SnapshotAttrDashEquals(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
@ -111,7 +110,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
}
fn match_attr_prefix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrHasPrefix(self.ptr(),
bindings::Gecko_SnapshotAttrHasPrefix(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
@ -119,7 +118,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
}
fn match_attr_substring(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrHasSubstring(self.ptr(),
bindings::Gecko_SnapshotAttrHasSubstring(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
@ -127,7 +126,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
}
fn match_attr_suffix(&self, attr: &AttrSelector<SelectorImpl>, value: &Atom) -> bool {
unsafe {
bindings::Gecko_SnapshotAttrHasSuffix(self.ptr(),
bindings::Gecko_SnapshotAttrHasSuffix(self,
attr.ns_or_null(),
attr.select_name(self.is_html_element_in_html_document()),
value.as_ptr())
@ -138,7 +137,7 @@ impl ::selectors::MatchAttr for GeckoElementSnapshot {
impl ElementSnapshot for GeckoElementSnapshot {
fn state(&self) -> Option<ElementState> {
if self.has_any(Flags::State) {
Some(ElementState::from_bits_truncate(unsafe { (*self.0).mState }))
Some(ElementState::from_bits_truncate(self.mState))
} else {
None
}
@ -151,7 +150,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
fn id_attr(&self) -> Option<Atom> {
let ptr = unsafe {
bindings::Gecko_SnapshotAtomAttrValue(self.ptr(),
bindings::Gecko_SnapshotAtomAttrValue(self,
atom!("id").as_ptr())
};
@ -163,7 +162,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
}
fn has_class(&self, name: &Atom) -> bool {
snapshot_helpers::has_class(self.ptr(),
snapshot_helpers::has_class(self.as_ptr(),
name,
bindings::Gecko_SnapshotClassOrClassList)
}
@ -171,7 +170,7 @@ impl ElementSnapshot for GeckoElementSnapshot {
fn each_class<F>(&self, callback: F)
where F: FnMut(&Atom)
{
snapshot_helpers::each_class(self.ptr(),
snapshot_helpers::each_class(self.as_ptr(),
callback,
bindings::Gecko_SnapshotClassOrClassList)
}

View file

@ -47,9 +47,11 @@ use gecko_bindings::bindings::Gecko_UpdateAnimations;
use gecko_bindings::structs;
use gecko_bindings::structs::{RawGeckoElement, RawGeckoNode};
use gecko_bindings::structs::{nsIAtom, nsIContent, nsStyleContext};
use gecko_bindings::structs::ELEMENT_HANDLED_SNAPSHOT;
use gecko_bindings::structs::ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::ELEMENT_HAS_SNAPSHOT;
use gecko_bindings::structs::EffectCompositor_CascadeLevel as CascadeLevel;
use gecko_bindings::structs::NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO;
use gecko_bindings::structs::NODE_IS_IN_NATIVE_ANONYMOUS_SUBTREE;
use gecko_bindings::structs::NODE_IS_NATIVE_ANONYMOUS;
use gecko_bindings::sugar::ownership::HasArcFFI;
@ -60,7 +62,7 @@ use properties::{Importance, PropertyDeclaration, PropertyDeclarationBlock};
use properties::animated_properties::{AnimationValue, AnimationValueMap, TransitionProperty};
use properties::style_structs::Font;
use rule_tree::CascadeLevel as ServoCascadeLevel;
use selector_parser::{ElementExt, Snapshot};
use selector_parser::ElementExt;
use selectors::Element;
use selectors::matching::{ElementSelectorFlags, StyleRelations};
use selectors::parser::{AttrSelector, NamespaceConstraint};
@ -361,6 +363,10 @@ impl<'le> GeckoElement<'le> {
/// Clear the element data for a given element.
pub fn clear_data(&self) {
let ptr = self.0.mServoData.get();
unsafe {
self.unset_flags(ELEMENT_HAS_SNAPSHOT as u32 |
ELEMENT_HANDLED_SNAPSHOT as u32);
}
if !ptr.is_null() {
debug!("Dropping ElementData for {:?}", self);
let data = unsafe { Box::from_raw(self.0.mServoData.get()) };
@ -389,11 +395,6 @@ impl<'le> GeckoElement<'le> {
},
}
}
/// Creates a blank snapshot for this element.
pub fn create_snapshot(&self) -> Snapshot {
Snapshot::new(*self)
}
}
/// Converts flags from the layout used by rust-selectors to the layout used
@ -589,14 +590,27 @@ impl<'le> TElement for GeckoElement<'le> {
}
}
fn has_snapshot(&self) -> bool {
self.flags() & (ELEMENT_HAS_SNAPSHOT as u32) != 0
}
fn handled_snapshot(&self) -> bool {
self.flags() & (ELEMENT_HANDLED_SNAPSHOT as u32) != 0
}
unsafe fn set_handled_snapshot(&self) {
debug_assert!(self.get_data().is_some());
self.set_flags(ELEMENT_HANDLED_SNAPSHOT as u32)
}
fn has_dirty_descendants(&self) -> bool {
self.flags() & (NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
self.flags() & (ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
}
unsafe fn set_dirty_descendants(&self) {
debug_assert!(self.get_data().is_some());
debug!("Setting dirty descendants: {:?}", self);
self.set_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
self.set_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
}
unsafe fn note_descendants<B: DescendantsBit<Self>>(&self) {
@ -617,19 +631,19 @@ impl<'le> TElement for GeckoElement<'le> {
}
unsafe fn unset_dirty_descendants(&self) {
self.unset_flags(NODE_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
self.unset_flags(ELEMENT_HAS_DIRTY_DESCENDANTS_FOR_SERVO as u32)
}
fn has_animation_only_dirty_descendants(&self) -> bool {
self.flags() & (NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
self.flags() & (ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32) != 0
}
unsafe fn set_animation_only_dirty_descendants(&self) {
self.set_flags(NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
self.set_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
}
unsafe fn unset_animation_only_dirty_descendants(&self) {
self.unset_flags(NODE_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
self.unset_flags(ELEMENT_HAS_ANIMATION_ONLY_DIRTY_DESCENDANTS_FOR_SERVO as u32)
}
fn is_native_anonymous(&self) -> bool {