Skip to content

Commit c8fa668

Browse files
committed
Update async CSS parse to report fetch errors immediately
1 parent 0393b5c commit c8fa668

File tree

1 file changed

+83
-89
lines changed

1 file changed

+83
-89
lines changed

components/script/stylesheet_loader.rs

Lines changed: 83 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ use servo_url::ServoUrl;
3939
use std::mem;
4040
use std::sync::atomic::AtomicBool;
4141
use std::sync::Mutex;
42+
use style::global_style_data::STYLE_THREAD_POOL;
4243
use style::media_queries::MediaList;
4344
use style::parser::ParserContext;
44-
use style::global_style_data::STYLE_THREAD_POOL;
4545
use style::shared_lock::{Locked, SharedRwLock};
4646
use style::stylesheets::import_rule::ImportSheet;
4747
use style::stylesheets::StylesheetLoader as StyleStylesheetLoader;
@@ -209,64 +209,63 @@ impl StylesheetLoadContext {
209209
None => return self.parse_sync(status),
210210
};
211211

212-
let metadata = match self.metadata.take() {
213-
Some(meta) => meta,
214-
None => return,
215-
};
216-
let is_css = metadata.content_type.map_or(false, |ct| {
217-
let mime: Mime = ct.into_inner().into();
218-
mime.type_() == mime::TEXT && mime.subtype() == mime::CSS
219-
});
220-
let data = if is_css {
221-
mem::replace(&mut self.data, vec![])
222-
} else {
223-
vec![]
224-
};
212+
let elem = self.elem.root();
213+
let document = self.document.root();
225214

