From afe484e46b631689357de183020419ab1a49dcdf Mon Sep 17 00:00:00 2001 From: Bobby Holley Date: Tue, 20 Feb 2018 15:52:13 -0800 Subject: [PATCH] style: Allow placeholder import sheets. This is necessary because we can't create GeckoStyleSheets off-main-thread, so we need a placeholder until it can be filled in. Bug: 1454030 Reviewed-by: emilio MozReview-Commit-ID: ssRme4fLYg --- components/style/gecko/data.rs | 31 +++++-- components/style/stylesheet_set.rs | 2 +- components/style/stylesheets/import_rule.rs | 91 ++++++++++++++++--- .../style/stylesheets/rules_iterator.rs | 12 +-- components/style/stylesheets/stylesheet.rs | 80 ++++++++-------- ports/geckolib/glue.rs | 2 +- ports/geckolib/stylesheet_loader.rs | 5 +- 7 files changed, 152 insertions(+), 71 deletions(-) diff --git a/components/style/gecko/data.rs b/components/style/gecko/data.rs index 9c58a292dfc..331b07ea551 100644 --- a/components/style/gecko/data.rs +++ b/components/style/gecko/data.rs @@ -5,6 +5,7 @@ //! Data needed to style a Gecko document. use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; +use context::QuirksMode; use dom::TElement; use gecko_bindings::bindings::{self, RawServoStyleSet}; use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet}; @@ -17,7 +18,7 @@ use properties::ComputedValues; use selector_parser::SnapshotMap; use servo_arc::Arc; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; -use stylesheets::{StylesheetContents, StylesheetInDocument}; +use stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument}; use stylist::Stylist; /// Little wrapper to a Gecko style sheet. @@ -58,6 +59,16 @@ impl GeckoStyleSheet { &*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner) } } + + /// Gets the StylesheetContents for this stylesheet. + pub fn contents(&self) -> &StylesheetContents { + debug_assert!(!self.inner().mContents.mRawPtr.is_null()); + unsafe { + let contents = + (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _; + &*contents + } + } } impl Drop for GeckoStyleSheet { @@ -74,13 +85,12 @@ impl Clone for GeckoStyleSheet { } impl StylesheetInDocument for GeckoStyleSheet { - fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents { - debug_assert!(!self.inner().mContents.mRawPtr.is_null()); - unsafe { - let contents = - (&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _; - &*contents - } + fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin { + self.contents().origin + } + + fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode { + self.contents().quirks_mode } fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { @@ -103,6 +113,11 @@ impl StylesheetInDocument for GeckoStyleSheet { fn enabled(&self) -> bool { true } + + #[inline] + fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { + self.contents().rules(guard) + } } /// The container for data that a Servo-backed Gecko document needs to style diff --git a/components/style/stylesheet_set.rs b/components/style/stylesheet_set.rs index 1091b6674a1..a3b6e5cdc17 100644 --- a/components/style/stylesheet_set.rs +++ b/components/style/stylesheet_set.rs @@ -478,7 +478,7 @@ where sheet: &S, guard: &SharedRwLockReadGuard, ) -> &mut SheetCollection { - let origin = sheet.contents(guard).origin; + let origin = sheet.origin(guard); self.collections.borrow_mut_for_origin(&origin) } diff --git a/components/style/stylesheets/import_rule.rs b/components/style/stylesheets/import_rule.rs index 75557ed50ee..5fe5f9549d2 100644 --- a/components/style/stylesheets/import_rule.rs +++ b/components/style/stylesheets/import_rule.rs @@ -6,6 +6,7 @@ //! //! [import]: https://drafts.csswg.org/css-cascade-3/#at-import +use context::QuirksMode; use cssparser::SourceLocation; use media_queries::MediaList; use shared_lock::{DeepCloneParams, DeepCloneWithLock}; @@ -13,13 +14,52 @@ use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard}; use std::fmt::{self, Write}; use str::CssStringWriter; use style_traits::{CssWriter, ToCss}; -use stylesheets::{StylesheetContents, StylesheetInDocument}; +use stylesheets::{CssRule, Origin, StylesheetInDocument}; use values::CssUrl; +/// With asynchronous stylesheet parsing, we can't synchronously create a +/// GeckoStyleSheet. So we use this placeholder instead. +#[derive(Clone, Debug)] +pub struct PendingSheet { + origin: Origin, + quirks_mode: QuirksMode, +} + /// A sheet that is held from an import rule. #[cfg(feature = "gecko")] #[derive(Debug)] -pub struct ImportSheet(pub ::gecko::data::GeckoStyleSheet); +pub enum ImportSheet { + /// A bonafide stylesheet. + Sheet(::gecko::data::GeckoStyleSheet), + /// An @import created while parsing off-main-thread, whose Gecko sheet has + /// yet to be created and attached. + Pending(PendingSheet), +} + +#[cfg(feature = "gecko")] +impl ImportSheet { + /// Creates a new ImportSheet from a GeckoStyleSheet. + pub fn new(sheet: ::gecko::data::GeckoStyleSheet) -> Self { + ImportSheet::Sheet(sheet) + } + + /// Creates a pending ImportSheet for a load that has not started yet. + pub fn new_pending(origin: Origin, quirks_mode: QuirksMode) -> Self { + ImportSheet::Pending(PendingSheet { + origin, + quirks_mode, + }) + } + + /// Returns a reference to the GeckoStyleSheet in this ImportSheet, if it + /// exists. + pub fn as_sheet(&self) -> Option<&::gecko::data::GeckoStyleSheet> { + match *self { + ImportSheet::Sheet(ref s) => Some(s), + ImportSheet::Pending(_) => None, + } + } +} #[cfg(feature = "gecko")] impl DeepCloneWithLock for ImportSheet { @@ -31,10 +71,15 @@ impl DeepCloneWithLock for ImportSheet { ) -> Self { use gecko::data::GeckoStyleSheet; use gecko_bindings::bindings; - let clone = unsafe { - bindings::Gecko_StyleSheet_Clone(self.0.raw() as *const _, params.reference_sheet) - }; - ImportSheet(unsafe { GeckoStyleSheet::from_addrefed(clone) }) + match *self { + ImportSheet::Sheet(ref s) => { + let clone = unsafe { + bindings::Gecko_StyleSheet_Clone(s.raw() as *const _, params.reference_sheet) + }; + ImportSheet::Sheet(unsafe { GeckoStyleSheet::from_addrefed(clone) }) + }, + ImportSheet::Pending(ref p) => ImportSheet::Pending(p.clone()), + } } } @@ -44,17 +89,39 @@ impl DeepCloneWithLock for ImportSheet { pub struct ImportSheet(pub ::servo_arc::Arc<::stylesheets::Stylesheet>); impl StylesheetInDocument for ImportSheet { - /// Get the media associated with this stylesheet. - fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { - self.0.media(guard) + fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin { + match *self { + ImportSheet::Sheet(ref s) => s.contents().origin, + ImportSheet::Pending(ref p) => p.origin, + } } - fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents { - self.0.contents(guard) + fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode { + match *self { + ImportSheet::Sheet(ref s) => s.contents().quirks_mode, + ImportSheet::Pending(ref p) => p.quirks_mode, + } } fn enabled(&self) -> bool { - self.0.enabled() + match *self { + ImportSheet::Sheet(ref s) => s.enabled(), + ImportSheet::Pending(_) => true, + } + } + + fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { + match *self { + ImportSheet::Sheet(ref s) => s.media(guard), + ImportSheet::Pending(_) => None, + } + } + + fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { + match *self { + ImportSheet::Sheet(ref s) => s.contents().rules(guard), + ImportSheet::Pending(_) => &[], + } } } diff --git a/components/style/stylesheets/rules_iterator.rs b/components/style/stylesheets/rules_iterator.rs index 3d63a218ff4..81bf890b0fd 100644 --- a/components/style/stylesheets/rules_iterator.rs +++ b/components/style/stylesheets/rules_iterator.rs @@ -9,8 +9,9 @@ use media_queries::Device; use shared_lock::SharedRwLockReadGuard; use smallvec::SmallVec; use std::slice; -use stylesheets::{CssRule, CssRules, DocumentRule, ImportRule, MediaRule, SupportsRule}; +use stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule}; use stylesheets::StylesheetInDocument; +use stylesheets::import_rule::ImportSheet; /// An iterator over a list of rules. pub struct RulesIterator<'a, 'b, C> @@ -35,10 +36,10 @@ where device: &'a Device, quirks_mode: QuirksMode, guard: &'a SharedRwLockReadGuard<'b>, - rules: &'a CssRules, + rules: &'a [CssRule], ) -> Self { let mut stack = SmallVec::new(); - stack.push(rules.0.iter()); + stack.push(rules.iter()); Self { device: device, quirks_mode: quirks_mode, @@ -102,10 +103,7 @@ where } import_rule .stylesheet - .contents(self.guard) - .rules - .read_with(self.guard) - .0 + .rules(self.guard) .iter() }, CssRule::Document(ref doc_rule) => { diff --git a/components/style/stylesheets/stylesheet.rs b/components/style/stylesheets/stylesheet.rs index 4bccbb504c9..08c2cb05f7a 100644 --- a/components/style/stylesheets/stylesheet.rs +++ b/components/style/stylesheets/stylesheet.rs @@ -103,22 +103,10 @@ impl StylesheetContents { } } - /// Return an iterator using the condition `C`. + /// Returns a reference to the list of rules. #[inline] - pub fn iter_rules<'a, 'b, C>( - &'a self, - device: &'a Device, - guard: &'a SharedRwLockReadGuard<'b>, - ) -> RulesIterator<'a, 'b, C> - where - C: NestedRuleIterationCondition, - { - RulesIterator::new( - device, - self.quirks_mode, - guard, - &self.rules.read_with(guard), - ) + pub fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { + &self.rules.read_with(guard).0 } /// Measure heap usage. @@ -189,32 +177,20 @@ macro_rules! rule_filter { /// A trait to represent a given stylesheet in a document. pub trait StylesheetInDocument { - /// Get the contents of this stylesheet. - fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents; - /// Get the stylesheet origin. - fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { - self.contents(guard).origin - } + fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin; /// Get the stylesheet quirks mode. - fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode { - self.contents(guard).quirks_mode - } + fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode; + + /// Get whether this stylesheet is enabled. + fn enabled(&self) -> bool; /// Get the media associated with this stylesheet. fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>; - /// Returns whether the style-sheet applies for the current device. - fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool { - match self.media(guard) { - Some(medialist) => medialist.evaluate(device, self.quirks_mode(guard)), - None => true, - } - } - - /// Get whether this stylesheet is enabled. - fn enabled(&self) -> bool; + /// Returns a reference to the list of rules in this stylesheet. + fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule]; /// Return an iterator using the condition `C`. #[inline] @@ -226,7 +202,15 @@ pub trait StylesheetInDocument { where C: NestedRuleIterationCondition, { - self.contents(guard).iter_rules(device, guard) + RulesIterator::new(device, self.quirks_mode(guard), guard, self.rules(guard)) + } + + /// Returns whether the style-sheet applies for the current device. + fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool { + match self.media(guard) { + Some(medialist) => medialist.evaluate(device, self.quirks_mode(guard)), + None => true, + } } /// Return an iterator over the effective rules within the style-sheet, as @@ -255,8 +239,12 @@ pub trait StylesheetInDocument { } impl StylesheetInDocument for Stylesheet { - fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents { - &self.contents + fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin { + self.contents.origin + } + + fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode { + self.contents.quirks_mode } fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { @@ -266,6 +254,11 @@ impl StylesheetInDocument for Stylesheet { fn enabled(&self) -> bool { !self.disabled() } + + #[inline] + fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { + self.contents.rules(guard) + } } /// A simple wrapper over an `Arc`, with pointer comparison, and @@ -289,8 +282,12 @@ impl ToMediaListKey for DocumentStyleSheet { } impl StylesheetInDocument for DocumentStyleSheet { - fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents { - self.0.contents(guard) + fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { + self.0.origin(guard) + } + + fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode { + self.0.quirks_mode(guard) } fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { @@ -300,6 +297,11 @@ impl StylesheetInDocument for DocumentStyleSheet { fn enabled(&self) -> bool { self.0.enabled() } + + #[inline] + fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] { + self.0.rules(guard) + } } impl Stylesheet { diff --git a/ports/geckolib/glue.rs b/ports/geckolib/glue.rs index ce957398391..3a476640de1 100644 --- a/ports/geckolib/glue.rs +++ b/ports/geckolib/glue.rs @@ -2048,7 +2048,7 @@ pub extern "C" fn Servo_ImportRule_GetSheet( rule: RawServoImportRuleBorrowed, ) -> *const ServoStyleSheet { read_locked_arc(rule, |rule: &ImportRule| { - rule.stylesheet.0.raw() as *const ServoStyleSheet + rule.stylesheet.as_sheet().unwrap().raw() as *const ServoStyleSheet }) } diff --git a/ports/geckolib/stylesheet_loader.rs b/ports/geckolib/stylesheet_loader.rs index 0addb4f9ef8..1dfe30e8bdb 100644 --- a/ports/geckolib/stylesheet_loader.rs +++ b/ports/geckolib/stylesheet_loader.rs @@ -55,9 +55,8 @@ impl StyleStylesheetLoader for StylesheetLoader { debug_assert!(!child_sheet.is_null(), "Import rules should always have a strong sheet"); - let stylesheet = unsafe { - ImportSheet(GeckoStyleSheet::from_addrefed(child_sheet)) - }; + let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) }; + let stylesheet = ImportSheet::new(sheet); Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet })) } }