stylesheet_loader.rs (5851B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ 4 5 use cssparser::SourceLocation; 6 use nsstring::nsCString; 7 use servo_arc::Arc; 8 use style::context::QuirksMode; 9 use style::gecko::data::GeckoStyleSheet; 10 use style::gecko_bindings::bindings; 11 use style::gecko_bindings::bindings::Gecko_LoadStyleSheet; 12 use style::gecko_bindings::structs::{Loader, LoaderReusableStyleSheets}; 13 use style::gecko_bindings::structs::{ 14 SheetLoadData, SheetLoadDataHolder, StyleSheet as DomStyleSheet, 15 }; 16 use style::gecko_bindings::sugar::refptr::RefPtr; 17 use style::global_style_data::GLOBAL_STYLE_DATA; 18 use style::media_queries::MediaList; 19 use style::shared_lock::{Locked, SharedRwLock}; 20 use style::stylesheets::import_rule::{ImportLayer, ImportSheet, ImportSupportsCondition}; 21 use style::stylesheets::AllowImportRules; 22 use style::stylesheets::{ImportRule, Origin, StylesheetLoader as StyleStylesheetLoader}; 23 use style::stylesheets::{StylesheetContents, UrlExtraData}; 24 use style::values::CssUrl; 25 26 pub struct StylesheetLoader( 27 *mut Loader, 28 *mut DomStyleSheet, 29 *mut SheetLoadData, 30 *mut LoaderReusableStyleSheets, 31 ); 32 33 impl StylesheetLoader { 34 pub fn new( 35 loader: *mut Loader, 36 parent: *mut DomStyleSheet, 37 parent_load_data: *mut SheetLoadData, 38 reusable_sheets: *mut LoaderReusableStyleSheets, 39 ) -> Self { 40 StylesheetLoader(loader, parent, parent_load_data, reusable_sheets) 41 } 42 } 43 44 impl StyleStylesheetLoader for StylesheetLoader { 45 fn request_stylesheet( 46 &self, 47 url: CssUrl, 48 source_location: SourceLocation, 49 lock: &SharedRwLock, 50 media: Arc<Locked<MediaList>>, 51 supports: Option<ImportSupportsCondition>, 52 layer: ImportLayer, 53 ) -> Arc<Locked<ImportRule>> { 54 // Ensure the supports conditions for this @import are true, if not, refuse to load 55 if !supports.as_ref().map_or(true, |s| s.enabled) { 56 return Arc::new(lock.wrap(ImportRule { 57 url, 58 stylesheet: ImportSheet::new_refused(), 59 supports, 60 layer, 61 source_location, 62 })); 63 } 64 65 // After we get this raw pointer ImportRule will be moved into a lock and Arc 66 // and so the Arc<Url> pointer inside will also move, 67 // but the Url it points to or the allocating backing the String inside that Url won’t, 68 // so this raw pointer will still be valid. 69 70 let child_sheet = 71 unsafe { Gecko_LoadStyleSheet(self.0, self.1, self.2, self.3, &url, media.into()) }; 72 73 debug_assert!( 74 !child_sheet.is_null(), 75 "Import rules should always have a strong sheet" 76 ); 77 let sheet = unsafe { GeckoStyleSheet::from_addrefed(child_sheet) }; 78 let stylesheet = ImportSheet::new(sheet); 79 Arc::new(lock.wrap(ImportRule { 80 url, 81 stylesheet, 82 supports, 83 layer, 84 source_location, 85 })) 86 } 87 } 88 89 pub struct AsyncStylesheetParser { 90 load_data: RefPtr<SheetLoadDataHolder>, 91 extra_data: UrlExtraData, 92 bytes: nsCString, 93 origin: Origin, 94 quirks_mode: QuirksMode, 95 allow_import_rules: AllowImportRules, 96 } 97 98 impl AsyncStylesheetParser { 99 pub fn new( 100 load_data: RefPtr<SheetLoadDataHolder>, 101 extra_data: UrlExtraData, 102 bytes: nsCString, 103 origin: Origin, 104 quirks_mode: QuirksMode, 105 allow_import_rules: AllowImportRules, 106 ) -> Self { 107 AsyncStylesheetParser { 108 load_data, 109 extra_data, 110 bytes, 111 origin, 112 quirks_mode, 113 allow_import_rules, 114 } 115 } 116 117 pub fn parse(self) { 118 let global_style_data = &*GLOBAL_STYLE_DATA; 119 let input: &str = unsafe { (*self.bytes).as_str_unchecked() }; 120 121 // Note: Parallel CSS parsing doesn't report CSS errors. When errors are 122 // being logged, Gecko prevents the parallel parsing path from running. 123 let sheet = StylesheetContents::from_str( 124 input, 125 self.extra_data.clone(), 126 self.origin, 127 &global_style_data.shared_lock, 128 Some(&self), 129 None, 130 self.quirks_mode.into(), 131 self.allow_import_rules, 132 /* sanitized_output = */ None, 133 ); 134 135 unsafe { 136 bindings::Gecko_StyleSheet_FinishAsyncParse(self.load_data.get(), sheet.into()); 137 } 138 } 139 } 140 141 impl StyleStylesheetLoader for AsyncStylesheetParser { 142 fn request_stylesheet( 143 &self, 144 url: CssUrl, 145 source_location: SourceLocation, 146 lock: &SharedRwLock, 147 media: Arc<Locked<MediaList>>, 148 supports: Option<ImportSupportsCondition>, 149 layer: ImportLayer, 150 ) -> Arc<Locked<ImportRule>> { 151 // Ensure the supports conditions for this @import are true, if not, refuse to load 152 if !supports.as_ref().map_or(true, |s| s.enabled) { 153 return Arc::new(lock.wrap(ImportRule { 154 url: url.clone(), 155 stylesheet: ImportSheet::new_refused(), 156 supports, 157 layer, 158 source_location, 159 })); 160 } 161 162 let stylesheet = ImportSheet::new_pending(); 163 let rule = Arc::new(lock.wrap(ImportRule { 164 url: url.clone(), 165 stylesheet, 166 supports, 167 layer, 168 source_location, 169 })); 170 171 unsafe { 172 bindings::Gecko_LoadStyleSheetAsync( 173 self.load_data.get(), 174 &url, 175 media.into(), 176 rule.clone().into(), 177 ); 178 } 179 180 rule 181 } 182 }