226-
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
227-
let environment_encoding = UTF_8;
228-
let final_url = metadata.final_url;
229-
// FIXME: Revisit once consensus is reached at:
230-
// https://github.com/whatwg/html/issues/1142
231-
let successful = metadata.status.map_or(false, |(code, _)| code == 200);
232-
let charset = metadata.charset;
215+
if status.is_ok() {
216+
let metadata = match self.metadata.take() {
217+
Some(meta) => meta,
218+
None => return,
219+
};
220+
let is_css = metadata.content_type.map_or(false, |ct| {
221+
let mime: Mime = ct.into_inner().into();
222+
mime.type_() == mime::TEXT && mime.subtype() == mime::CSS
223+
});
224+
let data = if is_css {
225+
mem::replace(&mut self.data, vec![])
226+
} else {
227+
vec![]
228+
};
233229

234-
let document = self.document.root();
235-
let pipeline_id = document.window().pipeline_id();
236-
let shared_lock = document.style_shared_lock().clone();
237-
let quirks_mode = document.quirks_mode();
230+
// TODO: Get the actual value. http://dev.w3.org/csswg/css-syntax/#environment-encoding
231+
let environment_encoding = UTF_8;
232+
let final_url = metadata.final_url;
233+
// FIXME: Revisit once consensus is reached at:
234+
// https://github.com/whatwg/html/issues/1142
235+
let successful = metadata.status.map_or(false, |(code, _)| code == 200);
236+
let charset = metadata.charset;
238237

239-
let trusted_elem = self.elem.clone();
240-
let elem = self.elem.root();
241-
let script_chan = window_from_node(&*elem).main_thread_script_chan().clone();
238+
let pipeline_id = document.window().pipeline_id();
239+
let shared_lock = document.style_shared_lock().clone();
240+
let quirks_mode = document.quirks_mode();
242241

243-
let origin_clean = self.origin_clean;
244-
let url = self.url.clone();
242+
let trusted_elem = self.elem.clone();
243+
let script_chan = window_from_node(&*elem).main_thread_script_chan().clone();
245244

246-
let loader = ThreadSafeStylesheetLoader {
247-
elem: trusted_elem.clone(),
248-
script_chan: script_chan.clone(),
249-
pipeline_id: pipeline_id,
250-
};
245+
let origin_clean = self.origin_clean;
246+
let url = self.url.clone();
251247

252-
let status_ok = status.is_ok();
248+
let loader = ThreadSafeStylesheetLoader {
249+
elem: trusted_elem.clone(),
250+
script_chan: script_chan.clone(),
251+
pipeline_id: pipeline_id,
252+
};
253253

254-
// Unroot document and move that into the thread. TODO(mandreyel):
255-
// Should we move a rooted or an unrooted document into the thread?
256-
let document = self.document.clone();
257-
let request_generation_id = self.request_generation_id;
254+
// Unroot document and move that into the thread. TODO(mandreyel):
255+
// Should we move a rooted or an unrooted document into the thread?
256+
let document = self.document.clone();
257+
let request_generation_id = self.request_generation_id;
258258

259-
// Can't clone `MediaList` or move out of `self`, so manually move or
260-
// clone sheet source as appropriate.
261-
let mut source = match self.source {
262-
StylesheetSource::LinkElement(ref mut media) => {
263-
StylesheetSource::LinkElement(Some(media.take().unwrap()))
264-
},
265-
StylesheetSource::Import(ref mut sheet) => StylesheetSource::Import(sheet.clone()),
266-
};
259+
// Can't clone `MediaList` or move out of `self`, so manually move or
260+
// clone sheet source as appropriate.
261+
let mut source = match self.source {
262+
StylesheetSource::LinkElement(ref mut media) => {
263+
StylesheetSource::LinkElement(Some(media.take().unwrap()))
264+
},
265+
StylesheetSource::Import(ref mut sheet) => StylesheetSource::Import(sheet.clone()),
266+
};
267267

268-
thread_pool.spawn(move || {
269-
if status_ok {
268+
thread_pool.spawn(move || {
270269
let protocol_encoding_label = charset.as_ref().map(|s| &**s);
271270
let sheet = match source {
272271
StylesheetSource::LinkElement(ref mut media) => {
@@ -306,7 +305,6 @@ impl StylesheetLoadContext {
306305
ScriptThreadEventCategory::StylesheetLoad,
307306
Box::new(FinishAsyncStylesheetLoadTask {
308307
successful,
309-
invalidate_stylesheets: true,
310308
origin_clean,
311309
top_level_stylesheet: sheet,
312310
elem: trusted_elem,
@@ -317,28 +315,30 @@ impl StylesheetLoadContext {
317315
pipeline_id,
318316
TaskSourceName::Networking,
319317
)));
320-
} else {
321-
// Even if we didn't manage to parse the sheet, we still need to
322-
// send a message to the event loop to tell the document that
323-
// the load has finished.
324-
// TODO(mandreyel): What to do with errors?
325-
let _ = script_chan.send(Msg::Common(CommonScriptMsg::Task(
326-
ScriptThreadEventCategory::StylesheetLoad,
327-
Box::new(FinishAsyncStylesheetLoadTask {
328-
successful,
329-
invalidate_stylesheets: false,
330-
origin_clean,
331-
top_level_stylesheet: None,
332-
elem: trusted_elem,
333-
document,
334-
url,
335-
request_generation_id: None,
336-
}),
337-
pipeline_id,
338-
TaskSourceName::Networking,
339-
)));
318+
});
319+
} else {
320+
// The load was not successful, let document know.
321+
let owner = elem
322+
.upcast::<Element>()
323+
.as_stylesheet_owner()
324+
.expect("Stylesheet not loaded by <style> or <link> element!");
325+
owner.set_origin_clean(self.origin_clean);
326+
if owner.parser_inserted() {
327+
document.decrement_script_blocking_stylesheet_count();
340328
}
341-
});
329+
330+
document.finish_load(LoadType::Stylesheet(self.url.clone()));
331+
332+
let successful = false;
333+
if let Some(any_failed) = owner.load_finished(successful) {
334+
let event = if any_failed {
335+
atom!("error")
336+
} else {
337+
atom!("load")
338+
};
339+
elem.upcast::<EventTarget>().fire_event(event);
340+
}
341+
}
342342
}
343343
}
344344

@@ -580,24 +580,22 @@ impl TaskOnce for ImportStylesheetTask {
580580
}
581581

582582
/// A stylesheet may be parsed on a thread pool rather than its document's event
583-
/// loop. Setting the parsed stylesheet on the HTML element and the document
584-
/// needs to be done on the event loop, thus when the thread parsing the sheet
585-
/// is done it enqueues this task on the script thread's task queue that's
586-
/// managing the document.
583+
/// loop. However, setting the parsed stylesheet on the HTML element and the
584+
/// document needs to be done on the event loop, thus when the thread parsing
585+
/// the sheet is done it enqueues this task on the script thread's task queue
586+
/// that's managing the document.
587587
///
588588
/// This task is used for both top-level as well as nested stylesheet loads. For
589589
/// top-level sheets the `top_level_stylesheet` field must be set, but parsing
590-
/// an imported sheet returns an empty sheet wrapped in an Arc in an
591-
/// `ImportRule` (which is inserted in its parent's rule list), and after an
592-
/// async fetch and parse, the empty stylesheet is set through the Arc
593-
/// reference.
590+
/// an imported sheet (in loader's `request_stylesheet`) returns an empty sheet
591+
/// wrapped in an Arc in an `ImportRule` (which is inserted in its parent's rule
592+
/// list), and after an async fetch and parse, the empty stylesheet is set
593+
/// through the Arc reference.
594+
///
595+
/// This task is only enqueued on the event loop if the load was successful.
594596
struct FinishAsyncStylesheetLoadTask {
595597
/// Used to tell the document whether the load has concluded successfully.
596598
successful: bool,
597-
/// Whether document's current stylesheet needs to be invalidated. This is
598-
/// necessary if a new top-level stylesheet or an import sheet has been
599-
/// successfully parsed.
600-
invalidate_stylesheets: bool,
601599
origin_clean: bool,
602600
/// If this was a top-level stylesheet load, the parsed stylesheet is placed
603601
/// here.
@@ -640,11 +638,7 @@ impl TaskOnce for FinishAsyncStylesheetLoadTask {
640638
}
641639
}
642640

643-
// We also need to invalidate a document's stylesheets if this was an
644-
// import rule load, not just in the case of top-level sheet loads.
645-
if self.invalidate_stylesheets {
646-
document.invalidate_stylesheets();
647-
}
641+
document.invalidate_stylesheets();
648642

649643
let owner = elem
650644
.upcast::<Element>()

0 commit comments

Comments
 (0)