mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
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:
commit
c8171ed5d7
22 changed files with 2194 additions and 1137 deletions
|
@ -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
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue