aboutsummaryrefslogtreecommitdiffstats
path: root/components/script/dom/characterdata.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/script/dom/characterdata.rs')
-rw-r--r--components/script/dom/characterdata.rs174
1 files changed, 112 insertions, 62 deletions
diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs
index be4fc4d0ac1..f8c5acb5a8f 100644
--- a/components/script/dom/characterdata.rs
+++ b/components/script/dom/characterdata.rs
@@ -1,54 +1,59 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
//! DOM bindings for `CharacterData`.
-use dom::bindings::cell::DOMRefCell;
-use dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
-use dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
-use dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId};
-use dom::bindings::codegen::UnionTypes::NodeOrString;
-use dom::bindings::error::{Error, ErrorResult, Fallible};
-use dom::bindings::inheritance::Castable;
-use dom::bindings::js::{LayoutJS, Root};
-use dom::bindings::str::DOMString;
-use dom::comment::Comment;
-use dom::document::Document;
-use dom::element::Element;
-use dom::node::{Node, NodeDamage};
-use dom::processinginstruction::ProcessingInstruction;
-use dom::text::Text;
+use crate::dom::bindings::cell::{DomRefCell, Ref};
+use crate::dom::bindings::codegen::Bindings::CharacterDataBinding::CharacterDataMethods;
+use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
+use crate::dom::bindings::codegen::Bindings::ProcessingInstructionBinding::ProcessingInstructionMethods;
+use crate::dom::bindings::codegen::InheritTypes::{CharacterDataTypeId, NodeTypeId, TextTypeId};
+use crate::dom::bindings::codegen::UnionTypes::NodeOrString;
+use crate::dom::bindings::error::{Error, ErrorResult, Fallible};
+use crate::dom::bindings::inheritance::Castable;
+use crate::dom::bindings::root::{DomRoot, LayoutDom};
+use crate::dom::bindings::str::DOMString;
+use crate::dom::cdatasection::CDATASection;
+use crate::dom::comment::Comment;
+use crate::dom::document::Document;
+use crate::dom::element::Element;
+use crate::dom::mutationobserver::{Mutation, MutationObserver};
+use crate::dom::node::{ChildrenMutation, Node, NodeDamage};
+use crate::dom::processinginstruction::ProcessingInstruction;
+use crate::dom::text::Text;
+use crate::dom::virtualmethods::vtable_for;
use dom_struct::dom_struct;
-use servo_config::opts;
-use std::cell::Ref;
// https://dom.spec.whatwg.org/#characterdata
#[dom_struct]
pub struct CharacterData {
node: Node,
- data: DOMRefCell<DOMString>,
+ data: DomRefCell<DOMString>,
}
impl CharacterData {
pub fn new_inherited(data: DOMString, document: &Document) -> CharacterData {
CharacterData {
node: Node::new_inherited(document),
- data: DOMRefCell::new(data),
+ data: DomRefCell::new(data),
}
}
- pub fn clone_with_data(&self, data: DOMString, document: &Document) -> Root<Node> {
+ pub fn clone_with_data(&self, data: DOMString, document: &Document) -> DomRoot<Node> {
match self.upcast::<Node>().type_id() {
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
- Root::upcast(Comment::new(data, &document))
- }
+ DomRoot::upcast(Comment::new(data, &document))
+ },
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
let pi = self.downcast::<ProcessingInstruction>().unwrap();
- Root::upcast(ProcessingInstruction::new(pi.Target(), data, &document))
+ DomRoot::upcast(ProcessingInstruction::new(pi.Target(), data, &document))
+ },
+ NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::CDATASection)) => {
+ DomRoot::upcast(CDATASection::new(data, &document))
},
- NodeTypeId::CharacterData(CharacterDataTypeId::Text) => {
- Root::upcast(Text::new(data, &document))
+ NodeTypeId::CharacterData(CharacterDataTypeId::Text(TextTypeId::Text)) => {
+ DomRoot::upcast(Text::new(data, &document))
},
_ => unreachable!(),
}
@@ -61,6 +66,7 @@ impl CharacterData {
#[inline]
pub fn append_data(&self, data: &str) {
+ self.queue_mutation_record();
self.data.borrow_mut().push_str(data);
self.content_changed();
}
@@ -68,6 +74,24 @@ impl CharacterData {
fn content_changed(&self) {
let node = self.upcast::<Node>();
node.dirty(NodeDamage::OtherNodeDamage);
+
+ // If this is a Text node, we might need to re-parse (say, if our parent
+ // is a <style> element.) We don't need to if this is a Comment or
+ // ProcessingInstruction.
+ if self.is::<Text>() {
+ if let Some(parent_node) = node.GetParentNode() {
+ let mutation = ChildrenMutation::ChangeText;
+ vtable_for(&parent_node).children_changed(&mutation);
+ }
+ }
+ }
+
+ // Queue a MutationObserver record before changing the content.
+ fn queue_mutation_record(&self) {
+ let mutation = Mutation::CharacterData {
+ old_value: self.data.borrow().clone(),
+ };
+ MutationObserver::queue_a_mutation_record(self.upcast::<Node>(), mutation);
}
}
@@ -79,12 +103,14 @@ impl CharacterDataMethods for CharacterData {
// https://dom.spec.whatwg.org/#dom-characterdata-data
fn SetData(&self, data: DOMString) {
+ self.queue_mutation_record();
let old_length = self.Length();
let new_length = data.encode_utf16().count() as u32;
*self.data.borrow_mut() = data;
self.content_changed();
let node = self.upcast::<Node>();
- node.ranges().replace_code_units(node, 0, old_length, new_length);
+ node.ranges()
+ .replace_code_units(node, 0, old_length, new_length);
}
// https://dom.spec.whatwg.org/#dom-characterdata-length
@@ -94,11 +120,16 @@ impl CharacterDataMethods for CharacterData {
// https://dom.spec.whatwg.org/#dom-characterdata-substringdata
fn SubstringData(&self, offset: u32, count: u32) -> Fallible<DOMString> {
+ let replace_surrogates = self
+ .upcast::<Node>()
+ .owner_doc()
+ .window()
+ .replace_surrogates();
let data = self.data.borrow();
// Step 1.
let mut substring = String::new();
let remaining;
- match split_at_utf16_code_unit_offset(&data, offset) {
+ match split_at_utf16_code_unit_offset(&data, offset, replace_surrogates) {
Ok((_, astral, s)) => {
// As if we had split the UTF-16 surrogate pair in half
// and then transcoded that to UTF-8 lossily,
@@ -107,11 +138,11 @@ impl CharacterDataMethods for CharacterData {
substring = substring + "\u{FFFD}";
}
remaining = s;
- }
+ },
// Step 2.
Err(()) => return Err(Error::IndexSize),
}
- match split_at_utf16_code_unit_offset(remaining, count) {
+ match split_at_utf16_code_unit_offset(remaining, count, replace_surrogates) {
// Steps 3.
Err(()) => substring = substring + remaining,
// Steps 4.
@@ -123,7 +154,7 @@ impl CharacterDataMethods for CharacterData {
if astral.is_some() {
substring = substring + "\u{FFFD}";
}
- }
+ },
};
Ok(DOMString::from(substring))
}
@@ -148,11 +179,16 @@ impl CharacterDataMethods for CharacterData {
fn ReplaceData(&self, offset: u32, count: u32, arg: DOMString) -> ErrorResult {
let mut new_data;
{
+ let replace_surrogates = self
+ .upcast::<Node>()
+ .owner_doc()
+ .window()
+ .replace_surrogates();
let data = self.data.borrow();
let prefix;
let replacement_before;
let remaining;
- match split_at_utf16_code_unit_offset(&data, offset) {
+ match split_at_utf16_code_unit_offset(&data, offset, replace_surrogates) {
Ok((p, astral, r)) => {
prefix = p;
// As if we had split the UTF-16 surrogate pair in half
@@ -160,34 +196,37 @@ impl CharacterDataMethods for CharacterData {
// since our DOMString is currently strict UTF-8.
replacement_before = if astral.is_some() { "\u{FFFD}" } else { "" };
remaining = r;
- }
+ },
// Step 2.
Err(()) => return Err(Error::IndexSize),
};
let replacement_after;
let suffix;
- match split_at_utf16_code_unit_offset(remaining, count) {
+ match split_at_utf16_code_unit_offset(remaining, count, replace_surrogates) {
// Steps 3.
Err(()) => {
replacement_after = "";
suffix = "";
- }
+ },
Ok((_, astral, s)) => {
// As if we had split the UTF-16 surrogate pair in half
// and then transcoded that to UTF-8 lossily,
// since our DOMString is currently strict UTF-8.
replacement_after = if astral.is_some() { "\u{FFFD}" } else { "" };
suffix = s;
- }
+ },
};
// Step 4: Mutation observers.
+ self.queue_mutation_record();
+
// Step 5 to 7.
new_data = String::with_capacity(
prefix.len() +
- replacement_before.len() +
- arg.len() +
- replacement_after.len() +
- suffix.len());
+ replacement_before.len() +
+ arg.len() +
+ replacement_after.len() +
+ suffix.len(),
+ );
new_data.push_str(prefix);
new_data.push_str(replacement_before);
new_data.push_str(&arg);
@@ -198,8 +237,8 @@ impl CharacterDataMethods for CharacterData {
self.content_changed();
// Steps 8-11.
let node = self.upcast::<Node>();
- node.ranges().replace_code_units(
- node, offset, count, arg.encode_utf16().count() as u32);
+ node.ranges()
+ .replace_code_units(node, offset, count, arg.encode_utf16().count() as u32);
Ok(())
}
@@ -225,26 +264,31 @@ impl CharacterDataMethods for CharacterData {
}
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-previouselementsibling
- fn GetPreviousElementSibling(&self) -> Option<Root<Element>> {
- self.upcast::<Node>().preceding_siblings().filter_map(Root::downcast).next()
+ fn GetPreviousElementSibling(&self) -> Option<DomRoot<Element>> {
+ self.upcast::<Node>()
+ .preceding_siblings()
+ .filter_map(DomRoot::downcast)
+ .next()
}
// https://dom.spec.whatwg.org/#dom-nondocumenttypechildnode-nextelementsibling
- fn GetNextElementSibling(&self) -> Option<Root<Element>> {
- self.upcast::<Node>().following_siblings().filter_map(Root::downcast).next()
+ fn GetNextElementSibling(&self) -> Option<DomRoot<Element>> {
+ self.upcast::<Node>()
+ .following_siblings()
+ .filter_map(DomRoot::downcast)
+ .next()
}
}
-#[allow(unsafe_code)]
-pub trait LayoutCharacterDataHelpers {
- unsafe fn data_for_layout(&self) -> &str;
+pub trait LayoutCharacterDataHelpers<'dom> {
+ fn data_for_layout(self) -> &'dom str;
}
-#[allow(unsafe_code)]
-impl LayoutCharacterDataHelpers for LayoutJS<CharacterData> {
+impl<'dom> LayoutCharacterDataHelpers<'dom> for LayoutDom<'dom, CharacterData> {
+ #[allow(unsafe_code)]
#[inline]
- unsafe fn data_for_layout(&self) -> &str {
- &(*self.unsafe_get()).data.borrow_for_layout()
+ fn data_for_layout(self) -> &'dom str {
+ unsafe { self.unsafe_get().data.borrow_for_layout() }
}
}
@@ -268,7 +312,11 @@ impl LayoutCharacterDataHelpers for LayoutJS<CharacterData> {
/// Note that the third variant is only ever returned when the `-Z replace-surrogates`
/// command-line option is specified.
/// When it *would* be returned but the option is *not* specified, this function panics.
-fn split_at_utf16_code_unit_offset(s: &str, offset: u32) -> Result<(&str, Option<char>, &str), ()> {
+fn split_at_utf16_code_unit_offset(
+ s: &str,
+ offset: u32,
+ replace_surrogates: bool,
+) -> Result<(&str, Option<char>, &str), ()> {
let mut code_units = 0;
for (i, c) in s.char_indices() {
if code_units == offset {
@@ -278,15 +326,17 @@ fn split_at_utf16_code_unit_offset(s: &str, offset: u32) -> Result<(&str, Option
code_units += 1;
if c > '\u{FFFF}' {
if code_units == offset {
- if opts::get().replace_surrogates {
- debug_assert!(c.len_utf8() == 4);
- return Ok((&s[..i], Some(c), &s[i + c.len_utf8()..]))
+ if replace_surrogates {
+ debug_assert_eq!(c.len_utf8(), 4);
+ return Ok((&s[..i], Some(c), &s[i + c.len_utf8()..]));
}
- panic!("\n\n\
- Would split a surrogate pair in CharacterData API.\n\
- If you see this in real content, please comment with the URL\n\
- on https://github.com/servo/servo/issues/6873\n\
- \n");
+ panic!(
+ "\n\n\
+ Would split a surrogate pair in CharacterData API.\n\
+ If you see this in real content, please comment with the URL\n\
+ on https://github.com/servo/servo/issues/6873\n\
+ \n"
+ );
}
code_units += 1;
}