summaryrefslogtreecommitdiffstats
path: root/servo/components/style/stylesheets/import_rule.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/components/style/stylesheets/import_rule.rs')
-rw-r--r--servo/components/style/stylesheets/import_rule.rs223
1 files changed, 223 insertions, 0 deletions
diff --git a/servo/components/style/stylesheets/import_rule.rs b/servo/components/style/stylesheets/import_rule.rs
new file mode 100644
index 0000000000..5efae0a3ee
--- /dev/null
+++ b/servo/components/style/stylesheets/import_rule.rs
@@ -0,0 +1,223 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+//! The [`@import`][import] at-rule.
+//!
+//! [import]: https://drafts.csswg.org/css-cascade-3/#at-import
+
+use crate::context::QuirksMode;
+use crate::media_queries::MediaList;
+use crate::shared_lock::{DeepCloneParams, DeepCloneWithLock};
+use crate::shared_lock::{SharedRwLock, SharedRwLockReadGuard, ToCssWithGuard};
+use crate::str::CssStringWriter;
+use crate::stylesheets::{CssRule, Origin, StylesheetInDocument};
+use crate::values::CssUrl;
+use cssparser::SourceLocation;
+use std::fmt::{self, Write};
+use style_traits::{CssWriter, ToCss};
+use to_shmem::{self, SharedMemoryBuilder, ToShmem};
+
+/// With asynchronous stylesheet parsing, we can't synchronously create a
+/// GeckoStyleSheet. So we use this placeholder instead.
+#[cfg(feature = "gecko")]
+#[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 enum ImportSheet {
+ /// A bonafide stylesheet.
+ Sheet(crate::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: crate::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<&crate::gecko::data::GeckoStyleSheet> {
+ match *self {
+ ImportSheet::Sheet(ref s) => Some(s),
+ ImportSheet::Pending(_) => None,
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl DeepCloneWithLock for ImportSheet {
+ fn deep_clone_with_lock(
+ &self,
+ _lock: &SharedRwLock,
+ _guard: &SharedRwLockReadGuard,
+ params: &DeepCloneParams,
+ ) -> Self {
+ use crate::gecko::data::GeckoStyleSheet;
+ use crate::gecko_bindings::bindings;
+ 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()),
+ }
+ }
+}
+
+#[cfg(feature = "gecko")]
+impl StylesheetInDocument for ImportSheet {
+ fn origin(&self, _guard: &SharedRwLockReadGuard) -> Origin {
+ match *self {
+ ImportSheet::Sheet(ref s) => s.contents().origin,
+ ImportSheet::Pending(ref p) => p.origin,
+ }
+ }
+
+ 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 {
+ 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(_) => &[],
+ }
+ }
+}
+
+/// A sheet that is held from an import rule.
+#[cfg(feature = "servo")]
+#[derive(Debug)]
+pub struct ImportSheet(pub ::servo_arc::Arc<crate::stylesheets::Stylesheet>);
+
+#[cfg(feature = "servo")]
+impl StylesheetInDocument for ImportSheet {
+ fn origin(&self, guard: &SharedRwLockReadGuard) -> Origin {
+ self.0.origin(guard)
+ }
+
+ fn quirks_mode(&self, guard: &SharedRwLockReadGuard) -> QuirksMode {
+ self.0.quirks_mode(guard)
+ }
+
+ fn enabled(&self) -> bool {
+ self.0.enabled()
+ }
+
+ fn media<'a>(&'a self, guard: &'a SharedRwLockReadGuard) -> Option<&'a MediaList> {
+ self.0.media(guard)
+ }
+
+ fn rules<'a, 'b: 'a>(&'a self, guard: &'b SharedRwLockReadGuard) -> &'a [CssRule] {
+ self.0.rules(guard)
+ }
+}
+
+#[cfg(feature = "servo")]
+impl DeepCloneWithLock for ImportSheet {
+ fn deep_clone_with_lock(
+ &self,
+ _lock: &SharedRwLock,
+ _guard: &SharedRwLockReadGuard,
+ _params: &DeepCloneParams,
+ ) -> Self {
+ use servo_arc::Arc;
+
+ ImportSheet(Arc::new((&*self.0).clone()))
+ }
+}
+
+/// The [`@import`][import] at-rule.
+///
+/// [import]: https://drafts.csswg.org/css-cascade-3/#at-import
+#[derive(Debug)]
+pub struct ImportRule {
+ /// The `<url>` this `@import` rule is loading.
+ pub url: CssUrl,
+
+ /// The stylesheet is always present. However, in the case of gecko async
+ /// parsing, we don't actually have a Gecko sheet at first, and so the
+ /// ImportSheet just has stub behavior until it appears.
+ pub stylesheet: ImportSheet,
+
+ /// The line and column of the rule's source code.
+ pub source_location: SourceLocation,
+}
+
+impl ToShmem for ImportRule {
+ fn to_shmem(&self, _builder: &mut SharedMemoryBuilder) -> to_shmem::Result<Self> {
+ Err(String::from(
+ "ToShmem failed for ImportRule: cannot handle imported style sheets",
+ ))
+ }
+}
+
+impl DeepCloneWithLock for ImportRule {
+ fn deep_clone_with_lock(
+ &self,
+ lock: &SharedRwLock,
+ guard: &SharedRwLockReadGuard,
+ params: &DeepCloneParams,
+ ) -> Self {
+ ImportRule {
+ url: self.url.clone(),
+ stylesheet: self.stylesheet.deep_clone_with_lock(lock, guard, params),
+ source_location: self.source_location.clone(),
+ }
+ }
+}
+
+impl ToCssWithGuard for ImportRule {
+ fn to_css(&self, guard: &SharedRwLockReadGuard, dest: &mut CssStringWriter) -> fmt::Result {
+ dest.write_str("@import ")?;
+ self.url.to_css(&mut CssWriter::new(dest))?;
+
+ match self.stylesheet.media(guard) {
+ Some(media) if !media.is_empty() => {
+ dest.write_str(" ")?;
+ media.to_css(&mut CssWriter::new(dest))?;
+ },
+ _ => {},
+ };
+
+ dest.write_str(";")
+ }
+}