Introduce PendingScript

This moves scripts' loading results in Document, instead of maintaining them
behind a DOMRefCell in each HTMLScriptElement.
This commit is contained in:
Anthony Ramine 2017-01-11 14:13:15 +01:00
parent 965370c0bf
commit 30f0553ac7
8 changed files with 193 additions and 82 deletions

View file

@ -4,7 +4,6 @@
use document_loader::LoadType;
use dom::attr::Attr;
use dom::bindings::cell::DOMRefCell;
use dom::bindings::codegen::Bindings::AttrBinding::AttrMethods;
use dom::bindings::codegen::Bindings::DocumentBinding::DocumentMethods;
use dom::bindings::codegen::Bindings::HTMLScriptElementBinding;
@ -61,9 +60,6 @@ pub struct HTMLScriptElement {
/// Document of the parser that created this element
parser_document: JS<Document>,
/// The source this script was loaded from
load: DOMRefCell<Option<Result<ClassicScript, NetworkError>>>,
}
impl HTMLScriptElement {
@ -77,7 +73,6 @@ impl HTMLScriptElement {
non_blocking: Cell::new(creator != ElementCreator::ParserCreated),
ready_to_be_parser_executed: Cell::new(false),
parser_document: JS::from_ref(document),
load: DOMRefCell::new(None),
}
}
@ -137,10 +132,14 @@ impl ClassicScript {
}
}
pub type ScriptResult = Result<ClassicScript, NetworkError>;
/// The context required for asynchronously loading an external script source.
struct ScriptContext {
/// The element that initiated the request.
elem: Trusted<HTMLScriptElement>,
/// The kind of external script.
kind: ExternalScriptKind,
/// The (fallback) character encoding argument to the "fetch a classic
/// script" algorithm.
character_encoding: EncodingRef,
@ -207,10 +206,16 @@ impl FetchResponseListener for ScriptContext {
// https://html.spec.whatwg.org/multipage/#prepare-a-script
// Step 18.6 (When the chosen algorithm asynchronously completes).
let elem = self.elem.root();
*elem.load.borrow_mut() = Some(load);
elem.ready_to_be_parser_executed.set(true);
let document = document_from_node(&*elem);
match self.kind {
ExternalScriptKind::Asap => document.asap_script_loaded(&elem, load),
ExternalScriptKind::AsapInOrder => document.asap_in_order_script_loaded(&elem, load),
ExternalScriptKind::Deferred => document.deferred_script_loaded(&elem, load),
ExternalScriptKind::ParsingBlocking => document.pending_parsing_blocking_script_loaded(&elem, load),
}
document.finish_load(LoadType::Script(self.url.clone()));
}
}
@ -219,6 +224,7 @@ impl PreInvoke for ScriptContext {}
/// https://html.spec.whatwg.org/multipage/#fetch-a-classic-script
fn fetch_a_classic_script(script: &HTMLScriptElement,
kind: ExternalScriptKind,
url: ServoUrl,
cors_setting: Option<CorsSettings>,
integrity_metadata: String,
@ -254,6 +260,7 @@ fn fetch_a_classic_script(script: &HTMLScriptElement,
let context = Arc::new(Mutex::new(ScriptContext {
elem: Trusted::new(script),
kind: kind,
character_encoding: character_encoding,
data: vec!(),
metadata: None,
@ -422,19 +429,19 @@ impl HTMLScriptElement {
};
// Step 20.6.
fetch_a_classic_script(self, url, cors_setting, integrity_metadata.to_owned(), encoding);
fetch_a_classic_script(self, kind, url, cors_setting, integrity_metadata.to_owned(), encoding);
// Step 22.
match kind {
ExternalScriptKind::Deferred => doc.add_deferred_script(self),
ExternalScriptKind::ParsingBlocking => doc.set_pending_parsing_blocking_script(self),
ExternalScriptKind::ParsingBlocking => doc.set_pending_parsing_blocking_script(self, None),
ExternalScriptKind::AsapInOrder => doc.push_asap_in_order_script(self),
ExternalScriptKind::Asap => doc.add_asap_script(self),
}
} else {
// Step 21.
assert!(!text.is_empty());
*self.load.borrow_mut() = Some(Ok(ClassicScript::internal(text, base_url)));
let result = Ok(ClassicScript::internal(text, base_url));
self.ready_to_be_parser_executed.set(true);
// Step 22.
@ -442,10 +449,10 @@ impl HTMLScriptElement {
doc.get_current_parser().map_or(false, |parser| parser.script_nesting_level() <= 1) &&
doc.get_script_blocking_stylesheets_count() > 0 {
// Step 22.e: classic, has no src, was parser-inserted, is blocked on stylesheet.
doc.set_pending_parsing_blocking_script(self);
doc.set_pending_parsing_blocking_script(self, Some(result));
} else {
// Step 22.f: otherwise.
self.execute();
self.execute(result);
}
}
}
@ -455,7 +462,7 @@ impl HTMLScriptElement {
}
/// https://html.spec.whatwg.org/multipage/#execute-the-script-block
pub fn execute(&self) {
pub fn execute(&self, result: Result<ClassicScript, NetworkError>) {
assert!(self.ready_to_be_parser_executed.get());
// Step 1.
@ -464,8 +471,7 @@ impl HTMLScriptElement {
return;
}
let load = self.load.borrow_mut().take().unwrap();
let script = match load {
let script = match result {
// Step 2.
Err(e) => {
warn!("error loading script {:?}", e);