From 1e471b9b41f2bbf136dfdbf852c2cd5875984955 Mon Sep 17 00:00:00 2001 From: Narfinger Date: Thu, 25 Sep 2025 14:27:42 +0200 Subject: [PATCH] Script: Change the rest of script to not rely on Deref 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 --- components/script/body.rs | 2 +- components/script/dom/bindings/domname.rs | 10 +-- components/script/dom/blob.rs | 4 +- components/script/dom/characterdata.rs | 10 +-- components/script/dom/clipboarditem.rs | 2 +- components/script/dom/compositionevent.rs | 2 +- components/script/dom/console.rs | 4 +- components/script/dom/css.rs | 8 +-- components/script/dom/csskeyframesrule.rs | 8 +-- components/script/dom/cssrulelist.rs | 5 +- components/script/dom/cssstyledeclaration.rs | 14 ++-- components/script/dom/cssstylerule.rs | 2 +- components/script/dom/cssstylesheet.rs | 2 +- .../script/dom/customelementregistry.rs | 13 ++-- components/script/dom/datatransfer.rs | 6 +- components/script/dom/document.rs | 14 ++-- components/script/dom/domexception.rs | 2 +- components/script/dom/domtokenlist.rs | 2 +- components/script/dom/servoparser/html.rs | 8 +-- components/script/dom/servoparser/mod.rs | 2 +- .../script/dom/stylepropertymapreadonly.rs | 4 +- components/script/dom/testbinding.rs | 4 +- components/script/dom/text.rs | 2 +- components/script/dom/trustedhtml.rs | 2 +- components/script/dom/trustedscript.rs | 4 +- components/script/dom/trustedscripturl.rs | 2 +- .../script/dom/trustedtypepolicyfactory.rs | 5 +- components/script/dom/url.rs | 2 +- .../script/dom/webgl/extensions/extensions.rs | 3 +- components/script/dom/webgl/webglprogram.rs | 22 +++--- components/script/dom/webgl/webglshader.rs | 2 +- components/script/dom/webgpu/gpuadapter.rs | 2 +- .../script/dom/webrtc/rtcdatachannel.rs | 2 +- components/script/dom/websocket.rs | 2 +- components/script/dom/window.rs | 4 +- components/script/dom/windowproxy.rs | 2 +- components/script/dom/worker.rs | 4 +- components/script/dom/workerglobalscope.rs | 4 +- components/script/dom/xmlhttprequest.rs | 4 +- components/script/dom/xpathevaluator.rs | 4 +- components/script/drag_data_store.rs | 6 +- components/script/indexed_db.rs | 4 +- components/script/links.rs | 2 +- components/script/script_module.rs | 12 ++-- components/script/textinput.rs | 44 +++++++----- components/script/timers.rs | 4 +- components/script_bindings/conversions.rs | 2 +- components/script_bindings/proxyhandler.rs | 5 +- components/script_bindings/record.rs | 2 +- components/script_bindings/str.rs | 70 ++++++++++++++++++- 50 files changed, 219 insertions(+), 132 deletions(-) diff --git a/components/script/body.rs b/components/script/body.rs index ab4ab0b42ba..a6459325f87 100644 --- a/components/script/body.rs +++ b/components/script/body.rs @@ -507,7 +507,7 @@ impl Extractable for Vec { impl Extractable for Blob { fn extract(&self, _global: &GlobalScope, can_gc: CanGc) -> Fallible { 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) diff --git a/components/script/dom/bindings/domname.rs b/components/script/dom/bindings/domname.rs index ba1553e6193..9994bda8f5e 100644 --- a/components/script/dom/bindings/domname.rs +++ b/components/script/dom/bindings/domname.rs @@ -91,7 +91,7 @@ pub(crate) fn is_valid_element_local_name(name: &str) -> bool { } /// -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 { /// pub(crate) fn validate_and_extract( namespace: Option, - qualified_name: &str, + qualified_name: &DOMString, context: Context, ) -> Fallible<(Namespace, Option, 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, diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs index 6c6c8d66b02..f8fb48edd35 100644 --- a/components/script/dom/blob.rs +++ b/components/script/dom/blob.rs @@ -176,7 +176,7 @@ impl BlobMethods 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 for Blob { can_gc: CanGc, ) -> DomRoot { 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. diff --git a/components/script/dom/characterdata.rs b/components/script/dom/characterdata.rs index fa0e9fe537c..d23de5a7d70 100644 --- a/components/script/dom/characterdata.rs +++ b/components/script/dom/characterdata.rs @@ -136,7 +136,7 @@ impl CharacterDataMethods 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 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 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 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() } } } diff --git a/components/script/dom/clipboarditem.rs b/components/script/dom/clipboarditem.rs index d1e01078442..98db5dbb34c 100644 --- a/components/script/dom/clipboarditem.rs +++ b/components/script/dom/clipboarditem.rs @@ -160,7 +160,7 @@ impl ClipboardItemMethods 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), diff --git a/components/script/dom/compositionevent.rs b/components/script/dom/compositionevent.rs index ec3a973ab10..52acad8c006 100644 --- a/components/script/dom/compositionevent.rs +++ b/components/script/dom/compositionevent.rs @@ -77,7 +77,7 @@ impl CompositionEvent { ev } - pub(crate) fn data(&self) -> &str { + pub(crate) fn data(&self) -> &DOMString { &self.data } } diff --git a/components/script/dom/console.rs b/components/script/dom/console.rs index f6e6c5da622..4ab8c75e50a 100644 --- a/components/script/dom/console.rs +++ b/components/script/dom/console.rs @@ -419,7 +419,7 @@ impl consoleMethods for Console { // https://console.spec.whatwg.org/#timelog fn TimeLog(_cx: JSContext, global: &GlobalScope, label: DOMString, data: Vec) { - 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 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()); diff --git a/components/script/dom/css.rs b/components/script/dom/css.rs index 97f8f71220b..b6e8a68f76c 100644 --- a/components/script/dom/css.rs +++ b/components/script/dom/css.rs @@ -31,16 +31,16 @@ impl CSSMethods for CSS { /// fn Escape(_: &Window, ident: DOMString) -> Fallible { let mut escaped = String::new(); - serialize_identifier(&ident, &mut escaped).unwrap(); + serialize_identifier(ident.str(), &mut escaped).unwrap(); Ok(DOMString::from(escaped)) } /// 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 for CSS { /// 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, diff --git a/components/script/dom/csskeyframesrule.rs b/components/script/dom/csskeyframesrule.rs index 58a13ca9852..2fcdc70cc7d 100644 --- a/components/script/dom/csskeyframesrule.rs +++ b/components/script/dom/csskeyframesrule.rs @@ -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 { - let mut input = ParserInput::new(selector); + fn find_rule(&self, selector: &DOMString) -> Option { + 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 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 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(); diff --git a/components/script/dom/cssrulelist.rs b/components/script/dom/cssrulelist.rs index e3b0338a309..09976f32a98 100644 --- a/components/script/dom/cssrulelist.rs +++ b/components/script/dom/cssrulelist.rs @@ -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, @@ -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, diff --git a/components/script/dom/cssstyledeclaration.rs b/components/script/dom/cssstyledeclaration.rs index 47457e7b823..f072c54769a 100644 --- a/components/script/dom/cssstyledeclaration.rs +++ b/components/script/dom/cssstyledeclaration.rs @@ -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 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 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 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 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, diff --git a/components/script/dom/cssstylerule.rs b/components/script/dom/cssstylerule.rs index c43d2a29369..90adcd5d4f5 100644 --- a/components/script/dom/cssstylerule.rs +++ b/components/script/dom/cssstylerule.rs @@ -151,7 +151,7 @@ impl CSSStyleRuleMethods 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? diff --git a/components/script/dom/cssstylesheet.rs b/components/script/dom/cssstylesheet.rs index a600dbbc461..85b567bb4b1 100644 --- a/components/script/dom/cssstylesheet.rs +++ b/components/script/dom/cssstylesheet.rs @@ -294,7 +294,7 @@ impl CSSStyleSheetMethods 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(), })); diff --git a/components/script/dom/customelementregistry.rs b/components/script/dom/customelementregistry.rs index c7908180e14..8529a55579c 100644 --- a/components/script/dom/customelementregistry.rs +++ b/components/script/dom/customelementregistry.rs @@ -345,7 +345,7 @@ impl CustomElementRegistryMethods 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 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 for CustomElementRegistr /// 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 for CustomElementRegistr /// fn WhenDefined(&self, name: DOMString, comp: InRealm, can_gc: CanGc) -> Rc { - 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; diff --git a/components/script/dom/datatransfer.rs b/components/script/dom/datatransfer.rs index c9fecde9bd3..d6674b4dc3b 100644 --- a/components/script/dom/datatransfer.rs +++ b/components/script/dom/datatransfer.rs @@ -112,7 +112,7 @@ impl DataTransferMethods for DataTransfer { /// 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 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 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. diff --git a/components/script/dom/document.rs b/components/script/dom/document.rs index f96d70a538b..57b9163abf4 100644 --- a/components/script/dom/document.rs +++ b/components/script/dom/document.rs @@ -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 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 { // 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 bool>(&self, callback: F) -> u32 { @@ -4669,7 +4669,7 @@ impl DocumentMethods for Document { qualified_name: DOMString, can_gc: CanGc, ) -> DomRoot { - 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 for Document { // https://dom.spec.whatwg.org/#dom-document-getelementsbyclassname fn GetElementsByClassName(&self, classes: DOMString, can_gc: CanGc) -> DomRoot { - let class_atoms: Vec = split_html_space_chars(&classes).map(Atom::from).collect(); + let class_atoms: Vec = 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); } diff --git a/components/script/dom/domexception.rs b/components/script/dom/domexception.rs index cdf5ec957ee..384ceaf90c1 100644 --- a/components/script/dom/domexception.rs +++ b/components/script/dom/domexception.rs @@ -61,7 +61,7 @@ pub(crate) enum DOMErrorName { impl DOMErrorName { pub(crate) fn from(s: &DOMString) -> Option { - match s.as_ref() { + match s.str() { "IndexSizeError" => Some(DOMErrorName::IndexSizeError), "HierarchyRequestError" => Some(DOMErrorName::HierarchyRequestError), "WrongDocumentError" => Some(DOMErrorName::WrongDocumentError), diff --git a/components/script/dom/domtokenlist.rs b/components/script/dom/domtokenlist.rs index 57a6d204f32..2bb80552927 100644 --- a/components/script/dom/domtokenlist.rs +++ b/components/script/dom/domtokenlist.rs @@ -192,7 +192,7 @@ impl DOMTokenListMethods 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); } diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs index 0fc3207438a..f50d737595d 100644 --- a/components/script/dom/servoparser/html.rs +++ b/components/script/dom/servoparser/html.rs @@ -303,23 +303,23 @@ pub(crate) fn serialize_html_fragment( SerializationCommand::SerializeNonelement(n) => match n.type_id() { NodeTypeId::DocumentType => { let doctype = n.downcast::().unwrap(); - serializer.write_doctype(doctype.name())?; + serializer.write_doctype(doctype.name().str())?; }, NodeTypeId::CharacterData(CharacterDataTypeId::Text(_)) => { let cdata = n.downcast::().unwrap(); - serializer.write_text(&cdata.data())?; + serializer.write_text(cdata.data().str())?; }, NodeTypeId::CharacterData(CharacterDataTypeId::Comment) => { let cdata = n.downcast::().unwrap(); - serializer.write_comment(&cdata.data())?; + serializer.write_comment(cdata.data().str())?; }, NodeTypeId::CharacterData(CharacterDataTypeId::ProcessingInstruction) => { let pi = n.downcast::().unwrap(); let data = pi.upcast::().data(); - serializer.write_processing_instruction(pi.target(), &data)?; + serializer.write_processing_instruction(pi.target().str(), data.str())?; }, NodeTypeId::DocumentFragment(_) | NodeTypeId::Attr => {}, diff --git a/components/script/dom/servoparser/mod.rs b/components/script/dom/servoparser/mod.rs index aad3143ece4..3bb1569eb64 100644 --- a/components/script/dom/servoparser/mod.rs +++ b/components/script/dom/servoparser/mod.rs @@ -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()); diff --git a/components/script/dom/stylepropertymapreadonly.rs b/components/script/dom/stylepropertymapreadonly.rs index fa2a8175df5..da09eb2d56a 100644 --- a/components/script/dom/stylepropertymapreadonly.rs +++ b/components/script/dom/stylepropertymapreadonly.rs @@ -90,8 +90,8 @@ impl StylePropertyMapReadOnlyMethods 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 diff --git a/components/script/dom/testbinding.rs b/components/script/dom/testbinding.rs index 8c1b9994284..0a7ddef0811 100644 --- a/components/script/dom/testbinding.rs +++ b/components/script/dom/testbinding.rs @@ -882,14 +882,14 @@ impl TestBindingMethods 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(), ) diff --git a/components/script/dom/text.rs b/components/script/dom/text.rs index a39bb65df23..42235c36777 100644 --- a/components/script/dom/text.rs +++ b/components/script/dom/text.rs @@ -117,7 +117,7 @@ impl TextMethods for Text { let mut text = String::new(); for ref node in nodes { let cdata = node.downcast::().unwrap(); - text.push_str(&cdata.data()); + text.push_str(cdata.data().str()); } DOMString::from(text) } diff --git a/components/script/dom/trustedhtml.rs b/components/script/dom/trustedhtml.rs index 905c5e58422..fd4898e65b6 100644 --- a/components/script/dom/trustedhtml.rs +++ b/components/script/dom/trustedhtml.rs @@ -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()) } } diff --git a/components/script/dom/trustedscript.rs b/components/script/dom/trustedscript.rs index 95b4827ee16..5724d9aa6d0 100644 --- a/components/script/dom/trustedscript.rs +++ b/components/script/dom/trustedscript.rs @@ -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()) } } diff --git a/components/script/dom/trustedscripturl.rs b/components/script/dom/trustedscripturl.rs index 0f509efa1eb..46da9f52789 100644 --- a/components/script/dom/trustedscripturl.rs +++ b/components/script/dom/trustedscripturl.rs @@ -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()) } } diff --git a/components/script/dom/trustedtypepolicyfactory.rs b/components/script/dom/trustedtypepolicyfactory.rs index 2bcb493e956..71053f28bae 100644 --- a/components/script/dom/trustedtypepolicyfactory.rs +++ b/components/script/dom/trustedtypepolicyfactory.rs @@ -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 { diff --git a/components/script/dom/url.rs b/components/script/dom/url.rs index 553aec8e442..d3930e0b4c7 100644 --- a/components/script/dom/url.rs +++ b/components/script/dom/url.rs @@ -199,7 +199,7 @@ impl URLMethods 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(); diff --git a/components/script/dom/webgl/extensions/extensions.rs b/components/script/dom/webgl/extensions/extensions.rs index 9fdf46586cb..65ebc4fb0cf 100644 --- a/components/script/dom/webgl/extensions/extensions.rs +++ b/components/script/dom/webgl/extensions/extensions.rs @@ -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> { let name = name.to_uppercase(); diff --git a/components/script/dom/webgl/webglprogram.rs b/components/script/dom/webgl/webglprogram.rs index 29750c521bd..1e5b037d64f 100644 --- a/components/script/dom/webgl/webglprogram.rs +++ b/components/script/dom/webgl/webglprogram.rs @@ -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::>(); + let validation_errors = names.iter().map(validate_glsl_name).collect::>(); 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 { +fn validate_glsl_name(name: &DOMString) -> WebGLResult { if name.is_empty() { return Ok(false); } @@ -689,7 +686,7 @@ fn validate_glsl_name(name: &str) -> WebGLResult { 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)> { +fn parse_uniform_name(name: &DOMString) -> Option<(&str, Option)> { + let name = name.str(); if !name.ends_with(']') { return Some((name, None)); } diff --git a/components/script/dom/webgl/webglshader.rs b/components/script/dom/webgl/webglshader.rs index 52a76cb8946..8aab0efab00 100644 --- a/components/script/dom/webgl/webglshader.rs +++ b/components/script/dom/webgl/webglshader.rs @@ -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); diff --git a/components/script/dom/webgpu/gpuadapter.rs b/components/script/dom/webgpu/gpuadapter.rs index 35e6a9d8f34..536897669e3 100644 --- a/components/script/dom/webgpu/gpuadapter.rs +++ b/components/script/dom/webgpu/gpuadapter.rs @@ -139,7 +139,7 @@ impl GPUAdapterMethods 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; diff --git a/components/script/dom/webrtc/rtcdatachannel.rs b/components/script/dom/webrtc/rtcdatachannel.rs index cad090b7f42..794d581fd96 100644 --- a/components/script/dom/webrtc/rtcdatachannel.rs +++ b/components/script/dom/webrtc/rtcdatachannel.rs @@ -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, diff --git a/components/script/dom/websocket.rs b/components/script/dom/websocket.rs index d74cd08731b..ed1e9a54602 100644 --- a/components/script/dom/websocket.rs +++ b/components/script/dom/websocket.rs @@ -190,7 +190,7 @@ impl WebSocketMethods 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 urlRecord’s scheme is "http", then set urlRecord’s scheme to "ws". // Step 5. Otherwise, if urlRecord’s scheme is "https", set urlRecord’s scheme to "wss". diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index 3984d69613a..faa60d66b7d 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -1792,7 +1792,7 @@ impl WindowMethods for Window { // https://drafts.csswg.org/cssom-view/#dom-window-matchmedia fn MatchMedia(&self, query: DOMString) -> DomRoot { - 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 for Window { let iframe_iter = iframes.iter().map(|iframe| iframe.upcast::()); - let name = Atom::from(&*name); + let name = Atom::from(name); // Step 1. let elements_with_name = document.get_elements_with_name(&name); diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs index d58e87814ee..c02169929a8 100644 --- a/components/script/dom/windowproxy.rs +++ b/components/script/dom/windowproxy.rs @@ -485,7 +485,7 @@ impl WindowProxy { can_gc: CanGc, ) -> Fallible>> { // 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, }; diff --git a/components/script/dom/worker.rs b/components/script/dom/worker.rs index f76b76b50d7..a7b99574612 100644 --- a/components/script/dom/worker.rs +++ b/components/script/dom/worker.rs @@ -177,7 +177,7 @@ impl WorkerMethods 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 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(), diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs index c2a6fd54039..569755f83c8 100644 --- a/components/script/dom/workerglobalscope.rs +++ b/components/script/dom/workerglobalscope.rs @@ -392,7 +392,7 @@ impl WorkerGlobalScopeMethods 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, ) { diff --git a/components/script/dom/xmlhttprequest.rs b/components/script/dom/xmlhttprequest.rs index 7b5b068069b..e7d39598882 100644 --- a/components/script/dom/xmlhttprequest.rs +++ b/components/script/dom/xmlhttprequest.rs @@ -552,7 +552,7 @@ impl XMLHttpRequestMethods 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 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; } diff --git a/components/script/dom/xpathevaluator.rs b/components/script/dom/xpathevaluator.rs index 259c447d259..4afbf79d01b 100644 --- a/components/script/dom/xpathevaluator.rs +++ b/components/script/dom/xpathevaluator.rs @@ -70,7 +70,7 @@ impl XPathEvaluatorMethods 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 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) } diff --git a/components/script/drag_data_store.rs b/components/script/drag_data_store.rs index 123b195a8da..b5539cb42a2 100644 --- a/components/script/drag_data_store.rs +++ b/components/script/drag_data_store.rs @@ -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 { + pub(crate) fn find_matching_text(&self, type_: &DOMString) -> Option { 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". diff --git a/components/script/indexed_db.rs b/components/script/indexed_db.rs index 7b75380bb5d..5eacddbb774 100644 --- a/components/script/indexed_db.rs +++ b/components/script/indexed_db.rs @@ -106,11 +106,11 @@ pub(crate) fn is_valid_key_path(key_path: &StrOrStringSequence) -> Result, Error>()? .iter() diff --git a/components/script/links.rs b/components/script/links.rs index aa91a5731be..d704103297a 100644 --- a/components/script/links.rs +++ b/components/script/links.rs @@ -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; }; diff --git a/components/script/script_module.rs b/components/script/script_module.rs index b897227850d..c7bced3ecc3 100644 --- a/components/script/script_module.rs +++ b/components/script/script_module.rs @@ -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 { // 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() } /// diff --git a/components/script/textinput.rs b/components/script/textinput.rs index edb8248cfdc..12f0ee22961 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -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 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 TextInput { 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 TextInput { 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 TextInput { // 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 TextInput { } 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 TextInput { 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 TextInput { 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 TextInput { } 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 TextInput { 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 TextInput { /// 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()); diff --git a/components/script/timers.rs b/components/script/timers.rs index f0662e8572d..60411d85836 100644 --- a/components/script/timers.rs +++ b/components/script/timers.rs @@ -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. diff --git a/components/script_bindings/conversions.rs b/components/script_bindings/conversions.rs index 54b56121c8a..92086c58d9b 100644 --- a/components/script_bindings/conversions.rs +++ b/components/script_bindings/conversions.rs @@ -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); } } diff --git a/components/script_bindings/proxyhandler.rs b/components/script_bindings/proxyhandler.rs index 0f81e315efc..b3bd63f2fc3 100644 --- a/components/script_bindings/proxyhandler.rs +++ b/components/script_bindings/proxyhandler.rs @@ -517,7 +517,10 @@ pub(crate) fn report_cross_origin_denial( 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 { diff --git a/components/script_bindings/record.rs b/components/script_bindings/record.rs index d469faefaf2..369b495dd8b 100644 --- a/components/script_bindings/record.rs +++ b/components/script_bindings/record.rs @@ -36,7 +36,7 @@ pub trait RecordKey: Eq + Hash + Sized { impl RecordKey for DOMString { fn to_utf16_vec(&self) -> Vec { - self.encode_utf16().collect::>() + self.str().encode_utf16().collect::>() } unsafe fn from_id(cx: *mut JSContext, id: HandleId) -> Result, ()> { diff --git a/components/script_bindings/str.rs b/components/script_bindings/str.rs index bf47a6531b6..4fab5aa0e79 100644 --- a/components/script_bindings/str.rs +++ b/components/script_bindings/str.rs @@ -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(&self) -> Result::Err> { + self.0.parse::() + } + + 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 { + 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 for DOMString { } } +impl PartialEq 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