aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
authorJosh Matthews <josh@joshmatthews.net>2024-08-16 12:25:50 -0400
committerGitHub <noreply@github.com>2024-08-16 16:25:50 +0000
commit4df7a1af25b46146fc5a580ad2e50f2ebe91e154 (patch)
tree3e1d6fe86238b67d051c43b1b8a09b73db59051e /components
parentd44c0f7e5dd9952506dfc491975cc84d7dac111a (diff)
downloadservo-4df7a1af25b46146fc5a580ad2e50f2ebe91e154.tar.gz
servo-4df7a1af25b46146fc5a580ad2e50f2ebe91e154.zip
Support HTML parser reentrancy (#32820)
* Update parser interface for reentrancy. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Remove assertions around invoking scripts with active parser. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Add regression test. Signed-off-by: Josh Matthews <josh@joshmatthews.net> * Run test with normal and async html parser. Signed-off-by: Josh Matthews <josh@joshmatthews.net> --------- Signed-off-by: Josh Matthews <josh@joshmatthews.net>
Diffstat (limited to 'components')
-rw-r--r--components/script/dom/document.rs12
-rw-r--r--components/script/dom/eventtarget.rs5
-rw-r--r--components/script/dom/servoparser/async_html.rs133
-rw-r--r--components/script/dom/servoparser/html.rs9
-rw-r--r--components/script/dom/servoparser/mod.rs151
-rw-r--r--components/script/dom/servoparser/prefetch.rs33
-rw-r--r--components/script/dom/servoparser/xml.rs8
-rw-r--r--components/script/dom/window.rs3
8 files changed, 165 insertions, 189 deletions
diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs
index 048628e805f..9151a2be9a7 100644
--- a/components/script/dom/document.rs
+++ b/components/script/dom/document.rs
@@ -2670,18 +2670,6 @@ impl Document {
self.current_parser.get()
}
- pub fn can_invoke_script(&self) -> bool {
- match self.get_current_parser() {
- Some(parser) => {
- // It is safe to run script if the parser is not actively parsing,
- // or if it is impossible to interact with the token stream.
- parser.parser_is_not_active() ||
- self.throw_on_dynamic_markup_insertion_counter.get() > 0
- },
- None => true,
- }
- }
-
/// Iterate over all iframes in the document.
pub fn iter_iframes(&self) -> impl Iterator<Item = DomRoot<HTMLIFrameElement>> {
self.upcast::<Node>()
diff --git a/components/script/dom/eventtarget.rs b/components/script/dom/eventtarget.rs
index aa85c5ac090..26756cefd89 100644
--- a/components/script/dom/eventtarget.rs
+++ b/components/script/dom/eventtarget.rs
@@ -395,11 +395,6 @@ impl EventTarget {
}
pub fn dispatch_event(&self, event: &Event) -> EventStatus {
- if let Some(window) = self.global().downcast::<Window>() {
- if window.has_document() {
- assert!(window.Document().can_invoke_script());
- }
- };
event.dispatch(self, false)
}
diff --git a/components/script/dom/servoparser/async_html.rs b/components/script/dom/servoparser/async_html.rs
index 7200b9ed5c6..ed405c9ca61 100644
--- a/components/script/dom/servoparser/async_html.rs
+++ b/components/script/dom/servoparser/async_html.rs
@@ -5,7 +5,7 @@
#![allow(crown::unrooted_must_root)]
use std::borrow::Cow;
-use std::cell::Cell;
+use std::cell::{Cell, Ref, RefCell, RefMut};
use std::collections::vec_deque::VecDeque;
use std::collections::HashMap;
use std::thread;
@@ -171,7 +171,7 @@ enum ToHtmlTokenizerMsg {
}
fn create_buffer_queue(mut buffers: VecDeque<SendTendril<UTF8>>) -> BufferQueue {
- let mut buffer_queue = BufferQueue::default();
+ let buffer_queue = BufferQueue::default();
while let Some(st) = buffers.pop_front() {
buffer_queue.push_back(StrTendril::from(st));
}
@@ -214,7 +214,7 @@ pub struct Tokenizer {
#[no_trace]
html_tokenizer_sender: Sender<ToHtmlTokenizerMsg>,
#[ignore_malloc_size_of = "Defined in std"]
- nodes: HashMap<ParseNodeId, Dom<Node>>,
+ nodes: RefCell<HashMap<ParseNodeId, Dom<Node>>>,
#[no_trace]
url: ServoUrl,
parsing_algorithm: ParsingAlgorithm,
@@ -236,17 +236,17 @@ impl Tokenizer {
None => ParsingAlgorithm::Normal,
};
- let mut tokenizer = Tokenizer {
+ let tokenizer = Tokenizer {
document: Dom::from_ref(document),
receiver: tokenizer_receiver,
html_tokenizer_sender: to_html_tokenizer_sender,
- nodes: HashMap::new(),
+ nodes: RefCell::new(HashMap::new()),
url,
parsing_algorithm: algorithm,
};
tokenizer.insert_node(0, Dom::from_ref(document.upcast()));
- let mut sink = Sink::new(to_tokenizer_sender.clone());
+ let sink = Sink::new(to_tokenizer_sender.clone());
let mut ctxt_parse_node = None;
let mut form_parse_node = None;
let mut fragment_context_is_some = false;
@@ -283,7 +283,7 @@ impl Tokenizer {
tokenizer
}
- pub fn feed(&mut self, input: &mut BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
+ pub fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
let mut send_tendrils = VecDeque::new();
while let Some(str) = input.pop_front() {
send_tendrils.push_back(SendTendril::from(str));
@@ -306,7 +306,7 @@ impl Tokenizer {
ToTokenizerMsg::ProcessOperation(parse_op) => self.process_operation(parse_op),
ToTokenizerMsg::TokenizerResultDone { updated_input } => {
let buffer_queue = create_buffer_queue(updated_input);
- *input = buffer_queue;
+ input.replace_with(buffer_queue);
return TokenizerResult::Done;
},
ToTokenizerMsg::TokenizerResultScript {
@@ -314,7 +314,7 @@ impl Tokenizer {
updated_input,
} => {
let buffer_queue = create_buffer_queue(updated_input);
- *input = buffer_queue;
+ input.replace_with(buffer_queue);
let script = self.get_node(&script.id);
return TokenizerResult::Script(DomRoot::from_ref(script.downcast().unwrap()));
},
@@ -323,7 +323,7 @@ impl Tokenizer {
}
}
- pub fn end(&mut self) {
+ pub fn end(&self) {
self.html_tokenizer_sender
.send(ToHtmlTokenizerMsg::End)
.unwrap();
@@ -344,21 +344,23 @@ impl Tokenizer {
&self.url
}
- pub fn set_plaintext_state(&mut self) {
+ pub fn set_plaintext_state(&self) {
self.html_tokenizer_sender
.send(ToHtmlTokenizerMsg::SetPlainTextState)
.unwrap();
}
- fn insert_node(&mut self, id: ParseNodeId, node: Dom<Node>) {
- assert!(self.nodes.insert(id, node).is_none());
+ fn insert_node(&self, id: ParseNodeId, node: Dom<Node>) {
+ assert!(self.nodes.borrow_mut().insert(id, node).is_none());
}
- fn get_node<'a>(&'a self, id: &ParseNodeId) -> &'a Dom<Node> {
- self.nodes.get(id).expect("Node not found!")
+ fn get_node<'a>(&'a self, id: &ParseNodeId) -> Ref<'a, Dom<Node>> {
+ Ref::map(self.nodes.borrow(), |nodes| {
+ nodes.get(id).expect("Node not found!")
+ })
}
- fn append_before_sibling(&mut self, sibling: ParseNodeId, node: NodeOrText) {
+ fn append_before_sibling(&self, sibling: ParseNodeId, node: NodeOrText) {
let node = match node {
NodeOrText::Node(n) => {
HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id)))
@@ -373,7 +375,7 @@ impl Tokenizer {
super::insert(parent, Some(sibling), node, self.parsing_algorithm);
}
- fn append(&mut self, parent: ParseNodeId, node: NodeOrText) {
+ fn append(&self, parent: ParseNodeId, node: NodeOrText) {
let node = match node {
NodeOrText::Node(n) => {
HtmlNodeOrText::AppendNode(Dom::from_ref(&**self.get_node(&n.id)))
@@ -398,7 +400,7 @@ impl Tokenizer {
x.is_in_same_home_subtree(y)
}
- fn process_operation(&mut self, op: ParseOperation) {
+ fn process_operation(&self, op: ParseOperation) {
let document = DomRoot::from_ref(&**self.get_node(&0));
let document = document
.downcast::<Document>()
@@ -469,8 +471,8 @@ impl Tokenizer {
.expect("Appending failed");
},
ParseOperation::AddAttrsIfMissing { target, attrs } => {
- let elem = self
- .get_node(&target)
+ let node = self.get_node(&target);
+ let elem = node
.downcast::<Element>()
.expect("tried to set attrs on non-Element in HTML parsing");
for attr in attrs {
@@ -479,11 +481,12 @@ impl Tokenizer {
},
ParseOperation::RemoveFromParent { target } => {
if let Some(ref parent) = self.get_node(&target).GetParentNode() {
- parent.RemoveChild(self.get_node(&target)).unwrap();
+ parent.RemoveChild(&self.get_node(&target)).unwrap();
}
},
ParseOperation::MarkScriptAlreadyStarted { node } => {
- let script = self.get_node(&node).downcast::<HTMLScriptElement>();
+ let node = self.get_node(&node);
+ let script = node.downcast::<HTMLScriptElement>();
if let Some(script) = script {
script.set_already_started(true)
}
@@ -525,7 +528,7 @@ impl Tokenizer {
}
},
ParseOperation::Pop { node } => {
- vtable_for(self.get_node(&node)).pop();
+ vtable_for(&self.get_node(&node)).pop();
},
ParseOperation::CreatePI { node, target, data } => {
let pi = ProcessingInstruction::new(
@@ -555,7 +558,7 @@ fn run(
..Default::default()
};
- let mut html_tokenizer = if fragment_context_is_some {
+ let html_tokenizer = if fragment_context_is_some {
let tb =
TreeBuilder::new_for_fragment(sink, ctxt_parse_node.unwrap(), form_parse_node, options);
@@ -575,8 +578,8 @@ fn run(
.expect("Unexpected channel panic in html parser thread")
{
ToHtmlTokenizerMsg::Feed { input } => {
- let mut input = create_buffer_queue(input);
- let res = html_tokenizer.feed(&mut input);
+ let input = create_buffer_queue(input);
+ let res = html_tokenizer.feed(&input);
// Gather changes to 'input' and place them in 'updated_input',
// which will be sent to the main thread to update feed method's 'input'
@@ -611,8 +614,8 @@ struct ParseNodeData {
}
pub struct Sink {
- current_line: u64,
- parse_node_data: HashMap<ParseNodeId, ParseNodeData>,
+ current_line: Cell<u64>,
+ parse_node_data: RefCell<HashMap<ParseNodeId, ParseNodeData>>,
next_parse_node_id: Cell<ParseNodeId>,
document_node: ParseNode,
sender: Sender<ToTokenizerMsg>,
@@ -620,9 +623,9 @@ pub struct Sink {
impl Sink {
fn new(sender: Sender<ToTokenizerMsg>) -> Sink {
- let mut sink = Sink {
- current_line: 1,
- parse_node_data: HashMap::new(),
+ let sink = Sink {
+ current_line: Cell::new(1),
+ parse_node_data: RefCell::new(HashMap::new()),
next_parse_node_id: Cell::new(1),
document_node: ParseNode {
id: 0,
@@ -635,7 +638,7 @@ impl Sink {
sink
}
- fn new_parse_node(&mut self) -> ParseNode {
+ fn new_parse_node(&self) -> ParseNode {
let id = self.next_parse_node_id.get();
let data = ParseNodeData::default();
self.insert_parse_node_data(id, data);
@@ -652,20 +655,20 @@ impl Sink {
.unwrap();
}
- fn insert_parse_node_data(&mut self, id: ParseNodeId, data: ParseNodeData) {
- assert!(self.parse_node_data.insert(id, data).is_none());
+ fn insert_parse_node_data(&self, id: ParseNodeId, data: ParseNodeData) {
+ assert!(self.parse_node_data.borrow_mut().insert(id, data).is_none());
}
- fn get_parse_node_data<'a>(&'a self, id: &'a ParseNodeId) -> &'a ParseNodeData {
- self.parse_node_data
- .get(id)
- .expect("Parse Node data not found!")
+ fn get_parse_node_data<'a>(&'a self, id: &'a ParseNodeId) -> Ref<'a, ParseNodeData> {
+ Ref::map(self.parse_node_data.borrow(), |data| {
+ data.get(id).expect("Parse Node data not found!")
+ })
}
- fn get_parse_node_data_mut<'a>(&'a mut self, id: &'a ParseNodeId) -> &'a mut ParseNodeData {
- self.parse_node_data
- .get_mut(id)
- .expect("Parse Node data not found!")
+ fn get_parse_node_data_mut<'a>(&'a self, id: &'a ParseNodeId) -> RefMut<'a, ParseNodeData> {
+ RefMut::map(self.parse_node_data.borrow_mut(), |data| {
+ data.get_mut(id).expect("Parse Node data not found!")
+ })
}
}
@@ -678,17 +681,17 @@ impl TreeSink for Sink {
type Handle = ParseNode;
- fn get_document(&mut self) -> Self::Handle {
+ fn get_document(&self) -> Self::Handle {
self.document_node.clone()
}
- fn get_template_contents(&mut self, target: &Self::Handle) -> Self::Handle {
+ fn get_template_contents(&self, target: &Self::Handle) -> Self::Handle {
if let Some(ref contents) = self.get_parse_node_data(&target.id).contents {
return contents.clone();
}
let node = self.new_parse_node();
{
- let data = self.get_parse_node_data_mut(&target.id);
+ let mut data = self.get_parse_node_data_mut(&target.id);
data.contents = Some(node.clone());
}
self.send_op(ParseOperation::GetTemplateContents {
@@ -711,7 +714,7 @@ impl TreeSink for Sink {
}
fn create_element(
- &mut self,
+ &self,
name: QualName,
html_attrs: Vec<HtmlAttribute>,
_flags: ElementFlags,
@@ -719,7 +722,7 @@ impl TreeSink for Sink {
let mut node = self.new_parse_node();
node.qual_name = Some(name.clone());
{
- let node_data = self.get_parse_node_data_mut(&node.id);
+ let mut node_data = self.get_parse_node_data_mut(&node.id);
node_data.is_integration_point = html_attrs.iter().any(|attr| {
let attr_value = &String::from(attr.value.clone());
(attr.name.local == local_name!("encoding") && attr.name.ns == ns!()) &&
@@ -739,12 +742,12 @@ impl TreeSink for Sink {
node: node.id,
name,
attrs,
- current_line: self.current_line,
+ current_line: self.current_line.get(),
});
node
}
- fn create_comment(&mut self, text: StrTendril) -> Self::Handle {
+ fn create_comment(&self, text: StrTendril) -> Self::Handle {
let node = self.new_parse_node();
self.send_op(ParseOperation::CreateComment {
text: String::from(text),
@@ -753,7 +756,7 @@ impl TreeSink for Sink {
node
}
- fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> ParseNode {
+ fn create_pi(&self, target: StrTendril, data: StrTendril) -> ParseNode {
let node = self.new_parse_node();
self.send_op(ParseOperation::CreatePI {
node: node.id,
@@ -764,7 +767,7 @@ impl TreeSink for Sink {
}
fn associate_with_form(
- &mut self,
+ &self,
target: &Self::Handle,
form: &Self::Handle,
nodes: (&Self::Handle, Option<&Self::Handle>),
@@ -779,7 +782,7 @@ impl TreeSink for Sink {
}
fn append_before_sibling(
- &mut self,
+ &self,
sibling: &Self::Handle,
new_node: HtmlNodeOrText<Self::Handle>,
) {
@@ -794,7 +797,7 @@ impl TreeSink for Sink {
}
fn append_based_on_parent_node(
- &mut self,
+ &self,
elem: &Self::Handle,
prev_elem: &Self::Handle,
child: HtmlNodeOrText<Self::Handle>,
@@ -810,11 +813,11 @@ impl TreeSink for Sink {
});
}
- fn parse_error(&mut self, msg: Cow<'static, str>) {
+ fn parse_error(&self, msg: Cow<'static, str>) {
debug!("Parse error: {}", msg);
}
- fn set_quirks_mode(&mut self, mode: QuirksMode) {
+ fn set_quirks_mode(&self, mode: QuirksMode) {
let mode = match mode {
QuirksMode::Quirks => ServoQuirksMode::Quirks,
QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
@@ -823,7 +826,7 @@ impl TreeSink for Sink {
self.send_op(ParseOperation::SetQuirksMode { mode });
}
- fn append(&mut self, parent: &Self::Handle, child: HtmlNodeOrText<Self::Handle>) {
+ fn append(&self, parent: &Self::Handle, child: HtmlNodeOrText<Self::Handle>) {
let child = match child {
HtmlNodeOrText::AppendNode(node) => NodeOrText::Node(node),
HtmlNodeOrText::AppendText(text) => NodeOrText::Text(String::from(text)),
@@ -835,7 +838,7 @@ impl TreeSink for Sink {
}
fn append_doctype_to_document(
- &mut self,
+ &self,
name: StrTendril,
public_id: StrTendril,
system_id: StrTendril,
@@ -847,7 +850,7 @@ impl TreeSink for Sink {
});
}
- fn add_attrs_if_missing(&mut self, target: &Self::Handle, html_attrs: Vec<HtmlAttribute>) {
+ fn add_attrs_if_missing(&self, target: &Self::Handle, html_attrs: Vec<HtmlAttribute>) {
let attrs = html_attrs
.into_iter()
.map(|attr| Attribute {
@@ -861,19 +864,19 @@ impl TreeSink for Sink {
});
}
- fn remove_from_parent(&mut self, target: &Self::Handle) {
+ fn remove_from_parent(&self, target: &Self::Handle) {
self.send_op(ParseOperation::RemoveFromParent { target: target.id });
}
- fn mark_script_already_started(&mut self, node: &Self::Handle) {
+ fn mark_script_already_started(&self, node: &Self::Handle) {
self.send_op(ParseOperation::MarkScriptAlreadyStarted { node: node.id });
}
- fn complete_script(&mut self, _: &Self::Handle) -> NextParserState {
+ fn complete_script(&self, _: &Self::Handle) -> NextParserState {
panic!("complete_script should not be called here!");
}
- fn reparent_children(&mut self, parent: &Self::Handle, new_parent: &Self::Handle) {
+ fn reparent_children(&self, parent: &Self::Handle, new_parent: &Self::Handle) {
self.send_op(ParseOperation::ReparentChildren {
parent: parent.id,
new_parent: new_parent.id,
@@ -887,11 +890,11 @@ impl TreeSink for Sink {
node_data.is_integration_point
}
- fn set_current_line(&mut self, line_number: u64) {
- self.current_line = line_number;
+ fn set_current_line(&self, line_number: u64) {
+ self.current_line.set(line_number);
}
- fn pop(&mut self, node: &Self::Handle) {
+ fn pop(&self, node: &Self::Handle) {
self.send_op(ParseOperation::Pop { node: node.id });
}
}
diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs
index 3066abcbe61..b3184923609 100644
--- a/components/script/dom/servoparser/html.rs
+++ b/components/script/dom/servoparser/html.rs
@@ -4,6 +4,7 @@
#![allow(crown::unrooted_must_root)]
+use std::cell::Cell;
use std::io;
use html5ever::buffer_queue::BufferQueue;
@@ -47,7 +48,7 @@ impl Tokenizer {
let sink = Sink {
base_url: url,
document: Dom::from_ref(document),
- current_line: 1,
+ current_line: Cell::new(1),
script: Default::default(),
parsing_algorithm,
};
@@ -78,7 +79,7 @@ impl Tokenizer {
Tokenizer { inner }
}
- pub fn feed(&mut self, input: &mut BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
+ pub fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
match self.inner.feed(input) {
TokenizerResult::Done => TokenizerResult::Done,
TokenizerResult::Script(script) => {
@@ -87,7 +88,7 @@ impl Tokenizer {
}
}
- pub fn end(&mut self) {
+ pub fn end(&self) {
self.inner.end();
}
@@ -95,7 +96,7 @@ impl Tokenizer {
&self.inner.sink.sink.base_url
}
- pub fn set_plaintext_state(&mut self) {
+ pub fn set_plaintext_state(&self) {
self.inner.set_plaintext_state();
}
}
diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs
index 5323012e979..28806a5df0c 100644
--- a/components/script/dom/servoparser/mod.rs
+++ b/components/script/dom/servoparser/mod.rs
@@ -4,7 +4,6 @@
use std::borrow::Cow;
use std::cell::Cell;
-use std::mem;
use base::id::PipelineId;
use base64::engine::general_purpose;
@@ -102,13 +101,13 @@ pub struct ServoParser {
/// Input received from network.
#[ignore_malloc_size_of = "Defined in html5ever"]
#[no_trace]
- network_input: DomRefCell<BufferQueue>,
+ network_input: BufferQueue,
/// Input received from script. Used only to support document.write().
#[ignore_malloc_size_of = "Defined in html5ever"]
#[no_trace]
- script_input: DomRefCell<BufferQueue>,
+ script_input: BufferQueue,
/// The tokenizer of this parser.
- tokenizer: DomRefCell<Tokenizer>,
+ tokenizer: Tokenizer,
/// Whether to expect any further input from the associated network request.
last_chunk_received: Cell<bool>,
/// Whether this parser should avoid passing any further data to the tokenizer.
@@ -122,10 +121,10 @@ pub struct ServoParser {
/// We do a quick-and-dirty parse of the input looking for resources to prefetch.
// TODO: if we had speculative parsing, we could do this when speculatively
// building the DOM. https://github.com/servo/servo/pull/19203
- prefetch_tokenizer: DomRefCell<prefetch::Tokenizer>,
+ prefetch_tokenizer: prefetch::Tokenizer,
#[ignore_malloc_size_of = "Defined in html5ever"]
#[no_trace]
- prefetch_input: DomRefCell<BufferQueue>,
+ prefetch_input: BufferQueue,
}
pub struct ElementAttribute {
@@ -147,7 +146,7 @@ impl ElementAttribute {
impl ServoParser {
pub fn parser_is_not_active(&self) -> bool {
- self.can_write() || self.tokenizer.try_borrow_mut().is_ok()
+ self.can_write()
}
pub fn parse_html_document(document: &Document, input: Option<DOMString>, url: ServoUrl) {
@@ -302,12 +301,9 @@ impl ServoParser {
assert!(self.suspended.get());
self.suspended.set(false);
- mem::swap(
- &mut *self.script_input.borrow_mut(),
- &mut *self.network_input.borrow_mut(),
- );
- while let Some(chunk) = self.script_input.borrow_mut().pop_front() {
- self.network_input.borrow_mut().push_back(chunk);
+ self.script_input.swap_with(&self.network_input);
+ while let Some(chunk) = self.script_input.pop_front() {
+ self.network_input.push_back(chunk);
}
let script_nesting_level = self.script_nesting_level.get();
@@ -335,9 +331,7 @@ impl ServoParser {
// parser is suspended, we just append everything to the
// script input and abort these steps.
for chunk in text {
- self.script_input
- .borrow_mut()
- .push_back(String::from(chunk).into());
+ self.script_input.push_back(String::from(chunk).into());
}
return;
}
@@ -345,21 +339,21 @@ impl ServoParser {
// There is no pending parsing blocking script, so all previous calls
// to document.write() should have seen their entire input tokenized
// and process, with nothing pushed to the parser script input.
- assert!(self.script_input.borrow().is_empty());
+ assert!(self.script_input.is_empty());
- let mut input = BufferQueue::default();
+ let input = BufferQueue::default();
for chunk in text {
input.push_back(String::from(chunk).into());
}
- self.tokenize(|tokenizer| tokenizer.feed(&mut input));
+ self.tokenize(|tokenizer| tokenizer.feed(&input));
if self.suspended.get() {
// Parser got suspended, insert remaining input at end of
// script input, following anything written by scripts executed
// reentrantly during this call.
while let Some(chunk) = input.pop_front() {
- self.script_input.borrow_mut().push_back(chunk);
+ self.script_input.push_back(chunk);
}
return;
}
@@ -389,15 +383,15 @@ impl ServoParser {
self.aborted.set(true);
// Step 1.
- *self.script_input.borrow_mut() = BufferQueue::default();
- *self.network_input.borrow_mut() = BufferQueue::default();
+ self.script_input.replace_with(BufferQueue::default());
+ self.network_input.replace_with(BufferQueue::default());
// Step 2.
self.document
.set_ready_state(DocumentReadyState::Interactive);
// Step 3.
- self.tokenizer.borrow_mut().end();
+ self.tokenizer.end();
self.document.set_current_parser(None);
// Step 4.
@@ -416,16 +410,16 @@ impl ServoParser {
document: Dom::from_ref(document),
bom_sniff: DomRefCell::new(Some(Vec::with_capacity(3))),
network_decoder: DomRefCell::new(Some(NetworkDecoder::new(document.encoding()))),
- network_input: DomRefCell::new(BufferQueue::default()),
- script_input: DomRefCell::new(BufferQueue::default()),
- tokenizer: DomRefCell::new(tokenizer),
+ network_input: BufferQueue::default(),
+ script_input: BufferQueue::default(),
+ tokenizer,
last_chunk_received: Cell::new(false),
suspended: Default::default(),
script_nesting_level: Default::default(),
aborted: Default::default(),
script_created_parser: kind == ParserKind::ScriptCreated,
- prefetch_tokenizer: DomRefCell::new(prefetch::Tokenizer::new(document)),
- prefetch_input: DomRefCell::new(BufferQueue::default()),
+ prefetch_tokenizer: prefetch::Tokenizer::new(document),
+ prefetch_input: BufferQueue::default(),
}
}
@@ -454,15 +448,12 @@ impl ServoParser {
// to prefetch. If the user script uses `document.write()`
// to overwrite the network input, this prefetching may
// have been wasted, but in most cases it won't.
- let mut prefetch_input = self.prefetch_input.borrow_mut();
- prefetch_input.push_back(chunk.clone());
- self.prefetch_tokenizer
- .borrow_mut()
- .feed(&mut prefetch_input);
+ self.prefetch_input.push_back(chunk.clone());
+ self.prefetch_tokenizer.feed(&self.prefetch_input);
}
// Push the chunk into the network input stream,
// which is tokenized lazily.
- self.network_input.borrow_mut().push_back(chunk);
+ self.network_input.push_back(chunk);
}
fn push_bytes_input_chunk(&self, chunk: Vec<u8>) {
@@ -513,7 +504,7 @@ impl ServoParser {
iframe: TimerMetadataFrameType::RootWindow,
incremental: TimerMetadataReflowType::FirstReflow,
};
- let profiler_category = self.tokenizer.borrow().profiler_category();
+ let profiler_category = self.tokenizer.profiler_category();
profile(
profiler_category,
Some(metadata),
@@ -527,7 +518,7 @@ impl ServoParser {
}
fn do_parse_sync(&self) {
- assert!(self.script_input.borrow().is_empty());
+ assert!(self.script_input.is_empty());
// This parser will continue to parse while there is either pending input or
// the parser remains unsuspended.
@@ -536,17 +527,17 @@ impl ServoParser {
if let Some(decoder) = self.network_decoder.borrow_mut().take() {
let chunk = decoder.finish();
if !chunk.is_empty() {
- self.network_input.borrow_mut().push_back(chunk);
+ self.network_input.push_back(chunk);
}
}
}
- self.tokenize(|tokenizer| tokenizer.feed(&mut self.network_input.borrow_mut()));
+ self.tokenize(|tokenizer| tokenizer.feed(&self.network_input));
if self.suspended.get() {
return;
}
- assert!(self.network_input.borrow().is_empty());
+ assert!(self.network_input.is_empty());
if self.last_chunk_received.get() {
self.finish();
@@ -570,16 +561,16 @@ impl ServoParser {
}
}
- fn tokenize<F>(&self, mut feed: F)
+ fn tokenize<F>(&self, feed: F)
where
- F: FnMut(&mut Tokenizer) -> TokenizerResult<DomRoot<HTMLScriptElement>>,
+ F: Fn(&Tokenizer) -> TokenizerResult<DomRoot<HTMLScriptElement>>,
{
loop {
assert!(!self.suspended.get());
assert!(!self.aborted.get());
self.document.reflow_if_reflow_timer_expired();
- let script = match feed(&mut self.tokenizer.borrow_mut()) {
+ let script = match feed(&self.tokenizer) {
TokenizerResult::Done => return,
TokenizerResult::Script(script) => script,
};
@@ -617,8 +608,8 @@ impl ServoParser {
fn finish(&self) {
assert!(!self.suspended.get());
assert!(self.last_chunk_received.get());
- assert!(self.script_input.borrow().is_empty());
- assert!(self.network_input.borrow().is_empty());
+ assert!(self.script_input.is_empty());
+ assert!(self.network_input.is_empty());
assert!(self.network_decoder.borrow().is_none());
// Step 1.
@@ -626,11 +617,11 @@ impl ServoParser {
.set_ready_state(DocumentReadyState::Interactive);
// Step 2.
- self.tokenizer.borrow_mut().end();
+ self.tokenizer.end();
self.document.set_current_parser(None);
// Steps 3-12 are in another castle, namely finish_load.
- let url = self.tokenizer.borrow().url().clone();
+ let url = self.tokenizer.url().clone();
self.document.finish_load(LoadType::PageSource(url));
}
}
@@ -674,19 +665,19 @@ enum Tokenizer {
}
impl Tokenizer {
- fn feed(&mut self, input: &mut BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
+ fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
match *self {
- Tokenizer::Html(ref mut tokenizer) => tokenizer.feed(input),
- Tokenizer::AsyncHtml(ref mut tokenizer) => tokenizer.feed(input),
- Tokenizer::Xml(ref mut tokenizer) => tokenizer.feed(input),
+ Tokenizer::Html(ref tokenizer) => tokenizer.feed(input),
+ Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.feed(input),
+ Tokenizer::Xml(ref tokenizer) => tokenizer.feed(input),
}
}
- fn end(&mut self) {
+ fn end(&self) {
match *self {
- Tokenizer::Html(ref mut tokenizer) => tokenizer.end(),
- Tokenizer::AsyncHtml(ref mut tokenizer) => tokenizer.end(),
- Tokenizer::Xml(ref mut tokenizer) => tokenizer.end(),
+ Tokenizer::Html(ref tokenizer) => tokenizer.end(),
+ Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.end(),
+ Tokenizer::Xml(ref tokenizer) => tokenizer.end(),
}
}
@@ -698,10 +689,10 @@ impl Tokenizer {
}
}
- fn set_plaintext_state(&mut self) {
+ fn set_plaintext_state(&self) {
match *self {
- Tokenizer::Html(ref mut tokenizer) => tokenizer.set_plaintext_state(),
- Tokenizer::AsyncHtml(ref mut tokenizer) => tokenizer.set_plaintext_state(),
+ Tokenizer::Html(ref tokenizer) => tokenizer.set_plaintext_state(),
+ Tokenizer::AsyncHtml(ref tokenizer) => tokenizer.set_plaintext_state(),
Tokenizer::Xml(_) => unimplemented!(),
}
}
@@ -852,7 +843,7 @@ impl FetchResponseListener for ParserContext {
let page = "<pre>\n".into();
parser.push_string_input_chunk(page);
parser.parse_sync();
- parser.tokenizer.borrow_mut().set_plaintext_state();
+ parser.tokenizer.set_plaintext_state();
},
(mime::TEXT, mime::HTML, _) => match error {
Some(NetworkError::SslValidation(reason, bytes)) => {
@@ -1040,7 +1031,7 @@ pub struct Sink {
#[no_trace]
base_url: ServoUrl,
document: Dom<Document>,
- current_line: u64,
+ current_line: Cell<u64>,
script: MutNullableDom<HTMLScriptElement>,
parsing_algorithm: ParsingAlgorithm,
}
@@ -1068,12 +1059,12 @@ impl TreeSink for Sink {
type Handle = Dom<Node>;
#[allow(crown::unrooted_must_root)]
- fn get_document(&mut self) -> Dom<Node> {
+ fn get_document(&self) -> Dom<Node> {
Dom::from_ref(self.document.upcast())
}
#[allow(crown::unrooted_must_root)]
- fn get_template_contents(&mut self, target: &Dom<Node>) -> Dom<Node> {
+ fn get_template_contents(&self, target: &Dom<Node>) -> Dom<Node> {
let template = target
.downcast::<HTMLTemplateElement>()
.expect("tried to get template contents of non-HTMLTemplateElement in HTML parsing");
@@ -1096,7 +1087,7 @@ impl TreeSink for Sink {
#[allow(crown::unrooted_must_root)]
fn create_element(
- &mut self,
+ &self,
name: QualName,
attrs: Vec<Attribute>,
_flags: ElementFlags,
@@ -1109,20 +1100,20 @@ impl TreeSink for Sink {
name,
attrs,
&self.document,
- ElementCreator::ParserCreated(self.current_line),
+ ElementCreator::ParserCreated(self.current_line.get()),
self.parsing_algorithm,
);
Dom::from_ref(element.upcast())
}
#[allow(crown::unrooted_must_root)]
- fn create_comment(&mut self, text: StrTendril) -> Dom<Node> {
+ fn create_comment(&self, text: StrTendril) -> Dom<Node> {
let comment = Comment::new(DOMString::from(String::from(text)), &self.document, None);
Dom::from_ref(comment.upcast())
}
#[allow(crown::unrooted_must_root)]
- fn create_pi(&mut self, target: StrTendril, data: StrTendril) -> Dom<Node> {
+ fn create_pi(&self, target: StrTendril, data: StrTendril) -> Dom<Node> {
let doc = &*self.document;
let pi = ProcessingInstruction::new(
DOMString::from(String::from(target)),
@@ -1133,7 +1124,7 @@ impl TreeSink for Sink {
}
fn associate_with_form(
- &mut self,
+ &self,
target: &Dom<Node>,
form: &Dom<Node>,
nodes: (&Dom<Node>, Option<&Dom<Node>>),
@@ -1163,7 +1154,7 @@ impl TreeSink for Sink {
}
#[allow(crown::unrooted_must_root)]
- fn append_before_sibling(&mut self, sibling: &Dom<Node>, new_node: NodeOrText<Dom<Node>>) {
+ fn append_before_sibling(&self, sibling: &Dom<Node>, new_node: NodeOrText<Dom<Node>>) {
let parent = sibling
.GetParentNode()
.expect("append_before_sibling called on node without parent");
@@ -1171,11 +1162,11 @@ impl TreeSink for Sink {
insert(&parent, Some(sibling), new_node, self.parsing_algorithm);
}
- fn parse_error(&mut self, msg: Cow<'static, str>) {
+ fn parse_error(&self, msg: Cow<'static, str>) {
debug!("Parse error: {}", msg);
}
- fn set_quirks_mode(&mut self, mode: QuirksMode) {
+ fn set_quirks_mode(&self, mode: QuirksMode) {
let mode = match mode {
QuirksMode::Quirks => ServoQuirksMode::Quirks,
QuirksMode::LimitedQuirks => ServoQuirksMode::LimitedQuirks,
@@ -1185,13 +1176,13 @@ impl TreeSink for Sink {
}
#[allow(crown::unrooted_must_root)]
- fn append(&mut self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
+ fn append(&self, parent: &Dom<Node>, child: NodeOrText<Dom<Node>>) {
insert(parent, None, child, self.parsing_algorithm);
}
#[allow(crown::unrooted_must_root)]
fn append_based_on_parent_node(
- &mut self,
+ &self,
elem: &Dom<Node>,
prev_elem: &Dom<Node>,
child: NodeOrText<Dom<Node>>,
@@ -1204,7 +1195,7 @@ impl TreeSink for Sink {
}
fn append_doctype_to_document(
- &mut self,
+ &self,
name: StrTendril,
public_id: StrTendril,
system_id: StrTendril,
@@ -1221,7 +1212,7 @@ impl TreeSink for Sink {
.expect("Appending failed");
}
- fn add_attrs_if_missing(&mut self, target: &Dom<Node>, attrs: Vec<Attribute>) {
+ fn add_attrs_if_missing(&self, target: &Dom<Node>, attrs: Vec<Attribute>) {
let elem = target
.downcast::<Element>()
.expect("tried to set attrs on non-Element in HTML parsing");
@@ -1234,20 +1225,20 @@ impl TreeSink for Sink {
}
}
- fn remove_from_parent(&mut self, target: &Dom<Node>) {
+ fn remove_from_parent(&self, target: &Dom<Node>) {
if let Some(ref parent) = target.GetParentNode() {
parent.RemoveChild(target).unwrap();
}
}
- fn mark_script_already_started(&mut self, node: &Dom<Node>) {
+ fn mark_script_already_started(&self, node: &Dom<Node>) {
let script = node.downcast::<HTMLScriptElement>();
if let Some(script) = script {
script.set_already_started(true)
}
}
- fn complete_script(&mut self, node: &Dom<Node>) -> NextParserState {
+ fn complete_script(&self, node: &Dom<Node>) -> NextParserState {
if let Some(script) = node.downcast() {
self.script.set(Some(script));
NextParserState::Suspend
@@ -1256,7 +1247,7 @@ impl TreeSink for Sink {
}
}
- fn reparent_children(&mut self, node: &Dom<Node>, new_parent: &Dom<Node>) {
+ fn reparent_children(&self, node: &Dom<Node>, new_parent: &Dom<Node>) {
while let Some(ref child) = node.GetFirstChild() {
new_parent.AppendChild(child).unwrap();
}
@@ -1273,11 +1264,11 @@ impl TreeSink for Sink {
})
}
- fn set_current_line(&mut self, line_number: u64) {
- self.current_line = line_number;
+ fn set_current_line(&self, line_number: u64) {
+ self.current_line.set(line_number);
}
- fn pop(&mut self, node: &Dom<Node>) {
+ fn pop(&self, node: &Dom<Node>) {
let node = DomRoot::from_ref(&**node);
vtable_for(&node).pop();
}
diff --git a/components/script/dom/servoparser/prefetch.rs b/components/script/dom/servoparser/prefetch.rs
index 1f57ccc0a94..a96872590a3 100644
--- a/components/script/dom/servoparser/prefetch.rs
+++ b/components/script/dom/servoparser/prefetch.rs
@@ -2,6 +2,8 @@
* 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 std::cell::{Cell, RefCell};
+
use base::id::PipelineId;
use html5ever::buffer_queue::BufferQueue;
use html5ever::tokenizer::states::RawKind;
@@ -41,7 +43,7 @@ impl Tokenizer {
let sink = PrefetchSink {
origin: document.origin().immutable().clone(),
pipeline_id: document.global().pipeline_id(),
- base_url: None,
+ base_url: RefCell::new(None),
document_url: document.url(),
referrer: document.global().get_referrer(),
referrer_policy: document.get_referrer_policy(),
@@ -49,14 +51,14 @@ impl Tokenizer {
// Initially we set prefetching to false, and only set it
// true after the first script tag, since that is what will
// block the main parser.
- prefetching: false,
+ prefetching: Cell::new(false),
};
let options = Default::default();
let inner = HtmlTokenizer::new(sink, options);
Tokenizer { inner }
}
- pub fn feed(&mut self, input: &mut BufferQueue) {
+ pub fn feed(&self, input: &BufferQueue) {
while let TokenizerResult::Script(PrefetchHandle) = self.inner.feed(input) {}
}
}
@@ -70,14 +72,14 @@ struct PrefetchSink {
#[no_trace]
document_url: ServoUrl,
#[no_trace]
- base_url: Option<ServoUrl>,
+ base_url: RefCell<Option<ServoUrl>>,
#[no_trace]
referrer: Referrer,
#[no_trace]
referrer_policy: Option<ReferrerPolicy>,
#[no_trace]
resource_threads: ResourceThreads,
- prefetching: bool,
+ prefetching: Cell<bool>,
}
/// The prefetch tokenizer produces trivial results
@@ -85,17 +87,13 @@ struct PrefetchHandle;
impl TokenSink for PrefetchSink {
type Handle = PrefetchHandle;
- fn process_token(
- &mut self,
- token: Token,
- _line_number: u64,
- ) -> TokenSinkResult<PrefetchHandle> {
+ fn process_token(&self, token: Token, _line_number: u64) -> TokenSinkResult<PrefetchHandle> {
let tag = match token {
Token::TagToken(ref tag) => tag,
_ => return TokenSinkResult::Continue,
};
match (tag.kind, &tag.name) {
- (TagKind::StartTag, &local_name!("script")) if self.prefetching => {
+ (TagKind::StartTag, &local_name!("script")) if self.prefetching.get() => {
if let Some(url) = self.get_url(tag, local_name!("src")) {
debug!("Prefetch script {}", url);
let cors_setting = self.get_cors_settings(tag, local_name!("crossorigin"));
@@ -123,7 +121,7 @@ impl TokenSink for PrefetchSink {
}
TokenSinkResult::RawData(RawKind::ScriptData)
},
- (TagKind::StartTag, &local_name!("img")) if self.prefetching => {
+ (TagKind::StartTag, &local_name!("img")) if self.prefetching.get() => {
if let Some(url) = self.get_url(tag, local_name!("src")) {
debug!("Prefetch {} {}", tag.name, url);
let request = image_fetch_request(
@@ -141,7 +139,7 @@ impl TokenSink for PrefetchSink {
}
TokenSinkResult::Continue
},
- (TagKind::StartTag, &local_name!("link")) if self.prefetching => {
+ (TagKind::StartTag, &local_name!("link")) if self.prefetching.get() => {
if let Some(rel) = self.get_attr(tag, local_name!("rel")) {
if rel.value.eq_ignore_ascii_case("stylesheet") {
if let Some(url) = self.get_url(tag, local_name!("href")) {
@@ -176,14 +174,14 @@ impl TokenSink for PrefetchSink {
},
(TagKind::EndTag, &local_name!("script")) => {
// After the first script tag, the main parser is blocked, so it's worth prefetching.
- self.prefetching = true;
+ self.prefetching.set(true);
TokenSinkResult::Script(PrefetchHandle)
},
(TagKind::StartTag, &local_name!("base")) => {
if let Some(url) = self.get_url(tag, local_name!("href")) {
- if self.base_url.is_none() {
+ if self.base_url.borrow().is_none() {
debug!("Setting base {}", url);
- self.base_url = Some(url);
+ *self.base_url.borrow_mut() = Some(url);
}
}
TokenSinkResult::Continue
@@ -200,7 +198,8 @@ impl PrefetchSink {
fn get_url(&self, tag: &Tag, name: LocalName) -> Option<ServoUrl> {
let attr = self.get_attr(tag, name)?;
- let base = self.base_url.as_ref().unwrap_or(&self.document_url);
+ let base_url = self.base_url.borrow();
+ let base = base_url.as_ref().unwrap_or(&self.document_url);
ServoUrl::parse_with_base(Some(base), &attr.value).ok()
}
diff --git a/components/script/dom/servoparser/xml.rs b/components/script/dom/servoparser/xml.rs
index 26b43910100..d0d7b153b99 100644
--- a/components/script/dom/servoparser/xml.rs
+++ b/components/script/dom/servoparser/xml.rs
@@ -4,6 +4,8 @@
#![allow(crown::unrooted_must_root)]
+use std::cell::Cell;
+
use html5ever::tokenizer::TokenizerResult;
use js::jsapi::JSTracer;
use servo_url::ServoUrl;
@@ -30,7 +32,7 @@ impl Tokenizer {
let sink = Sink {
base_url: url,
document: Dom::from_ref(document),
- current_line: 1,
+ current_line: Cell::new(1),
script: Default::default(),
parsing_algorithm: ParsingAlgorithm::Normal,
};
@@ -41,7 +43,7 @@ impl Tokenizer {
Tokenizer { inner: tok }
}
- pub fn feed(&mut self, input: &mut BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
+ pub fn feed(&self, input: &BufferQueue) -> TokenizerResult<DomRoot<HTMLScriptElement>> {
self.inner.run(input);
match self.inner.sink.sink.script.take() {
Some(script) => TokenizerResult::Script(script),
@@ -49,7 +51,7 @@ impl Tokenizer {
}
}
- pub fn end(&mut self) {
+ pub fn end(&self) {
self.inner.end()
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index 00f03df0e21..d89c7ebecfe 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -545,9 +545,6 @@ impl Window {
// see note at https://dom.spec.whatwg.org/#concept-event-dispatch step 2
pub fn dispatch_event_with_target_override(&self, event: &Event) -> EventStatus {
- if self.has_document() {
- assert!(self.Document().can_invoke_script());
- }
event.dispatch(self.upcast(), true)
}
}