summaryrefslogtreecommitdiffstats
path: root/servo/ports/geckolib/stylesheet_loader.rs
diff options
context:
space:
mode:
Diffstat (limited to 'servo/ports/geckolib/stylesheet_loader.rs')
-rw-r--r--servo/ports/geckolib/stylesheet_loader.rs200
1 files changed, 200 insertions, 0 deletions
diff --git a/servo/ports/geckolib/stylesheet_loader.rs b/servo/ports/geckolib/stylesheet_loader.rs
new file mode 100644
index 0000000000..08706fa6a8
--- /dev/null
+++ b/servo/ports/geckolib/stylesheet_loader.rs
@@ -0,0 +1,200 @@
+/* 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/. */
+
+use cssparser::SourceLocation;
+use nsstring::nsCString;
+use servo_arc::Arc;
+use style::context::QuirksMode;
+use style::gecko::data::GeckoStyleSheet;
+use style::gecko_bindings::bindings;
+use style::gecko_bindings::bindings::Gecko_LoadStyleSheet;
+use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets};
+use style::gecko_bindings::structs::{
+ SheetLoadData, SheetLoadDataHolder, StyleSheet as DomStyleSheet,
+};
+use style::gecko_bindings::sugar::refptr::RefPtr;
+use style::global_style_data::GLOBAL_STYLE_DATA;
+use style::media_queries::MediaList;
+use style::parser::ParserContext;
+use style::shared_lock::{Locked, SharedRwLock};
+use style::stylesheets::import_rule::{ImportLayer, ImportSheet, ImportSupportsCondition};
+use style::stylesheets::AllowImportRules;
+use style::stylesheets::{ImportRule, Origin, StylesheetLoader as StyleStylesheetLoader};
+use style::stylesheets::{StylesheetContents, UrlExtraData};
+use style::use_counters::UseCounters;
+use style::values::CssUrl;
+
+pub struct StylesheetLoader(
+ *mut Loader,
+ *mut DomStyleSheet,
+ *mut SheetLoadData,
+ *mut LoaderReusableStyleSheets,
+);
+
+impl StylesheetLoader {
+ pub fn new(
+ loader: *mut Loader,
+ parent: *mut DomStyleSheet,
+ parent_load_data: *mut SheetLoadData,
+ reusable_sheets: *mut LoaderReusableStyleSheets,
+ ) -> Self {
+ StylesheetLoader(loader, parent, parent_load_data, reusable_sheets)
+ }
+}
+
+impl StyleStylesheetLoader for StylesheetLoader {
+ fn request_stylesheet(
+ &self,
+ url: CssUrl,
+ source_location: SourceLocation,
+ _context: &ParserContext,
+ lock: &SharedRwLock,
+ media: Arc<Locked<MediaList>>,
+ supports: Option<ImportSupportsCondition>,
+ layer: ImportLayer,
+ ) -> Arc<Locked<ImportRule>> {
+ // Ensure the supports conditions for this @import are true, if not, refuse to load
+ if !supports.as_ref().map_or(true, |s| s.enabled) {
+ return Arc::new(lock.wrap(ImportRule {
+ url,
+ stylesheet: ImportSheet::new_refused(),
+ supports,
+ layer,
+ source_location,
+ }));
+ }
+
+ // After we get this raw pointer ImportRule will be moved into a lock and Arc
+ // and so the Arc<Url> pointer inside will also move,
+ // but the Url it points to or the allocating backing the String inside that Url won’t,
+ // so this raw pointer will still be valid.
+
+ let child_sheet =
+ unsafe { Gecko_LoadStyleSheet(self.0, self.1, self.2, self.3, &url, media.into()) };
+
+ debug_assert!(
+ !child_sheet.is_null(),
+ "Import rules should always have a strong sheet"
+ );
+ let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) };
+ let stylesheet = ImportSheet::new(sheet);
+ Arc::new(lock.wrap(ImportRule {
+ url,
+ stylesheet,
+ supports,
+ layer,
+ source_location,
+ }))
+ }
+}
+
+pub struct AsyncStylesheetParser {
+ load_data: RefPtr<SheetLoadDataHolder>,
+ extra_data: UrlExtraData,
+ bytes: nsCString,
+ origin: Origin,
+ quirks_mode: QuirksMode,
+ should_record_use_counters: bool,
+ allow_import_rules: AllowImportRules,
+}
+
+impl AsyncStylesheetParser {
+ pub fn new(
+ load_data: RefPtr<SheetLoadDataHolder>,
+ extra_data: UrlExtraData,
+ bytes: nsCString,
+ origin: Origin,
+ quirks_mode: QuirksMode,
+ should_record_use_counters: bool,
+ allow_import_rules: AllowImportRules,
+ ) -> Self {
+ AsyncStylesheetParser {
+ load_data,
+ extra_data,
+ bytes,
+ origin,
+ quirks_mode,
+ should_record_use_counters,
+ allow_import_rules,
+ }
+ }
+
+ pub fn parse(self) {
+ let global_style_data = &*GLOBAL_STYLE_DATA;
+ let input: &str = unsafe { (*self.bytes).as_str_unchecked() };
+
+ let use_counters = if self.should_record_use_counters {
+ Some(Box::new(UseCounters::default()))
+ } else {
+ None
+ };
+
+ // Note: Parallel CSS parsing doesn't report CSS errors. When errors are
+ // being logged, Gecko prevents the parallel parsing path from running.
+ let sheet = StylesheetContents::from_str(
+ input,
+ self.extra_data.clone(),
+ self.origin,
+ &global_style_data.shared_lock,
+ Some(&self),
+ None,
+ self.quirks_mode.into(),
+ use_counters.as_deref(),
+ self.allow_import_rules,
+ /* sanitized_output = */ None,
+ );
+
+ unsafe {
+ bindings::Gecko_StyleSheet_FinishAsyncParse(
+ self.load_data.get(),
+ sheet.into(),
+ use_counters.map_or(std::ptr::null_mut(), Box::into_raw),
+ );
+ }
+ }
+}
+
+impl StyleStylesheetLoader for AsyncStylesheetParser {
+ fn request_stylesheet(
+ &self,
+ url: CssUrl,
+ source_location: SourceLocation,
+ _context: &ParserContext,
+ lock: &SharedRwLock,
+ media: Arc<Locked<MediaList>>,
+ supports: Option<ImportSupportsCondition>,
+ layer: ImportLayer,
+ ) -> Arc<Locked<ImportRule>> {
+ // Ensure the supports conditions for this @import are true, if not, refuse to load
+ if !supports.as_ref().map_or(true, |s| s.enabled) {
+ return Arc::new(lock.wrap(ImportRule {
+ url: url.clone(),
+ stylesheet: ImportSheet::new_refused(),
+ supports,
+ layer,
+ source_location,
+ }));
+ }
+
+ let stylesheet = ImportSheet::new_pending();
+ let rule = Arc::new(lock.wrap(ImportRule {
+ url: url.clone(),
+ stylesheet,
+ supports,
+ layer,
+ source_location,
+ }));
+
+ unsafe {
+ bindings::Gecko_LoadStyleSheetAsync(
+ self.load_data.get(),
+ &url,
+ media.into(),
+ rule.clone().into(),
+ );
+ }
+
+ rule
+ }
+}