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
This commit is contained in:
Bobby Holley 2018-02-20 15:52:13 -08:00 committed by Emilio Cobos Álvarez
parent 441f1cd231
commit afe484e46b
No known key found for this signature in database
GPG key ID: 056B727BB9C1027C
7 changed files with 152 additions and 71 deletions

View file

@ -5,6 +5,7 @@
//! Data needed to style a Gecko document. //! Data needed to style a Gecko document.
use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut}; use atomic_refcell::{AtomicRef, AtomicRefCell, AtomicRefMut};
use context::QuirksMode;
use dom::TElement; use dom::TElement;
use gecko_bindings::bindings::{self, RawServoStyleSet}; use gecko_bindings::bindings::{self, RawServoStyleSet};
use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet}; use gecko_bindings::structs::{self, RawGeckoPresContextOwned, ServoStyleSetSizes, ServoStyleSheet};
@ -17,7 +18,7 @@ use properties::ComputedValues;
use selector_parser::SnapshotMap; use selector_parser::SnapshotMap;
use servo_arc::Arc; use servo_arc::Arc;
use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards}; use shared_lock::{Locked, SharedRwLockReadGuard, StylesheetGuards};
use stylesheets::{StylesheetContents, StylesheetInDocument}; use stylesheets::{CssRule, Origin, StylesheetContents, StylesheetInDocument};
use stylist::Stylist; use stylist::Stylist;
/// Little wrapper to a Gecko style sheet. /// Little wrapper to a Gecko style sheet.
@ -58,6 +59,16 @@ impl GeckoStyleSheet {
&*(self.raw()._base.mInner as *const StyleSheetInfo as *const ServoStyleSheetInner) &*(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 { impl Drop for GeckoStyleSheet {
@ -74,13 +85,12 @@ impl Clone for GeckoStyleSheet {
} }
impl StylesheetInDocument for GeckoStyleSheet { impl StylesheetInDocument for GeckoStyleSheet {
fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents { fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
debug_assert!(!self.inner().mContents.mRawPtr.is_null()); self.contents().origin
unsafe { }
let contents =
(&**StylesheetContents::as_arc(&&*self.inner().mContents.mRawPtr)) as *const _; fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
&*contents self.contents().quirks_mode
}
} }
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
@ -103,6 +113,11 @@ impl StylesheetInDocument for GeckoStyleSheet {
fn enabled(&self) -> bool { fn enabled(&self) -> bool {
true 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 /// The container for data that a Servo-backed Gecko document needs to style

View file

@ -478,7 +478,7 @@ where
sheet: &S, sheet: &S,
guard: &SharedRwLockReadGuard, guard: &SharedRwLockReadGuard,
) -> &mut SheetCollection<S> { ) -> &mut SheetCollection<S> {
let origin = sheet.contents(guard).origin; let origin = sheet.origin(guard);
self.collections.borrow_mut_for_origin(&origin) self.collections.borrow_mut_for_origin(&origin)
} }

View file

@ -6,6 +6,7 @@
//! //!
//! [import]: https://drafts.csswg.org/css-cascade-3/#at-import //! [import]: https://drafts.csswg.org/css-cascade-3/#at-import
use context::QuirksMode;
use cssparser::SourceLocation; use cssparser::SourceLocation;
use media_queries::MediaList; use media_queries::MediaList;
use shared_lock::{DeepCloneParams, DeepCloneWithLock}; use shared_lock::{DeepCloneParams, DeepCloneWithLock};
@ -13,13 +14,52 @@ use shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use str::CssStringWriter; use str::CssStringWriter;
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
use stylesheets::{StylesheetContents, StylesheetInDocument}; use stylesheets::{CssRule, Origin, StylesheetInDocument};
use values::CssUrl; 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. /// A sheet that is held from an import rule.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
#[derive(Debug)] #[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")] #[cfg(feature = "gecko")]
impl DeepCloneWithLock for ImportSheet { impl DeepCloneWithLock for ImportSheet {
@ -31,10 +71,15 @@ impl DeepCloneWithLock for ImportSheet {
) -> Self { ) -> Self {
use gecko::data::GeckoStyleSheet; use gecko::data::GeckoStyleSheet;
use gecko_bindings::bindings; use gecko_bindings::bindings;
let clone = unsafe { match *self {
bindings::Gecko_StyleSheet_Clone(self.0.raw() as *const _, params.reference_sheet) ImportSheet::Sheet(ref s) => {
}; let clone = unsafe {
ImportSheet(unsafe { GeckoStyleSheet::from_addrefed(clone) }) 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>); pub struct ImportSheet(pub ::servo_arc::Arc<::stylesheets::Stylesheet>);
impl StylesheetInDocument for ImportSheet { impl StylesheetInDocument for ImportSheet {
/// Get the media associated with this stylesheet. fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> { match *self {
self.0.media(guard) ImportSheet::Sheet(ref s) => s.contents().origin,
ImportSheet::Pending(ref p) => p.origin,
}
} }
fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents { fn quirks_mode(&self, _guard: &SharedRwLockReadGuard) -> QuirksMode {
self.0.contents(guard) match *self {
ImportSheet::Sheet(ref s) => s.contents().quirks_mode,
ImportSheet::Pending(ref p) => p.quirks_mode,
}
} }
fn enabled(&self) -> bool { 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(_) => &[],
}
} }
} }

View file

@ -9,8 +9,9 @@ use media_queries::Device;
use shared_lock::SharedRwLockReadGuard; use shared_lock::SharedRwLockReadGuard;
use smallvec::SmallVec; use smallvec::SmallVec;
use std::slice; use std::slice;
use stylesheets::{CssRule, CssRules, DocumentRule, ImportRule, MediaRule, SupportsRule}; use stylesheets::{CssRule, DocumentRule, ImportRule, MediaRule, SupportsRule};
use stylesheets::StylesheetInDocument; use stylesheets::StylesheetInDocument;
use stylesheets::import_rule::ImportSheet;
/// An iterator over a list of rules. /// An iterator over a list of rules.
pub struct RulesIterator<'a, 'b, C> pub struct RulesIterator<'a, 'b, C>
@ -35,10 +36,10 @@ where
device: &'a Device, device: &'a Device,
quirks_mode: QuirksMode, quirks_mode: QuirksMode,
guard: &'a SharedRwLockReadGuard<'b>, guard: &'a SharedRwLockReadGuard<'b>,
rules: &'a CssRules, rules: &'a [CssRule],
) -> Self { ) -> Self {
let mut stack = SmallVec::new(); let mut stack = SmallVec::new();
stack.push(rules.0.iter()); stack.push(rules.iter());
Self { Self {
device: device, device: device,
quirks_mode: quirks_mode, quirks_mode: quirks_mode,
@ -102,10 +103,7 @@ where
} }
import_rule import_rule
.stylesheet .stylesheet
.contents(self.guard) .rules(self.guard)
.rules
.read_with(self.guard)
.0
.iter() .iter()
}, },
CssRule::Document(ref doc_rule) => { CssRule::Document(ref doc_rule) => {

View file

@ -103,22 +103,10 @@ impl StylesheetContents {
} }
} }
/// Return an iterator using the condition `C`. /// Returns a reference to the list of rules.
#[inline] #[inline]
pub fn iter_rules<'a, 'b, C>( pub fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
&'a self, &self.rules.read_with(guard).0
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),
)
} }
/// Measure heap usage. /// Measure heap usage.
@ -189,32 +177,20 @@ macro_rules! rule_filter {
/// A trait to represent a given stylesheet in a document. /// A trait to represent a given stylesheet in a document.
pub trait StylesheetInDocument { pub trait StylesheetInDocument {
/// Get the contents of this stylesheet.
fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents;
/// Get the stylesheet origin. /// Get the stylesheet origin.
fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin { fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin;
self.contents(guard).origin
}
/// Get the stylesheet quirks mode. /// Get the stylesheet quirks mode.
fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode { fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode;
self.contents(guard).quirks_mode
} /// Get whether this stylesheet is enabled.
fn enabled(&self) -> bool;
/// Get the media associated with this stylesheet. /// Get the media associated with this stylesheet.
fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>; fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList>;
/// Returns whether the style-sheet applies for the current device. /// Returns a reference to the list of rules in this stylesheet.
fn is_effective_for_device(&self, device: &Device, guard: &SharedRwLockReadGuard) -> bool { fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule];
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;
/// Return an iterator using the condition `C`. /// Return an iterator using the condition `C`.
#[inline] #[inline]
@ -226,7 +202,15 @@ pub trait StylesheetInDocument {
where where
C: NestedRuleIterationCondition, 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 /// Return an iterator over the effective rules within the style-sheet, as
@ -255,8 +239,12 @@ pub trait StylesheetInDocument {
} }
impl StylesheetInDocument for Stylesheet { impl StylesheetInDocument for Stylesheet {
fn contents(&self, _: &SharedRwLockReadGuard) -> &StylesheetContents { fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
&self.contents 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> { fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
@ -266,6 +254,11 @@ impl StylesheetInDocument for Stylesheet {
fn enabled(&self) -> bool { fn enabled(&self) -> bool {
!self.disabled() !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<Stylesheet>`, with pointer comparison, and /// A simple wrapper over an `Arc<Stylesheet>`, with pointer comparison, and
@ -289,8 +282,12 @@ impl ToMediaListKey for DocumentStyleSheet {
} }
impl StylesheetInDocument for DocumentStyleSheet { impl StylesheetInDocument for DocumentStyleSheet {
fn contents(&self, guard: &SharedRwLockReadGuard) -> &StylesheetContents { fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
self.0.contents(guard) 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> { fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
@ -300,6 +297,11 @@ impl StylesheetInDocument for DocumentStyleSheet {
fn enabled(&self) -> bool { fn enabled(&self) -> bool {
self.0.enabled() self.0.enabled()
} }
#[inline]
fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
self.0.rules(guard)
}
} }
impl Stylesheet { impl Stylesheet {

View file

@ -2048,7 +2048,7 @@ pub extern "C" fn Servo_ImportRule_GetSheet(
rule: RawServoImportRuleBorrowed, rule: RawServoImportRuleBorrowed,
) -> *const ServoStyleSheet { ) -> *const ServoStyleSheet {
read_locked_arc(rule, |rule: &ImportRule| { read_locked_arc(rule, |rule: &ImportRule| {
rule.stylesheet.0.raw() as *const ServoStyleSheet rule.stylesheet.as_sheet().unwrap().raw() as *const ServoStyleSheet
}) })
} }

View file

@ -55,9 +55,8 @@ impl StyleStylesheetLoader for StylesheetLoader {
debug_assert!(!child_sheet.is_null(), debug_assert!(!child_sheet.is_null(),
"Import rules should always have a strong sheet"); "Import rules should always have a strong sheet");
let stylesheet = unsafe { let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) };
ImportSheet(GeckoStyleSheet::from_addrefed(child_sheet)) let stylesheet = ImportSheet::new(sheet);
};
Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet })) Arc::new(lock.wrap(ImportRule { url, source_location, stylesheet }))
} }
} }