mirror of
https://github.com/servo/servo.git
synced 2025-08-04 13:10:20 +01:00
Bug 1357583: style: Hook up the invalidator in the StyleSheetSet. r=heycam
MozReview-Commit-ID: IhgKAovTJMX
This commit is contained in:
parent
658075af32
commit
39e836966e
5 changed files with 117 additions and 22 deletions
|
@ -6,8 +6,10 @@
|
||||||
|
|
||||||
use Atom;
|
use Atom;
|
||||||
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
|
||||||
|
use dom::TElement;
|
||||||
use fnv::FnvHashMap;
|
use fnv::FnvHashMap;
|
||||||
use gecko::rules::{CounterStyleRule, FontFaceRule};
|
use gecko::rules::{CounterStyleRule, FontFaceRule};
|
||||||
|
use gecko::wrapper::GeckoElement;
|
||||||
use gecko_bindings::bindings::RawServoStyleSet;
|
use gecko_bindings::bindings::RawServoStyleSet;
|
||||||
use gecko_bindings::structs::RawGeckoPresContextOwned;
|
use gecko_bindings::structs::RawGeckoPresContextOwned;
|
||||||
use gecko_bindings::structs::nsIDocument;
|
use gecko_bindings::structs::nsIDocument;
|
||||||
|
@ -74,11 +76,15 @@ impl PerDocumentStyleDataImpl {
|
||||||
pub fn reset_device(&mut self, guard: &SharedRwLockReadGuard) {
|
pub fn reset_device(&mut self, guard: &SharedRwLockReadGuard) {
|
||||||
Arc::get_mut(self.stylist.device_mut()).unwrap().reset();
|
Arc::get_mut(self.stylist.device_mut()).unwrap().reset();
|
||||||
self.stylesheets.force_dirty();
|
self.stylesheets.force_dirty();
|
||||||
self.flush_stylesheets(guard);
|
self.flush_stylesheets::<GeckoElement>(guard, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Recreate the style data if the stylesheets have changed.
|
/// Recreate the style data if the stylesheets have changed.
|
||||||
pub fn flush_stylesheets(&mut self, guard: &SharedRwLockReadGuard) {
|
pub fn flush_stylesheets<E>(&mut self,
|
||||||
|
guard: &SharedRwLockReadGuard,
|
||||||
|
document_element: Option<E>)
|
||||||
|
where E: TElement,
|
||||||
|
{
|
||||||
if !self.stylesheets.has_changed() {
|
if !self.stylesheets.has_changed() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -90,7 +96,8 @@ impl PerDocumentStyleDataImpl {
|
||||||
|
|
||||||
let author_style_disabled = self.stylesheets.author_style_disabled();
|
let author_style_disabled = self.stylesheets.author_style_disabled();
|
||||||
self.stylist.clear();
|
self.stylist.clear();
|
||||||
self.stylist.rebuild(self.stylesheets.flush(),
|
let iter = self.stylesheets.flush(document_element);
|
||||||
|
self.stylist.rebuild(iter,
|
||||||
&StylesheetGuards::same(guard),
|
&StylesheetGuards::same(guard),
|
||||||
/* ua_sheets = */ None,
|
/* ua_sheets = */ None,
|
||||||
/* stylesheets_changed = */ true,
|
/* stylesheets_changed = */ true,
|
||||||
|
|
|
@ -34,9 +34,9 @@ pub mod namespace;
|
||||||
|
|
||||||
pub use self::namespace::{Namespace, WeakNamespace};
|
pub use self::namespace::{Namespace, WeakNamespace};
|
||||||
|
|
||||||
macro_rules! local_name {
|
// macro_rules! local_name {
|
||||||
($s: tt) => { atom!($s) }
|
// ($s: tt) => { atom!($s) }
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// A strong reference to a Gecko atom.
|
/// A strong reference to a Gecko atom.
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq)]
|
||||||
|
|
|
@ -51,7 +51,8 @@ impl InvalidationScope {
|
||||||
|
|
||||||
/// A set of invalidations due to stylesheet additions.
|
/// A set of invalidations due to stylesheet additions.
|
||||||
///
|
///
|
||||||
/// TODO(emilio): We might be able to do the same analysis for removals too?
|
/// TODO(emilio): We might be able to do the same analysis for removals and
|
||||||
|
/// media query changes too?
|
||||||
pub struct StylesheetInvalidationSet {
|
pub struct StylesheetInvalidationSet {
|
||||||
/// The style scopes we know we have to restyle so far.
|
/// The style scopes we know we have to restyle so far.
|
||||||
invalid_scopes: FnvHashSet<InvalidationScope>,
|
invalid_scopes: FnvHashSet<InvalidationScope>,
|
||||||
|
@ -68,6 +69,12 @@ impl StylesheetInvalidationSet {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Mark the DOM tree styles' as fully invalid.
|
||||||
|
pub fn invalidate_fully(&mut self) {
|
||||||
|
self.invalid_scopes.clear();
|
||||||
|
self.fully_invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
/// Analyze the given stylesheet, and collect invalidations from their
|
/// Analyze the given stylesheet, and collect invalidations from their
|
||||||
/// rules, in order to avoid doing a full restyle when we style the document
|
/// rules, in order to avoid doing a full restyle when we style the document
|
||||||
/// next time.
|
/// next time.
|
||||||
|
@ -89,13 +96,25 @@ impl StylesheetInvalidationSet {
|
||||||
guard);
|
guard);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clears the invalidation set, invalidating elements as needed if
|
||||||
|
/// `document_element` is provided.
|
||||||
|
pub fn flush<E>(&mut self, document_element: Option<E>)
|
||||||
|
where E: TElement,
|
||||||
|
{
|
||||||
|
if let Some(e) = document_element {
|
||||||
|
self.process_invalidations_in_subtree(e);
|
||||||
|
}
|
||||||
|
self.invalid_scopes.clear();
|
||||||
|
self.fully_invalid = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Process style invalidations in a given subtree, that is, look for all
|
/// Process style invalidations in a given subtree, that is, look for all
|
||||||
/// the relevant scopes in the subtree, and mark as dirty only the relevant
|
/// the relevant scopes in the subtree, and mark as dirty only the relevant
|
||||||
/// ones.
|
/// ones.
|
||||||
///
|
///
|
||||||
/// Returns whether it invalidated at least one element's style.
|
/// Returns whether it invalidated at least one element's style.
|
||||||
#[allow(unsafe_code)]
|
#[allow(unsafe_code)]
|
||||||
pub fn process_invalidations_in_subtree<E>(&self, element: E) -> bool
|
fn process_invalidations_in_subtree<E>(&self, element: E) -> bool
|
||||||
where E: TElement,
|
where E: TElement,
|
||||||
{
|
{
|
||||||
let mut data = match element.mutate_data() {
|
let mut data = match element.mutate_data() {
|
||||||
|
|
|
@ -4,9 +4,13 @@
|
||||||
|
|
||||||
//! A centralized set of stylesheets for a document.
|
//! A centralized set of stylesheets for a document.
|
||||||
|
|
||||||
|
use dom::TElement;
|
||||||
|
use invalidation::StylesheetInvalidationSet;
|
||||||
|
use shared_lock::SharedRwLockReadGuard;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use stylearc::Arc;
|
use stylearc::Arc;
|
||||||
use stylesheets::Stylesheet;
|
use stylesheets::Stylesheet;
|
||||||
|
use stylist::Stylist;
|
||||||
|
|
||||||
/// Entry for a StylesheetSet. We don't bother creating a constructor, because
|
/// Entry for a StylesheetSet. We don't bother creating a constructor, because
|
||||||
/// there's no sensible defaults for the member variables.
|
/// there's no sensible defaults for the member variables.
|
||||||
|
@ -40,6 +44,9 @@ pub struct StylesheetSet {
|
||||||
|
|
||||||
/// Has author style been disabled?
|
/// Has author style been disabled?
|
||||||
author_style_disabled: bool,
|
author_style_disabled: bool,
|
||||||
|
|
||||||
|
/// The style invalidations that we still haven't processed.
|
||||||
|
invalidations: StylesheetInvalidationSet,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StylesheetSet {
|
impl StylesheetSet {
|
||||||
|
@ -49,6 +56,7 @@ impl StylesheetSet {
|
||||||
entries: vec![],
|
entries: vec![],
|
||||||
dirty: false,
|
dirty: false,
|
||||||
author_style_disabled: false,
|
author_style_disabled: false,
|
||||||
|
invalidations: StylesheetInvalidationSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,32 +71,54 @@ impl StylesheetSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Appends a new stylesheet to the current set.
|
/// Appends a new stylesheet to the current set.
|
||||||
pub fn append_stylesheet(&mut self, sheet: &Arc<Stylesheet>,
|
pub fn append_stylesheet(
|
||||||
unique_id: u64) {
|
&mut self,
|
||||||
|
stylist: &Stylist,
|
||||||
|
sheet: &Arc<Stylesheet>,
|
||||||
|
unique_id: u64,
|
||||||
|
guard: &SharedRwLockReadGuard)
|
||||||
|
{
|
||||||
self.remove_stylesheet_if_present(unique_id);
|
self.remove_stylesheet_if_present(unique_id);
|
||||||
self.entries.push(StylesheetSetEntry {
|
self.entries.push(StylesheetSetEntry {
|
||||||
unique_id: unique_id,
|
unique_id: unique_id,
|
||||||
sheet: sheet.clone(),
|
sheet: sheet.clone(),
|
||||||
});
|
});
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
self.invalidations.collect_invalidations_for(
|
||||||
|
stylist,
|
||||||
|
sheet,
|
||||||
|
guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Prepend a new stylesheet to the current set.
|
/// Prepend a new stylesheet to the current set.
|
||||||
pub fn prepend_stylesheet(&mut self, sheet: &Arc<Stylesheet>,
|
pub fn prepend_stylesheet(
|
||||||
unique_id: u64) {
|
&mut self,
|
||||||
|
stylist: &Stylist,
|
||||||
|
sheet: &Arc<Stylesheet>,
|
||||||
|
unique_id: u64,
|
||||||
|
guard: &SharedRwLockReadGuard)
|
||||||
|
{
|
||||||
self.remove_stylesheet_if_present(unique_id);
|
self.remove_stylesheet_if_present(unique_id);
|
||||||
self.entries.insert(0, StylesheetSetEntry {
|
self.entries.insert(0, StylesheetSetEntry {
|
||||||
unique_id: unique_id,
|
unique_id: unique_id,
|
||||||
sheet: sheet.clone(),
|
sheet: sheet.clone(),
|
||||||
});
|
});
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
self.invalidations.collect_invalidations_for(
|
||||||
|
stylist,
|
||||||
|
sheet,
|
||||||
|
guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Insert a given stylesheet before another stylesheet in the document.
|
/// Insert a given stylesheet before another stylesheet in the document.
|
||||||
pub fn insert_stylesheet_before(&mut self,
|
pub fn insert_stylesheet_before(
|
||||||
|
&mut self,
|
||||||
|
stylist: &Stylist,
|
||||||
sheet: &Arc<Stylesheet>,
|
sheet: &Arc<Stylesheet>,
|
||||||
unique_id: u64,
|
unique_id: u64,
|
||||||
before_unique_id: u64) {
|
before_unique_id: u64,
|
||||||
|
guard: &SharedRwLockReadGuard)
|
||||||
|
{
|
||||||
self.remove_stylesheet_if_present(unique_id);
|
self.remove_stylesheet_if_present(unique_id);
|
||||||
let index = self.entries.iter().position(|x| {
|
let index = self.entries.iter().position(|x| {
|
||||||
x.unique_id == before_unique_id
|
x.unique_id == before_unique_id
|
||||||
|
@ -98,12 +128,18 @@ impl StylesheetSet {
|
||||||
sheet: sheet.clone(),
|
sheet: sheet.clone(),
|
||||||
});
|
});
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
self.invalidations.collect_invalidations_for(
|
||||||
|
stylist,
|
||||||
|
sheet,
|
||||||
|
guard)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a given stylesheet from the set.
|
/// Remove a given stylesheet from the set.
|
||||||
pub fn remove_stylesheet(&mut self, unique_id: u64) {
|
pub fn remove_stylesheet(&mut self, unique_id: u64) {
|
||||||
self.remove_stylesheet_if_present(unique_id);
|
self.remove_stylesheet_if_present(unique_id);
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
// FIXME(emilio): We can do better!
|
||||||
|
self.invalidations.invalidate_fully();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Notes that the author style has been disabled for this document.
|
/// Notes that the author style has been disabled for this document.
|
||||||
|
@ -113,6 +149,7 @@ impl StylesheetSet {
|
||||||
}
|
}
|
||||||
self.author_style_disabled = disabled;
|
self.author_style_disabled = disabled;
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
self.invalidations.invalidate_fully();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether the given set has changed from the last flush.
|
/// Returns whether the given set has changed from the last flush.
|
||||||
|
@ -122,8 +159,16 @@ impl StylesheetSet {
|
||||||
|
|
||||||
/// Flush the current set, unmarking it as dirty, and returns an iterator
|
/// Flush the current set, unmarking it as dirty, and returns an iterator
|
||||||
/// over the new stylesheet list.
|
/// over the new stylesheet list.
|
||||||
pub fn flush(&mut self) -> StylesheetIterator {
|
pub fn flush<E>(&mut self,
|
||||||
|
document_element: Option<E>)
|
||||||
|
-> StylesheetIterator
|
||||||
|
where E: TElement,
|
||||||
|
{
|
||||||
|
debug_assert!(self.dirty);
|
||||||
|
|
||||||
self.dirty = false;
|
self.dirty = false;
|
||||||
|
self.invalidations.flush(document_element);
|
||||||
|
|
||||||
StylesheetIterator(self.entries.iter())
|
StylesheetIterator(self.entries.iter())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,5 +178,6 @@ impl StylesheetSet {
|
||||||
/// FIXME(emilio): Make this more granular.
|
/// FIXME(emilio): Make this more granular.
|
||||||
pub fn force_dirty(&mut self) {
|
pub fn force_dirty(&mut self) {
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
|
self.invalidations.invalidate_fully();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -732,9 +732,16 @@ pub extern "C" fn Servo_StyleSheet_ClearAndUpdate(stylesheet: RawServoStyleSheet
|
||||||
pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed,
|
pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorrowed,
|
||||||
raw_sheet: RawServoStyleSheetBorrowed,
|
raw_sheet: RawServoStyleSheetBorrowed,
|
||||||
unique_id: u64) {
|
unique_id: u64) {
|
||||||
|
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||||
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
||||||
|
let mut data = &mut *data;
|
||||||
let sheet = HasArcFFI::as_arc(&raw_sheet);
|
let sheet = HasArcFFI::as_arc(&raw_sheet);
|
||||||
data.stylesheets.append_stylesheet(sheet, unique_id);
|
let guard = global_style_data.shared_lock.read();
|
||||||
|
data.stylesheets.append_stylesheet(
|
||||||
|
&data.stylist,
|
||||||
|
sheet,
|
||||||
|
unique_id,
|
||||||
|
&guard);
|
||||||
data.clear_stylist();
|
data.clear_stylist();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -742,9 +749,16 @@ pub extern "C" fn Servo_StyleSet_AppendStyleSheet(raw_data: RawServoStyleSetBorr
|
||||||
pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed,
|
pub extern "C" fn Servo_StyleSet_PrependStyleSheet(raw_data: RawServoStyleSetBorrowed,
|
||||||
raw_sheet: RawServoStyleSheetBorrowed,
|
raw_sheet: RawServoStyleSheetBorrowed,
|
||||||
unique_id: u64) {
|
unique_id: u64) {
|
||||||
|
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||||
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
||||||
|
let mut data = &mut *data;
|
||||||
let sheet = HasArcFFI::as_arc(&raw_sheet);
|
let sheet = HasArcFFI::as_arc(&raw_sheet);
|
||||||
data.stylesheets.prepend_stylesheet(sheet, unique_id);
|
let guard = global_style_data.shared_lock.read();
|
||||||
|
data.stylesheets.prepend_stylesheet(
|
||||||
|
&data.stylist,
|
||||||
|
sheet,
|
||||||
|
unique_id,
|
||||||
|
&guard);
|
||||||
data.clear_stylist();
|
data.clear_stylist();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,9 +767,17 @@ pub extern "C" fn Servo_StyleSet_InsertStyleSheetBefore(raw_data: RawServoStyleS
|
||||||
raw_sheet: RawServoStyleSheetBorrowed,
|
raw_sheet: RawServoStyleSheetBorrowed,
|
||||||
unique_id: u64,
|
unique_id: u64,
|
||||||
before_unique_id: u64) {
|
before_unique_id: u64) {
|
||||||
|
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||||
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
||||||
|
let mut data = &mut *data;
|
||||||
let sheet = HasArcFFI::as_arc(&raw_sheet);
|
let sheet = HasArcFFI::as_arc(&raw_sheet);
|
||||||
data.stylesheets.insert_stylesheet_before(sheet, unique_id, before_unique_id);
|
let guard = global_style_data.shared_lock.read();
|
||||||
|
data.stylesheets.insert_stylesheet_before(
|
||||||
|
&data.stylist,
|
||||||
|
sheet,
|
||||||
|
unique_id,
|
||||||
|
before_unique_id,
|
||||||
|
&guard);
|
||||||
data.clear_stylist();
|
data.clear_stylist();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -770,12 +792,13 @@ pub extern "C" fn Servo_StyleSet_RemoveStyleSheet(raw_data: RawServoStyleSetBorr
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn Servo_StyleSet_FlushStyleSheets(
|
pub extern "C" fn Servo_StyleSet_FlushStyleSheets(
|
||||||
raw_data: RawServoStyleSetBorrowed,
|
raw_data: RawServoStyleSetBorrowed,
|
||||||
doc_element: RawServoElementBorrowedOrNull)
|
doc_element: RawGeckoElementBorrowedOrNull)
|
||||||
{
|
{
|
||||||
let global_style_data = &*GLOBAL_STYLE_DATA;
|
let global_style_data = &*GLOBAL_STYLE_DATA;
|
||||||
let guard = global_style_data.shared_lock.read();
|
let guard = global_style_data.shared_lock.read();
|
||||||
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
let mut data = PerDocumentStyleData::from_ffi(raw_data).borrow_mut();
|
||||||
data.flush_stylesheets(&guard);
|
let doc_element = doc_element.map(GeckoElement);
|
||||||
|
data.flush_stylesheets(&guard, doc_element);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue