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

@ -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(_) => &[],
}
}
}