Skip to content

Commit

Permalink
Add a fast path in Element::SetInnerHTML when the value is small and …
Browse files Browse the repository at this point in the history
…trivial text

Inspired from gecko which has a similar fast path. This makes innerHTML
more than 10 times faster for this case.

Fixes #25892
  • Loading branch information
Eijebong committed May 4, 2020
1 parent d08c4ff commit 1b2464b
Show file tree
Hide file tree
Showing 13 changed files with 89 additions and 24 deletions.
19 changes: 17 additions & 2 deletions components/script/dom/element.rs
Expand Up @@ -2449,15 +2449,30 @@ impl ElementMethods for Element {

/// <https://w3c.github.io/DOM-Parsing/#widl-Element-innerHTML>
fn SetInnerHTML(&self, value: DOMString) -> ErrorResult {
// Step 1.
let frag = self.parse_fragment(value)?;
// Step 2.
// https://github.com/w3c/DOM-Parsing/issues/1
let target = if let Some(template) = self.downcast::<HTMLTemplateElement>() {
DomRoot::upcast(template.Content())
} else {
DomRoot::from_ref(self.upcast())
};

// Fast path for when the value is small, doesn't contain any markup and doesn't require
// extra work to set innerHTML.
if !self.node.has_weird_parser_insertion_mode() &&
value.len() < 100 &&
!value
.as_bytes()
.iter()
.any(|c| matches!(*c, b'&' | b'\0' | b'<' | b'\r'))
{
Node::SetTextContent(&target, Some(value));
return Ok(());
}

// Step 1.
let frag = self.parse_fragment(value)?;

Node::replace_all(Some(frag.upcast()), &target);
Ok(())
}
Expand Down
7 changes: 5 additions & 2 deletions components/script/dom/htmlframesetelement.rs
Expand Up @@ -4,6 +4,7 @@

use crate::dom::bindings::codegen::Bindings::HTMLFrameSetElementBinding::HTMLFrameSetElementMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::document::Document;
use crate::dom::htmlelement::HTMLElement;
Expand Down Expand Up @@ -33,12 +34,14 @@ impl HTMLFrameSetElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLFrameSetElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLFrameSetElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);
n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}

Expand Down
7 changes: 5 additions & 2 deletions components/script/dom/htmlheadelement.rs
Expand Up @@ -37,10 +37,13 @@ impl HTMLHeadElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLHeadElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLHeadElement::new_inherited(local_name, prefix, document)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}

/// <https://html.spec.whatwg.org/multipage/#meta-referrer>
Expand Down
8 changes: 6 additions & 2 deletions components/script/dom/htmlhtmlelement.rs
Expand Up @@ -2,6 +2,7 @@
* 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 crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::document::Document;
use crate::dom::htmlelement::HTMLElement;
Expand Down Expand Up @@ -32,9 +33,12 @@ impl HTMLHtmlElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLHtmlElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLHtmlElement::new_inherited(localName, prefix, document)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}
7 changes: 5 additions & 2 deletions components/script/dom/htmlselectelement.rs
Expand Up @@ -93,12 +93,15 @@ impl HTMLSelectElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLSelectElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLSelectElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}

// https://html.spec.whatwg.org/multipage/#concept-select-option-list
Expand Down
8 changes: 6 additions & 2 deletions components/script/dom/htmltablecaptionelement.rs
Expand Up @@ -2,6 +2,7 @@
* 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 crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::document::Document;
use crate::dom::htmlelement::HTMLElement;
Expand Down Expand Up @@ -31,11 +32,14 @@ impl HTMLTableCaptionElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTableCaptionElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTableCaptionElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}
7 changes: 5 additions & 2 deletions components/script/dom/htmltablecellelement.rs
Expand Up @@ -45,12 +45,15 @@ impl HTMLTableCellElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTableCellElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTableCellElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}

Expand Down
8 changes: 6 additions & 2 deletions components/script/dom/htmltablecolelement.rs
Expand Up @@ -2,6 +2,7 @@
* 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 crate::dom::bindings::inheritance::Castable;
use crate::dom::bindings::root::DomRoot;
use crate::dom::document::Document;
use crate::dom::htmlelement::HTMLElement;
Expand Down Expand Up @@ -31,11 +32,14 @@ impl HTMLTableColElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTableColElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTableColElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}
7 changes: 5 additions & 2 deletions components/script/dom/htmltableelement.rs
Expand Up @@ -70,12 +70,15 @@ impl HTMLTableElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTableElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTableElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}

pub fn get_border(&self) -> Option<u32> {
Expand Down
7 changes: 5 additions & 2 deletions components/script/dom/htmltablerowelement.rs
Expand Up @@ -57,12 +57,15 @@ impl HTMLTableRowElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTableRowElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTableRowElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}

/// Determine the index for this `HTMLTableRowElement` within the given
Expand Down
7 changes: 5 additions & 2 deletions components/script/dom/htmltablesectionelement.rs
Expand Up @@ -42,12 +42,15 @@ impl HTMLTableSectionElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTableSectionElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTableSectionElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}

Expand Down
7 changes: 5 additions & 2 deletions components/script/dom/htmltemplateelement.rs
Expand Up @@ -41,12 +41,15 @@ impl HTMLTemplateElement {
prefix: Option<Prefix>,
document: &Document,
) -> DomRoot<HTMLTemplateElement> {
Node::reflect_node(
let n = Node::reflect_node(
Box::new(HTMLTemplateElement::new_inherited(
local_name, prefix, document,
)),
document,
)
);

n.upcast::<Node>().set_weird_parser_insertion_mode();
n
}
}

Expand Down
14 changes: 14 additions & 0 deletions components/script/dom/node.rs
Expand Up @@ -196,6 +196,10 @@ bitflags! {

/// Specifies whether this node's shadow-including root is a document.
const IS_CONNECTED = 1 << 10;

/// Whether this node has a weird parser insertion mode. i.e whether setting innerHTML
/// needs extra work or not
const HAS_WEIRD_PARSER_INSERTION_MODE = 1 << 11;
}
}

Expand Down Expand Up @@ -554,6 +558,16 @@ impl Node {
self.flags.get().contains(NodeFlags::IS_IN_SHADOW_TREE)
}

pub fn has_weird_parser_insertion_mode(&self) -> bool {
self.flags
.get()
.contains(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE)
}

pub fn set_weird_parser_insertion_mode(&self) {
self.set_flag(NodeFlags::HAS_WEIRD_PARSER_INSERTION_MODE, true)
}

pub fn is_connected(&self) -> bool {
self.flags.get().contains(NodeFlags::IS_CONNECTED)
}
Expand Down

0 comments on commit 1b2464b

Please sign in to comment.