Script: Change the rest of script to not rely on Deref<str> for DOMString (#39481)

This is part of the future work of implementing LazyDOMString as
outlined in issue #39479.

We use str() method or direct implementations on DOMString for these
methods. We also change some types.
This is independent of https://github.com/servo/servo/pull/39480

Signed-off-by: Narfinger Narfinger@users.noreply.github.com

Testing: This is essentially just renaming a method and a type and
should not change functionality.

Signed-off-by: Narfinger <Narfinger@users.noreply.github.com>
This commit is contained in:
Narfinger 2025-09-25 14:27:42 +02:00 committed by GitHub
parent 9713bb9e1b
commit 1e471b9b41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 219 additions and 132 deletions

View file

@ -507,7 +507,7 @@ impl Extractable for Vec<u8> {
impl Extractable for Blob {
fn extract(&self, _global: &GlobalScope, can_gc: CanGc) -> Fallible<ExtractedBody> {
let blob_type = self.Type();
let content_type = if blob_type.as_ref().is_empty() {
let content_type = if blob_type.is_empty() {
None
} else {
Some(blob_type)

View file

@ -91,7 +91,7 @@ pub(crate) fn is_valid_element_local_name(name: &str) -> bool {
}
/// <https://dom.spec.whatwg.org/#valid-doctype-name>
pub(crate) fn is_valid_doctype_name(name: &str) -> bool {
pub(crate) fn is_valid_doctype_name(name: &DOMString) -> bool {
// A string is a valid doctype name if it does not contain
// ASCII whitespace, U+0000 NULL, or U+003E (>).
!name
@ -121,7 +121,7 @@ pub(crate) enum Context {
/// <https://dom.spec.whatwg.org/#validate-and-extract>
pub(crate) fn validate_and_extract(
namespace: Option<DOMString>,
qualified_name: &str,
qualified_name: &DOMString,
context: Context,
) -> Fallible<(Namespace, Option<Prefix>, LocalName)> {
// Step 1. If namespace is the empty string, then set it to null.
@ -130,12 +130,12 @@ pub(crate) fn validate_and_extract(
// Step 2. Let prefix be null.
let mut prefix = None;
// Step 3. Let localName be qualifiedName.
let mut local_name = qualified_name;
let mut local_name = qualified_name.str();
// Step 4. If qualifiedName contains a U+003A (:):
if let Some(idx) = qualified_name.find(':') {
// Step 4.1. Let splitResult be the result of running
// strictly split given qualifiedName and U+003A (:).
let p = &qualified_name[..idx];
let p = &qualified_name.str()[..idx];
// Step 5. If prefix is not a valid namespace prefix,
// then throw an "InvalidCharacterError" DOMException.
@ -148,7 +148,7 @@ pub(crate) fn validate_and_extract(
prefix = Some(p);
// Step 4.3. Set localName to splitResult[1].
let remaining = &qualified_name[(idx + 1).min(qualified_name.len())..];
let remaining = &qualified_name.str()[(idx + 1).min(qualified_name.len())..];
match remaining.find(':') {
Some(end) => local_name = &remaining[..end],
None => local_name = remaining,

View file

@ -176,7 +176,7 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
},
};
let type_string = normalize_type_string(blobPropertyBag.type_.as_ref());
let type_string = normalize_type_string(blobPropertyBag.type_.str());
let blob_impl = BlobImpl::new_from_bytes(bytes, type_string);
Ok(Blob::new_with_proto(global, proto, blob_impl, can_gc))
@ -206,7 +206,7 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
can_gc: CanGc,
) -> DomRoot<Blob> {
let global = self.global();
let type_string = normalize_type_string(&content_type.unwrap_or_default());
let type_string = normalize_type_string(content_type.unwrap_or_default().str());
// If our parent is already a sliced blob then we reference the data from the grandparent instead,
// to keep the blob ancestry chain short.

View file

@ -136,7 +136,7 @@ impl CharacterDataMethods<crate::DomTypeHolder> for CharacterData {
let data = self.data.borrow();
// Step 1.
let mut substring = String::new();
let remaining = match split_at_utf16_code_unit_offset(&data, offset) {
let remaining = match split_at_utf16_code_unit_offset(data.str(), offset) {
Ok((_, astral, s)) => {
// As if we had split the UTF-16 surrogate pair in half
// and then transcoded that to UTF-8 lossily,
@ -169,7 +169,7 @@ impl CharacterDataMethods<crate::DomTypeHolder> for CharacterData {
// https://dom.spec.whatwg.org/#dom-characterdata-appenddatadata
fn AppendData(&self, data: DOMString) {
// FIXME(ajeffrey): Efficient append on DOMStrings?
self.append_data(&data);
self.append_data(data.str());
}
// https://dom.spec.whatwg.org/#dom-characterdata-insertdataoffset-data
@ -190,7 +190,7 @@ impl CharacterDataMethods<crate::DomTypeHolder> for CharacterData {
let prefix;
let replacement_before;
let remaining;
match split_at_utf16_code_unit_offset(&data, offset) {
match split_at_utf16_code_unit_offset(data.str(), offset) {
Ok((p, astral, r)) => {
prefix = p;
// As if we had split the UTF-16 surrogate pair in half
@ -231,7 +231,7 @@ impl CharacterDataMethods<crate::DomTypeHolder> for CharacterData {
);
new_data.push_str(prefix);
new_data.push_str(replacement_before);
new_data.push_str(&arg);
new_data.push_str(arg.str());
new_data.push_str(replacement_after);
new_data.push_str(suffix);
}
@ -290,7 +290,7 @@ impl<'dom> LayoutCharacterDataHelpers<'dom> for LayoutDom<'dom, CharacterData> {
#[allow(unsafe_code)]
#[inline]
fn data_for_layout(self) -> &'dom str {
unsafe { self.unsafe_get().data.borrow_for_layout() }
unsafe { self.unsafe_get().data.borrow_for_layout().str() }
}
}

View file

@ -160,7 +160,7 @@ impl ClipboardItemMethods<crate::DomTypeHolder> for ClipboardItem {
// Step 6.3 If key starts with `"web "` prefix, then
// Step 6.3.1 Remove `"web "` prefix and assign the remaining string to key.
let (key, is_custom) = match key.strip_prefix(CUSTOM_FORMAT_PREFIX) {
let (key, is_custom) = match key.str().strip_prefix(CUSTOM_FORMAT_PREFIX) {
None => (key.str(), false),
// Step 6.3.2 Set isCustom true
Some(stripped) => (stripped, true),

View file

@ -77,7 +77,7 @@ impl CompositionEvent {
ev
}
pub(crate) fn data(&self) -> &str {
pub(crate) fn data(&self) -> &DOMString {
&self.data
}
}

View file

@ -419,7 +419,7 @@ impl consoleMethods<crate::DomTypeHolder> for Console {
// https://console.spec.whatwg.org/#timelog
fn TimeLog(_cx: JSContext, global: &GlobalScope, label: DOMString, data: Vec<HandleValue>) {
if let Ok(delta) = global.time_log(&label) {
if let Ok(delta) = global.time_log(label.str()) {
let message = format!("{label}: {delta}ms {}", stringify_handle_values(&data));
Console::send_string_message(global, LogLevel::Log, message.clone());
@ -428,7 +428,7 @@ impl consoleMethods<crate::DomTypeHolder> for Console {
// https://console.spec.whatwg.org/#timeend
fn TimeEnd(global: &GlobalScope, label: DOMString) {
if let Ok(delta) = global.time_end(&label) {
if let Ok(delta) = global.time_end(label.str()) {
let message = format!("{label}: {delta}ms");
Console::send_string_message(global, LogLevel::Log, message.clone());

View file

@ -31,16 +31,16 @@ impl CSSMethods<crate::DomTypeHolder> for CSS {
/// <https://drafts.csswg.org/cssom/#the-css.escape()-method>
fn Escape(_: &Window, ident: DOMString) -> Fallible<DOMString> {
let mut escaped = String::new();
serialize_identifier(&ident, &mut escaped).unwrap();
serialize_identifier(ident.str(), &mut escaped).unwrap();
Ok(DOMString::from(escaped))
}
/// <https://drafts.csswg.org/css-conditional/#dom-css-supports>
fn Supports(win: &Window, property: DOMString, value: DOMString) -> bool {
let mut decl = String::new();
serialize_identifier(&property, &mut decl).unwrap();
serialize_identifier(property.str(), &mut decl).unwrap();
decl.push_str(": ");
decl.push_str(&value);
decl.push_str(value.str());
let decl = Declaration(decl);
let url_data = UrlExtraData(win.Document().url().get_arc());
let context = ParserContext::new(
@ -58,7 +58,7 @@ impl CSSMethods<crate::DomTypeHolder> for CSS {
/// <https://drafts.csswg.org/css-conditional/#dom-css-supports>
fn Supports_(win: &Window, condition: DOMString) -> bool {
let mut input = ParserInput::new(&condition);
let mut input = ParserInput::new(condition.str());
let mut input = Parser::new(&mut input);
let cond = match parse_condition_or_declaration(&mut input) {
Ok(c) => c,

View file

@ -76,8 +76,8 @@ impl CSSKeyframesRule {
}
/// Given a keyframe selector, finds the index of the first corresponding rule if any
fn find_rule(&self, selector: &str) -> Option<usize> {
let mut input = ParserInput::new(selector);
fn find_rule(&self, selector: &DOMString) -> Option<usize> {
let mut input = ParserInput::new(selector.str());
let mut input = Parser::new(&mut input);
if let Ok(sel) = KeyframeSelector::parse(&mut input) {
let guard = self.cssrule.shared_lock().read();
@ -117,7 +117,7 @@ impl CSSKeyframesRuleMethods<crate::DomTypeHolder> for CSSKeyframesRule {
fn AppendRule(&self, rule: DOMString, can_gc: CanGc) {
let style_stylesheet = self.cssrule.parent_stylesheet().style_stylesheet();
let rule = Keyframe::parse(
&rule,
rule.str(),
&style_stylesheet.contents,
&style_stylesheet.shared_lock,
);
@ -161,7 +161,7 @@ impl CSSKeyframesRuleMethods<crate::DomTypeHolder> for CSSKeyframesRule {
// Setting this property to a CSS-wide keyword or `none` does not throw,
// it stores a value that serializes as a quoted string.
self.cssrule.parent_stylesheet().will_modify();
let name = KeyframesName::from_ident(&value);
let name = KeyframesName::from_ident(value.str());
let mut guard = self.cssrule.shared_lock().write();
self.keyframesrule.borrow().write_with(&mut guard).name = name;
self.cssrule.parent_stylesheet().notify_invalidations();

View file

@ -9,6 +9,7 @@ use std::cell::RefCell;
use dom_struct::dom_struct;
use itertools::izip;
use script_bindings::inheritance::Castable;
use script_bindings::str::DOMString;
use servo_arc::Arc;
use style::shared_lock::{Locked, SharedRwLockReadGuard};
use style::stylesheets::{
@ -105,7 +106,7 @@ impl CSSRuleList {
/// for keyframes-backed rules.
pub(crate) fn insert_rule(
&self,
rule: &str,
rule: &DOMString,
idx: u32,
containing_rule_types: CssRuleTypes,
parse_relative_rule_type: Option<CssRuleType>,
@ -138,7 +139,7 @@ impl CSSRuleList {
let new_rule = css_rules
.insert_rule(
&parent_stylesheet.shared_lock,
rule,
rule.str(),
&parent_stylesheet.contents,
index,
containing_rule_types,

View file

@ -356,7 +356,7 @@ impl CSSStyleDeclaration {
id
},
PotentiallyParsedPropertyId::NotParsed(unparsed) => {
match PropertyId::parse_enabled_for_all_content(&unparsed) {
match PropertyId::parse_enabled_for_all_content(unparsed.str()) {
Ok(id) => id,
Err(..) => return Ok(()),
}
@ -374,7 +374,7 @@ impl CSSStyleDeclaration {
// Step 4. If priority is not the empty string and is not an ASCII case-insensitive
// match for the string "important", then return.
let importance = match &*priority {
let importance = match priority.str() {
"" => Importance::Normal,
p if p.eq_ignore_ascii_case("important") => Importance::Important,
_ => {
@ -390,7 +390,7 @@ impl CSSStyleDeclaration {
let result = parse_one_declaration_into(
&mut declarations,
id,
&value,
value.str(),
Origin::Author,
&UrlExtraData(self.owner.base_url().get_arc()),
window.css_error_reporter(),
@ -481,7 +481,7 @@ impl CSSStyleDeclarationMethods<crate::DomTypeHolder> for CSSStyleDeclaration {
// https://dev.w3.org/csswg/cssom/#dom-cssstyledeclaration-getpropertyvalue
fn GetPropertyValue(&self, property: DOMString) -> DOMString {
let id = match PropertyId::parse_enabled_for_all_content(&property) {
let id = match PropertyId::parse_enabled_for_all_content(property.str()) {
Ok(id) => id,
Err(..) => return DOMString::new(),
};
@ -494,7 +494,7 @@ impl CSSStyleDeclarationMethods<crate::DomTypeHolder> for CSSStyleDeclaration {
// Readonly style declarations are used for getComputedStyle.
return DOMString::new();
}
let id = match PropertyId::parse_enabled_for_all_content(&property) {
let id = match PropertyId::parse_enabled_for_all_content(property.str()) {
Ok(id) => id,
Err(..) => return DOMString::new(),
};
@ -532,7 +532,7 @@ impl CSSStyleDeclarationMethods<crate::DomTypeHolder> for CSSStyleDeclaration {
return Err(Error::NoModificationAllowed);
}
let id = match PropertyId::parse_enabled_for_all_content(&property) {
let id = match PropertyId::parse_enabled_for_all_content(property.str()) {
Ok(id) => id,
Err(..) => return Ok(DOMString::new()),
};
@ -609,7 +609,7 @@ impl CSSStyleDeclarationMethods<crate::DomTypeHolder> for CSSStyleDeclaration {
|pdb, _changed| {
// Step 3
*pdb = parse_style_attribute(
&value,
value.str(),
&UrlExtraData(self.owner.base_url().get_arc()),
window.css_error_reporter(),
quirks_mode,

View file

@ -151,7 +151,7 @@ impl CSSStyleRuleMethods<crate::DomTypeHolder> for CSSStyleRule {
url_data: &url_data,
for_supports_rule: false,
};
let mut css_parser = CssParserInput::new(&value);
let mut css_parser = CssParserInput::new(value.str());
let mut css_parser = CssParser::new(&mut css_parser);
// TODO: Maybe allow setting relative selectors from the OM, if we're in a nested style
// rule?

View file

@ -294,7 +294,7 @@ impl CSSStyleSheetMethods<crate::DomTypeHolder> for CSSStyleSheet {
let media = Arc::new(shared_lock.wrap(match &options.media {
Some(media) => match media {
MediaListOrString::MediaList(media_list) => media_list.clone_media_list(),
MediaListOrString::String(str) => MediaList::parse_media_list(str, window),
MediaListOrString::String(str) => MediaList::parse_media_list(str.str(), window),
},
None => StyleMediaList::empty(),
}));

View file

@ -345,7 +345,7 @@ impl CustomElementRegistryMethods<crate::DomTypeHolder> for CustomElementRegistr
) -> ErrorResult {
let cx = GlobalScope::get_cx();
rooted!(in(*cx) let constructor = constructor_.callback());
let name = LocalName::from(&*name);
let name = LocalName::from(name);
// Step 1. If IsConstructor(constructor) is false, then throw a TypeError.
// We must unwrap the constructor as all wrappers are constructable if they are callable.
@ -392,19 +392,19 @@ impl CustomElementRegistryMethods<crate::DomTypeHolder> for CustomElementRegistr
// TODO Step 7.1 If this's is scoped is true, then throw a "NotSupportedError" DOMException.
// Step 7.2 If extends is a valid custom element name, then throw a "NotSupportedError" DOMException.
if is_valid_custom_element_name(extended_name) {
if is_valid_custom_element_name(extended_name.str()) {
return Err(Error::NotSupported);
}
// Step 7.3 If the element interface for extends and the HTML namespace is HTMLUnknownElement
// (e.g., if extends does not indicate an element definition in this specification)
// then throw a "NotSupportedError" DOMException.
if !is_extendable_element_interface(extended_name) {
if !is_extendable_element_interface(extended_name.str()) {
return Err(Error::NotSupported);
}
// Step 7.4 Set localName to extends.
LocalName::from(&**extended_name)
LocalName::from(extended_name.str())
} else {
// Step 5. Let localName be name.
name.clone()
@ -556,7 +556,7 @@ impl CustomElementRegistryMethods<crate::DomTypeHolder> for CustomElementRegistr
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-get>
fn Get(&self, cx: JSContext, name: DOMString, mut retval: MutableHandleValue) {
match self.definitions.borrow().get(&LocalName::from(&*name)) {
match self.definitions.borrow().get(&LocalName::from(name)) {
Some(definition) => definition.constructor.safe_to_jsval(cx, retval),
None => retval.set(UndefinedValue()),
}
@ -574,7 +574,7 @@ impl CustomElementRegistryMethods<crate::DomTypeHolder> for CustomElementRegistr
/// <https://html.spec.whatwg.org/multipage/#dom-customelementregistry-whendefined>
fn WhenDefined(&self, name: DOMString, comp: InRealm, can_gc: CanGc) -> Rc<Promise> {
let name = LocalName::from(&*name);
let name = LocalName::from(name);
// Step 1
if !is_valid_custom_element_name(&name) {
@ -1291,7 +1291,6 @@ impl ElementQueue {
pub(crate) fn is_valid_custom_element_name(name: &str) -> bool {
// Custom elment names must match:
// PotentialCustomElementName ::= [a-z] (PCENChar)* '-' (PCENChar)*
let mut chars = name.chars();
if !chars.next().is_some_and(|c| c.is_ascii_lowercase()) {
return false;

View file

@ -112,7 +112,7 @@ impl DataTransferMethods<crate::DomTypeHolder> for DataTransfer {
/// <https://html.spec.whatwg.org/multipage/#dom-datatransfer-dropeffect>
fn SetDropEffect(&self, value: DOMString) {
if VALID_DROP_EFFECTS.contains(&value.as_ref()) {
if VALID_DROP_EFFECTS.contains(&value.str()) {
*self.drop_effect.borrow_mut() = value;
}
}
@ -129,7 +129,7 @@ impl DataTransferMethods<crate::DomTypeHolder> for DataTransfer {
.borrow()
.as_ref()
.is_some_and(|data_store| data_store.mode() == Mode::ReadWrite) &&
VALID_EFFECTS_ALLOWED.contains(&value.as_ref())
VALID_EFFECTS_ALLOWED.contains(&value.str())
{
*self.drop_effect.borrow_mut() = value;
}
@ -187,7 +187,7 @@ impl DataTransferMethods<crate::DomTypeHolder> for DataTransfer {
// Step 4 Let convert-to-URL be false.
let mut convert_to_url = false;
let type_ = match format.as_ref() {
let type_ = match format.str() {
// Step 5 If format equals "text", change it to "text/plain".
"text" => DOMString::from("text/plain"),
// Step 6 If format equals "url", change it to "text/uri-list" and set convert-to-URL to true.

View file

@ -3108,7 +3108,7 @@ impl Document {
&format!("{} {}", containing_class, field),
can_gc,
)?
.as_ref()
.str()
.to_owned();
}
// Step 5: If lineFeed is true, append U+000A LINE FEED to string.
@ -3219,7 +3219,7 @@ impl<'dom> LayoutDocumentHelpers<'dom> for LayoutDom<'dom, Document> {
// The spec says to return a bool, we actually return an Option<Host> containing
// the parsed host in the successful case, to avoid having to re-parse the host.
fn get_registrable_domain_suffix_of_or_is_equal_to(
host_suffix_string: &str,
host_suffix_string: &DOMString,
original_host: Host,
) -> Option<Host> {
// Step 1
@ -3228,7 +3228,7 @@ fn get_registrable_domain_suffix_of_or_is_equal_to(
}
// Step 2-3.
let host = match Host::parse(host_suffix_string) {
let host = match Host::parse(host_suffix_string.str()) {
Ok(host) => host,
Err(_) => return None,
};
@ -3684,7 +3684,7 @@ impl Document {
if element.namespace() != &ns!(html) {
return false;
}
element.get_name().is_some_and(|n| *n == **name)
element.get_name().is_some_and(|n| *n == *name)
}
fn count_node_list<F: Fn(&Node) -> bool>(&self, callback: F) -> u32 {
@ -4669,7 +4669,7 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
qualified_name: DOMString,
can_gc: CanGc,
) -> DomRoot<HTMLCollection> {
let qualified_name = LocalName::from(&*qualified_name);
let qualified_name = LocalName::from(qualified_name.str());
if let Some(entry) = self.tag_map.borrow_mut().get(&qualified_name) {
return DomRoot::from_ref(entry);
}
@ -4708,7 +4708,9 @@ impl DocumentMethods<crate::DomTypeHolder> for Document {
// https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname
fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot<HTMLCollection> {
let class_atoms: Vec<Atom> = split_html_space_chars(&classes).map(Atom::from).collect();
let class_atoms: Vec<Atom> = split_html_space_chars(classes.str())
.map(Atom::from)
.collect();
if let Some(collection) = self.classes_map.borrow().get(&class_atoms) {
return DomRoot::from_ref(collection);
}

View file

@ -61,7 +61,7 @@ pub(crate) enum DOMErrorName {
impl DOMErrorName {
pub(crate) fn from(s: &DOMString) -> Option<DOMErrorName> {
match s.as_ref() {
match s.str() {
"IndexSizeError" => Some(DOMErrorName::IndexSizeError),
"HierarchyRequestError" => Some(DOMErrorName::HierarchyRequestError),
"WrongDocumentError" => Some(DOMErrorName::WrongDocumentError),

View file

@ -192,7 +192,7 @@ impl DOMTokenListMethods<crate::DomTypeHolder> for DOMTokenList {
// Step 1.
return Err(Error::Syntax(None));
}
if token.contains(HTML_SPACE_CHARACTERS) || new_token.contains(HTML_SPACE_CHARACTERS) {
if token.contains_html_space_characters() || new_token.contains_html_space_characters() {
// Step 2.
return Err(Error::InvalidCharacter);
}

View file

@ -303,23 +303,23 @@ pub(crate) fn serialize_html_fragment<S: Serializer>(
SerializationCommand::SerializeNonelement(n) => match n.type_id() {
NodeTypeId::DocumentType => {
let doctype = n.downcast::<DocumentType>().unwrap();
serializer.write_doctype(doctype.name())?;
serializer.write_doctype(doctype.name().str())?;
},
NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => {
let cdata = n.downcast::<CharacterData>().unwrap();
serializer.write_text(&cdata.data())?;
serializer.write_text(cdata.data().str())?;
},
NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => {
let cdata = n.downcast::<CharacterData>().unwrap();
serializer.write_comment(&cdata.data())?;
serializer.write_comment(cdata.data().str())?;
},
NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => {
let pi = n.downcast::<ProcessingInstruction>().unwrap();
let data = pi.upcast::<CharacterData>().data();
serializer.write_processing_instruction(pi.target(), &data)?;
serializer.write_processing_instruction(pi.target().str(), data.str())?;
},
NodeTypeId::DocumentFragment(_) | NodeTypeId::Attr => {},

View file

@ -1684,7 +1684,7 @@ fn create_element_for_token(
let is = attrs
.iter()
.find(|attr| attr.name.local.eq_str_ignore_ascii_case("is"))
.map(|attr| LocalName::from(&*attr.value));
.map(|attr| LocalName::from(attr.value.str()));
// Step 4.
let definition = document.lookup_custom_element_definition(&name.ns, &name.local, is.as_ref());

View file

@ -90,8 +90,8 @@ impl StylePropertyMapReadOnlyMethods<crate::DomTypeHolder> for StylePropertyMapR
// https://drafts.css-houdini.org/css-typed-om-1/#dom-stylepropertymap-getproperties
// requires this sort order
result.sort_by(|key1, key2| {
if let Ok(key1) = custom_properties::parse_name(key1) {
if let Ok(key2) = custom_properties::parse_name(key2) {
if let Ok(key1) = custom_properties::parse_name(key1.str()) {
if let Ok(key2) = custom_properties::parse_name(key2.str()) {
key1.cmp(key2)
} else {
Ordering::Greater

View file

@ -882,14 +882,14 @@ impl TestBindingMethods<crate::DomTypeHolder> for TestBinding {
fn PassVariadicObject(&self, _: SafeJSContext, _: Vec<*mut JSObject>) {}
fn BooleanMozPreference(&self, pref_name: DOMString) -> bool {
prefs::get()
.get_value(pref_name.as_ref())
.get_value(pref_name.str())
.try_into()
.unwrap_or(false)
}
fn StringMozPreference(&self, pref_name: DOMString) -> DOMString {
DOMString::from_string(
prefs::get()
.get_value(pref_name.as_ref())
.get_value(pref_name.str())
.try_into()
.unwrap_or_default(),
)

View file

@ -117,7 +117,7 @@ impl TextMethods<crate::DomTypeHolder> for Text {
let mut text = String::new();
for ref node in nodes {
let cdata = node.downcast::<CharacterData>().unwrap();
text.push_str(&cdata.data());
text.push_str(cdata.data().str());
}
DOMString::from(text)
}

View file

@ -70,7 +70,7 @@ impl TrustedHTML {
impl fmt::Display for TrustedHTML {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.data)
f.write_str(self.data.str())
}
}

View file

@ -150,14 +150,14 @@ impl TrustedScript {
};
global
.get_csp_list()
.is_js_evaluation_allowed(global, &source_string)
.is_js_evaluation_allowed(global, source_string.str())
}
}
impl fmt::Display for TrustedScript {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.data)
f.write_str(self.data.str())
}
}

View file

@ -70,7 +70,7 @@ impl TrustedScriptURL {
impl fmt::Display for TrustedScriptURL {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(&self.data)
f.write_str(self.data.str())
}
}

View file

@ -317,7 +317,10 @@ impl TrustedTypePolicyFactory {
let is_blocked = global
.get_csp_list()
.should_sink_type_mismatch_violation_be_blocked_by_csp(
global, sink, sink_group, &input,
global,
sink,
sink_group,
input.str(),
);
// Step 6.2: If disposition is “Allowed”, return stringified input and abort further steps.
if !is_blocked {

View file

@ -199,7 +199,7 @@ impl URLMethods<crate::DomTypeHolder> for URL {
// this method call does nothing. User agents may display a message on the error console.
let origin = get_blob_origin(&global.get_url());
if let Ok(url) = ServoUrl::parse(&url) {
if let Ok(url) = ServoUrl::parse(url.str()) {
if url.fragment().is_none() && origin == get_blob_origin(&url) {
if let Ok((id, _)) = parse_blob_url(&url) {
let resource_threads = global.resource_threads();

View file

@ -10,6 +10,7 @@ use canvas_traits::webgl::{GlType, TexFormat, WebGLSLVersion, WebGLVersion};
use js::jsapi::JSObject;
use malloc_size_of::MallocSizeOf;
use rustc_hash::{FxHashMap, FxHashSet};
use script_bindings::str::DOMString;
type GLenum = u32;
use super::wrapper::{TypedWebGLExtensionWrapper, WebGLExtensionWrapper};
@ -229,7 +230,7 @@ impl WebGLExtensions {
pub(crate) fn get_or_init_extension(
&self,
name: &str,
name: &DOMString,
ctx: &WebGLRenderingContext,
) -> Option<NonNull<JSObject>> {
let name = name.to_uppercase();

View file

@ -309,7 +309,7 @@ impl WebGLProgram {
if !validate_glsl_name(&name)? {
return Ok(());
}
if name.starts_with("gl_") {
if name.starts_with_str("gl_") {
return Err(WebGLError::InvalidOperation);
}
@ -375,7 +375,7 @@ impl WebGLProgram {
if !validate_glsl_name(&name)? {
return Ok(-1);
}
if name.starts_with("gl_") {
if name.starts_with_str("gl_") {
return Ok(-1);
}
@ -383,7 +383,7 @@ impl WebGLProgram {
.active_attribs
.borrow()
.iter()
.find(|attrib| attrib.name == *name)
.find(|attrib| *attrib.name == *name)
.and_then(|attrib| attrib.location.map(|l| l as i32))
.unwrap_or(-1);
Ok(location)
@ -398,7 +398,7 @@ impl WebGLProgram {
if !validate_glsl_name(&name)? {
return Ok(-1);
}
if name.starts_with("gl_") {
if name.starts_with_str("gl_") {
return Ok(-1);
}
@ -426,7 +426,7 @@ impl WebGLProgram {
if !validate_glsl_name(&name)? {
return Ok(None);
}
if name.starts_with("gl_") {
if name.starts_with_str("gl_") {
return Ok(None);
}
@ -499,10 +499,7 @@ impl WebGLProgram {
return Err(WebGLError::InvalidOperation);
}
let validation_errors = names
.iter()
.map(|name| validate_glsl_name(name))
.collect::<Vec<_>>();
let validation_errors = names.iter().map(validate_glsl_name).collect::<Vec<_>>();
let first_validation_error = validation_errors.iter().find(|result| result.is_err());
if let Some(error) = first_validation_error {
return Err(error.unwrap_err());
@ -679,7 +676,7 @@ impl Drop for WebGLProgram {
}
}
fn validate_glsl_name(name: &str) -> WebGLResult<bool> {
fn validate_glsl_name(name: &DOMString) -> WebGLResult<bool> {
if name.is_empty() {
return Ok(false);
}
@ -689,7 +686,7 @@ fn validate_glsl_name(name: &str) -> WebGLResult<bool> {
for c in name.chars() {
validate_glsl_char(c)?;
}
if name.starts_with("webgl_") || name.starts_with("_webgl_") {
if name.starts_with_str("webgl_") || name.starts_with_str("_webgl_") {
return Err(WebGLError::InvalidOperation);
}
Ok(true)
@ -735,7 +732,8 @@ fn validate_glsl_char(c: char) -> WebGLResult<()> {
}
}
fn parse_uniform_name(name: &str) -> Option<(&str, Option<i32>)> {
fn parse_uniform_name(name: &DOMString) -> Option<(&str, Option<i32>)> {
let name = name.str();
if !name.ends_with(']') {
return Some((name, None));
}

View file

@ -206,7 +206,7 @@ impl WebGLShader {
options.set_clampIndirectArrayBounds(1);
}
match validator.compile(&[&source], options) {
match validator.compile(&[source.str()], options) {
Ok(()) => {
let translated_source = validator.object_code();
debug!("Shader translated: {}", translated_source);

View file

@ -139,7 +139,7 @@ impl GPUAdapterMethods<crate::DomTypeHolder> for GPUAdapter {
let mut required_limits = wgpu_types::Limits::default();
if let Some(limits) = &descriptor.requiredLimits {
for (limit, value) in (*limits).iter() {
if !set_limit(&mut required_limits, limit.as_ref(), *value) {
if !set_limit(&mut required_limits, limit.str(), *value) {
warn!("Unknown GPUDevice limit: {limit}");
promise.reject_error(Error::Operation, can_gc);
return promise;

View file

@ -204,7 +204,7 @@ impl RTCDataChannel {
DataChannelMessage::Text(text) => {
text.safe_to_jsval(cx, message.handle_mut());
},
DataChannelMessage::Binary(data) => match &**self.binary_type.borrow() {
DataChannelMessage::Binary(data) => match self.binary_type.borrow().str() {
"blob" => {
let blob = Blob::new(
&global,

View file

@ -190,7 +190,7 @@ impl WebSocketMethods<crate::DomTypeHolder> for WebSocket {
// Step 1. Let baseURL be this's relevant settings object's API base URL.
// Step 2. Let urlRecord be the result of applying the URL parser to url with baseURL.
// Step 3. If urlRecord is failure, then throw a "SyntaxError" DOMException.
let mut url_record = ServoUrl::parse(&url).or(Err(Error::Syntax(None)))?;
let mut url_record = ServoUrl::parse(url.str()).or(Err(Error::Syntax(None)))?;
// Step 4. If urlRecords scheme is "http", then set urlRecords scheme to "ws".
// Step 5. Otherwise, if urlRecords scheme is "https", set urlRecords scheme to "wss".

View file

@ -1792,7 +1792,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
// https://drafts.csswg.org/cssom-view/#dom-window-matchmedia
fn MatchMedia(&self, query: DOMString) -> DomRoot<MediaQueryList> {
let media_query_list = MediaList::parse_media_list(&query, self);
let media_query_list = MediaList::parse_media_list(query.str(), self);
let document = self.Document();
let mql = MediaQueryList::new(&document, media_query_list, CanGc::note());
self.media_query_lists.track(&*mql);
@ -1881,7 +1881,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let iframe_iter = iframes.iter().map(|iframe| iframe.upcast::<Element>());
let name = Atom::from(&*name);
let name = Atom::from(name);
// Step 1.
let elements_with_name = document.get_elements_with_name(&name);

View file

@ -485,7 +485,7 @@ impl WindowProxy {
can_gc: CanGc,
) -> Fallible<Option<DomRoot<WindowProxy>>> {
// Step 5. If target is the empty string, then set target to "_blank".
let non_empty_target = match target.as_ref() {
let non_empty_target = match target.str() {
"" => DOMString::from("_blank"),
_ => target,
};

View file

@ -177,7 +177,7 @@ impl WorkerMethods<crate::DomTypeHolder> for Worker {
can_gc,
)?;
// Step 2-4.
let worker_url = match global.api_base_url().join(&compliant_script_url) {
let worker_url = match global.api_base_url().join(compliant_script_url.str()) {
Ok(url) => url,
Err(_) => return Err(Error::Syntax(None)),
};
@ -244,7 +244,7 @@ impl WorkerMethods<crate::DomTypeHolder> for Worker {
sender,
receiver,
worker_load_origin,
String::from(&*worker_options.name),
String::from(worker_options.name.str()),
worker_options.type_,
closing.clone(),
global.image_cache(),

View file

@ -392,7 +392,7 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
"importScripts",
can_gc,
)?;
let url = self.worker_url.borrow().join(&url);
let url = self.worker_url.borrow().join(url.str());
match url {
Ok(url) => urls.push(url),
Err(_) => return Err(Error::Syntax(None)),
@ -661,7 +661,7 @@ impl WorkerGlobalScope {
options.set_introduction_type(IntroductionType::WORKER);
match self.runtime.borrow().as_ref().unwrap().evaluate_script(
self.reflector().get_jsobject(),
&source,
source.str(),
rval.handle_mut(),
options,
) {

View file

@ -552,7 +552,7 @@ impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest {
// Step 4 (first half)
let mut extracted_or_serialized = match data {
Some(DocumentOrXMLHttpRequestBodyInit::Document(ref doc)) => {
let bytes = Vec::from(serialize_document(doc)?.as_ref());
let bytes = Vec::from(serialize_document(doc)?.str());
let content_type = if doc.is_html_document() {
"text/html;charset=UTF-8"
} else {
@ -720,7 +720,7 @@ impl XMLHttpRequestMethods<crate::DomTypeHolder> for XMLHttpRequest {
if !request.headers.contains_key(header::CONTENT_TYPE) {
request.headers.insert(
header::CONTENT_TYPE,
HeaderValue::from_str(&content_type).unwrap(),
HeaderValue::from_str(content_type.str()).unwrap(),
);
content_type_set = true;
}

View file

@ -70,7 +70,7 @@ impl XPathEvaluatorMethods<crate::DomTypeHolder> for XPathEvaluator {
// NB: this function is *not* Fallible according to the spec, so we swallow any parsing errors and
// just pass a None as the expression... it's not great.
let parsed_expression =
crate::xpath::parse(&expression).map_err(|_e| Error::Syntax(None))?;
crate::xpath::parse(expression.str()).map_err(|_e| Error::Syntax(None))?;
Ok(XPathExpression::new(
window,
None,
@ -98,7 +98,7 @@ impl XPathEvaluatorMethods<crate::DomTypeHolder> for XPathEvaluator {
let global = self.global();
let window = global.as_window();
let parsed_expression =
crate::xpath::parse(&expression_str).map_err(|_| Error::Syntax(None))?;
crate::xpath::parse(expression_str.str()).map_err(|_| Error::Syntax(None))?;
let expression = XPathExpression::new(window, None, can_gc, parsed_expression);
expression.evaluate_internal(context_node, result_type, result, resolver, can_gc)
}

View file

@ -58,7 +58,7 @@ impl Kind {
}
}
fn text_type_matches(&self, text_type: &str) -> bool {
fn text_type_matches(&self, text_type: &DOMString) -> bool {
matches!(self, Kind::Text { type_, .. } if type_.eq(text_type))
}
@ -153,7 +153,7 @@ impl DragDataStore {
types
}
pub(crate) fn find_matching_text(&self, type_: &str) -> Option<DOMString> {
pub(crate) fn find_matching_text(&self, type_: &DOMString) -> Option<DOMString> {
self.item_list
.values()
.find(|item| item.text_type_matches(type_))
@ -277,7 +277,7 @@ fn normalize_mime(mut format: DOMString) -> DOMString {
// Convert format to ASCII lowercase.
format.make_ascii_lowercase();
match format.as_ref() {
match format.str() {
// If format equals "text", change it to "text/plain".
"text" => DOMString::from("text/plain"),
// If format equals "url", change it to "text/uri-list".

View file

@ -106,11 +106,11 @@ pub(crate) fn is_valid_key_path(key_path: &StrOrStringSequence) -> Result<bool,
// An identifier, which is a string matching the IdentifierName production from the
// ECMAScript Language Specification [ECMA-262].
let is_identifier = is_identifier_name(path)?;
let is_identifier = is_identifier_name(path.str())?;
// A string consisting of two or more identifiers separated by periods (U+002E FULL STOP).
let is_identifier_list = path
.split(".")
.split('.')
.map(is_identifier_name)
.try_collect::<bool, Vec<bool>, Error>()?
.iter()

View file

@ -415,7 +415,7 @@ pub(crate) fn follow_hyperlink(
if let Some(suffix) = hyperlink_suffix {
href.push_str(&suffix);
}
let Ok(url) = document.base_url().join(&href) else {
let Ok(url) = document.base_url().join(href.str()) else {
return;
};

View file

@ -489,7 +489,7 @@ impl ModuleTree {
module_script.set(CompileModule1(
*cx,
compile_options.ptr,
&mut transform_str_to_source_text(&module_source.source),
&mut transform_str_to_source_text(module_source.source.str()),
));
if module_script.is_null() {
@ -695,7 +695,7 @@ impl ModuleTree {
// otherwise, specifier.
let normalized_specifier = match &as_url {
Some(url) => url.as_str(),
None => &specifier,
None => specifier.str(),
};
// Step 9. Let result be a URL-or-null, initially null.
@ -768,13 +768,15 @@ impl ModuleTree {
base_url: &ServoUrl,
) -> Option<ServoUrl> {
// Step 1. If specifier starts with "/", "./", or "../", then:
if specifier.starts_with('/') || specifier.starts_with("./") || specifier.starts_with("../")
if specifier.starts_with('/') ||
specifier.starts_with_str("./") ||
specifier.starts_with_str("../")
{
// Step 1.1. Let url be the result of URL parsing specifier with baseURL.
return ServoUrl::parse_with_base(Some(base_url), specifier).ok();
return ServoUrl::parse_with_base(Some(base_url), specifier.str()).ok();
}
// Step 2. Let url be the result of URL parsing specifier (with no base URL).
ServoUrl::parse(specifier).ok()
ServoUrl::parse(specifier.str()).ok()
}
/// <https://html.spec.whatwg.org/multipage/#finding-the-first-parse-error>

View file

@ -78,6 +78,12 @@ impl AddAssign for UTF8Bytes {
trait StrExt {
fn len_utf8(&self) -> UTF8Bytes;
}
impl StrExt for DOMString {
fn len_utf8(&self) -> UTF8Bytes {
UTF8Bytes(self.len())
}
}
impl StrExt for str {
fn len_utf8(&self) -> UTF8Bytes {
UTF8Bytes(self.len())
@ -121,7 +127,7 @@ impl AddAssign for UTF16CodeUnits {
impl From<DOMString> for SelectionDirection {
fn from(direction: DOMString) -> SelectionDirection {
match direction.as_ref() {
match direction.str() {
"forward" => SelectionDirection::Forward,
"backward" => SelectionDirection::Backward,
_ => SelectionDirection::None,
@ -246,7 +252,7 @@ pub(crate) const CMD_OR_CONTROL: Modifiers = Modifiers::CONTROL;
///
/// If the string has fewer than n characters, returns the length of the whole string.
/// If n is 0, returns 0
fn len_of_first_n_chars(text: &str, n: usize) -> UTF8Bytes {
fn len_of_first_n_chars(text: &DOMString, n: usize) -> UTF8Bytes {
match text.char_indices().take(n).last() {
Some((index, ch)) => UTF8Bytes(index + ch.len_utf8()),
None => UTF8Bytes::zero(),
@ -256,7 +262,7 @@ fn len_of_first_n_chars(text: &str, n: usize) -> UTF8Bytes {
/// The length in bytes of the first n code units in a string when encoded in UTF-16.
///
/// If the string is fewer than n code units, returns the length of the whole string.
fn len_of_first_n_code_units(text: &str, n: UTF16CodeUnits) -> UTF8Bytes {
fn len_of_first_n_code_units(text: &DOMString, n: UTF16CodeUnits) -> UTF8Bytes {
let mut utf8_len = UTF8Bytes::zero();
let mut utf16_len = UTF16CodeUnits::zero();
for c in text.chars() {
@ -460,15 +466,18 @@ impl<T: ClipboardProvider> TextInput<T> {
let UTF8Bytes(end_offset) = end.index;
if start.line == end.line {
f(&mut acc, &self.lines[start.line][start_offset..end_offset])
f(
&mut acc,
&self.lines[start.line].str()[start_offset..end_offset],
)
} else {
f(&mut acc, &self.lines[start.line][start_offset..]);
f(&mut acc, &self.lines[start.line].str()[start_offset..]);
for line in &self.lines[start.line + 1..end.line] {
f(&mut acc, "\n");
f(&mut acc, line);
}
f(&mut acc, "\n");
f(&mut acc, &self.lines[end.line][..end_offset])
f(&mut acc, &self.lines[end.line].str()[..end_offset])
}
}
@ -490,15 +499,15 @@ impl<T: ClipboardProvider> TextInput<T> {
let UTF8Bytes(last_char_index) =
len_of_first_n_code_units(&insert, allowed_to_insert_count);
let to_insert = &insert[..last_char_index];
let to_insert = &insert.str()[..last_char_index];
let (start, end) = self.sorted_selection_bounds();
let UTF8Bytes(start_offset) = start.index;
let UTF8Bytes(end_offset) = end.index;
let new_lines = {
let prefix = &self.lines[start.line][..start_offset];
let suffix = &self.lines[end.line][end_offset..];
let prefix = &self.lines[start.line].str()[..start_offset];
let suffix = &self.lines[end.line].str()[end_offset..];
let lines_prefix = &self.lines[..start.line];
let lines_suffix = &self.lines[end.line + 1..];
@ -511,7 +520,7 @@ impl<T: ClipboardProvider> TextInput<T> {
// FIXME(ajeffrey): efficient append for DOMStrings
let mut new_line = prefix.to_owned();
new_line.push_str(&insert_lines[0]);
new_line.push_str(insert_lines[0].str());
insert_lines[0] = DOMString::from(new_line);
let last_insert_lines_index = insert_lines.len() - 1;
@ -583,7 +592,7 @@ impl<T: ClipboardProvider> TextInput<T> {
}
let UTF8Bytes(edit_index) = self.edit_point.index;
let col = self.lines[self.edit_point.line][..edit_index]
let col = self.lines[self.edit_point.line].str()[..edit_index]
.chars()
.count();
self.edit_point.line = target_line as usize;
@ -625,7 +634,7 @@ impl<T: ClipboardProvider> TextInput<T> {
return;
}
let adjust = {
let current_line = &self.lines[self.edit_point.line];
let current_line = self.lines[self.edit_point.line].str();
let UTF8Bytes(current_offset) = self.edit_point.index;
let next_ch = match direction {
Direction::Forward => current_line[current_offset..].graphemes(true).next(),
@ -836,8 +845,8 @@ impl<T: ClipboardProvider> TextInput<T> {
let current_line = &self.lines[self.edit_point.line];
let UTF8Bytes(current_offset) = self.edit_point.index;
match direction {
Direction::Backward => current_line[..current_offset].len(),
Direction::Forward => current_line[current_offset..].len(),
Direction::Backward => current_line.str()[..current_offset].len(),
Direction::Forward => current_line.str()[current_offset..].len(),
}
};
self.perform_horizontal_adjustment(UTF8Bytes(shift), direction, select);
@ -1042,13 +1051,13 @@ impl<T: ClipboardProvider> TextInput<T> {
}
pub(crate) fn handle_compositionend(&mut self, event: &CompositionEvent) -> KeyReaction {
self.insert_string(event.data());
self.insert_string(event.data().str());
KeyReaction::DispatchInput
}
pub(crate) fn handle_compositionupdate(&mut self, event: &CompositionEvent) -> KeyReaction {
let start = self.selection_start_offset().0;
self.insert_string(event.data());
self.insert_string(event.data().str());
self.set_selection_range(
start as u32,
(start + event.data().len_utf8().0) as u32,
@ -1094,7 +1103,7 @@ impl<T: ClipboardProvider> TextInput<T> {
pub fn get_content(&self) -> DOMString {
let mut content = "".to_owned();
for (i, line) in self.lines.iter().enumerate() {
content.push_str(line);
content.push_str(line.str());
if i < self.lines.len() - 1 {
content.push('\n');
}
@ -1201,6 +1210,7 @@ impl<T: ClipboardProvider> TextInput<T> {
/// Set the edit point index position based off of a given grapheme cluster offset
pub fn set_edit_point_index(&mut self, index: usize) {
let byte_offset = self.lines[self.edit_point.line]
.str()
.graphemes(true)
.take(index)
.fold(UTF8Bytes::zero(), |acc, x| acc + x.len_utf8());

View file

@ -465,7 +465,7 @@ impl JsTimers {
// If this throws an exception, catch it, report it for global, and abort these steps.
if global
.get_csp_list()
.is_js_evaluation_allowed(global, code_str.as_ref())
.is_js_evaluation_allowed(global, code_str.str())
{
// Step 9.6.2. Assert: handler is a string.
InternalTimerCallback::StringTimerCallback(code_str)
@ -611,7 +611,7 @@ impl JsTimerTask {
//
// FIXME(cybai): Use base url properly by saving private reference for timers (#27260)
_ = global.evaluate_js_on_global_with_result(
code_str,
code_str.str(),
rval.handle_mut(),
ScriptFetchOptions::default_classic_script(&global),
// Step 9.6. Let base URL be settings object's API base URL.

View file

@ -75,7 +75,7 @@ pub enum StringificationBehavior {
// https://heycam.github.io/webidl/#es-DOMString
impl ToJSValConvertible for DOMString {
unsafe fn to_jsval(&self, cx: *mut JSContext, rval: MutableHandleValue) {
(**self).to_jsval(cx, rval);
self.str().to_jsval(cx, rval);
}
}

View file

@ -517,7 +517,10 @@ pub(crate) fn report_cross_origin_denial<D: DomTypes>(
debug!(
"permission denied to {} property {} on cross-origin object",
access,
id_to_source(cx, id).as_deref().unwrap_or("< error >"),
id_to_source(cx, id)
.as_ref()
.map(|source| source.str())
.unwrap_or("< error >"),
);
let in_realm_proof = AlreadyInRealm::assert_for_cx(cx);
unsafe {

View file

@ -36,7 +36,7 @@ pub trait RecordKey: Eq + Hash + Sized {
impl RecordKey for DOMString {
fn to_utf16_vec(&self) -> Vec<u16> {
self.encode_utf16().collect::<Vec<_>>()
self.str().encode_utf16().collect::<Vec<_>>()
}
unsafe fn from_id(cx: *mut JSContext, id: HandleId) -> Result<ConversionResult<Self>, ()> {

View file

@ -8,7 +8,7 @@ use std::default::Default;
use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::str::FromStr;
use std::str::{Chars, EncodeUtf16, FromStr};
use std::sync::LazyLock;
use std::{fmt, ops, slice, str};
@ -18,6 +18,7 @@ use js::rust::wrappers::ToJSON;
use js::rust::{HandleObject, HandleValue};
use num_traits::Zero;
use regex::Regex;
use style::str::HTML_SPACE_CHARACTERS;
use stylo_atoms::Atom;
use crate::error::Error;
@ -296,6 +297,67 @@ impl DOMString {
self.0 = parsed_value.to_string()
}
}
// What follows are the functions inherited from std::string
pub fn make_ascii_lowercase(&mut self) {
self.0.make_ascii_lowercase();
}
pub fn to_ascii_lowercase(&self) -> String {
self.0.to_ascii_lowercase()
}
pub fn len(&self) -> usize {
self.0.len()
}
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
pub fn chars(&self) -> Chars<'_> {
self.0.chars()
}
pub fn parse<T: FromStr>(&self) -> Result<T, <T as FromStr>::Err> {
self.0.parse::<T>()
}
pub fn contains(&self, needle: &str) -> bool {
self.0.contains(needle)
}
pub fn to_lowercase(&self) -> String {
self.0.to_lowercase()
}
pub fn as_bytes(&self) -> &[u8] {
self.0.as_bytes()
}
pub fn to_uppercase(&self) -> String {
self.0.to_uppercase()
}
pub fn encode_utf16(&self) -> EncodeUtf16<'_> {
self.0.encode_utf16()
}
pub fn find(&self, c: char) -> Option<usize> {
self.0.find(c)
}
pub fn starts_with(&self, c: char) -> bool {
self.0.starts_with(c)
}
pub fn starts_with_str(&self, needle: &str) -> bool {
self.0.starts_with(needle)
}
pub fn contains_html_space_characters(&self) -> bool {
self.0.contains(HTML_SPACE_CHARACTERS)
}
}
/// Because this converts to a DOMString it becomes UTF-8 encoded which is closer to
@ -404,6 +466,12 @@ impl PartialEq<str> for DOMString {
}
}
impl PartialEq<DOMString> for str {
fn eq(&self, other: &DOMString) -> bool {
self == other.str()
}
}
impl<'a> PartialEq<&'a str> for DOMString {
fn eq(&self, other: &&'a str) -> bool {
&**self == *other