aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock57
-rw-r--r--Cargo.toml1
-rw-r--r--components/layout/construct_modern.rs40
-rw-r--r--components/layout/dom.rs66
-rw-r--r--components/layout/dom_traversal.rs114
-rw-r--r--components/layout/flexbox/mod.rs6
-rw-r--r--components/layout/flow/construct.rs85
-rw-r--r--components/layout/flow/float.rs5
-rw-r--r--components/layout/flow/inline/construct.rs7
-rw-r--r--components/layout/flow/inline/inline_box.rs3
-rw-r--r--components/layout/flow/root.rs30
-rw-r--r--components/layout/formatting_contexts.rs16
-rw-r--r--components/layout/lists.rs10
-rw-r--r--components/layout/positioned.rs5
-rw-r--r--components/layout/query.rs35
-rw-r--r--components/layout/replaced.rs12
-rw-r--r--components/layout/table/construct.rs88
-rw-r--r--components/layout/taffy/mod.rs6
-rw-r--r--components/malloc_size_of/Cargo.toml1
-rw-r--r--components/malloc_size_of/lib.rs1
-rw-r--r--components/net/fetch/methods.rs2
-rw-r--r--components/script/Cargo.toml1
-rw-r--r--components/script/dom/blob.rs29
-rw-r--r--components/script/dom/globalscope.rs96
-rw-r--r--components/script/dom/servoparser/html.rs3
-rw-r--r--components/script/dom/urlpattern.rs204
-rw-r--r--components/script/dom/urlpattern/mod.rs810
-rw-r--r--components/script/dom/urlpattern/pattern_parser.rs473
-rw-r--r--components/script/dom/urlpattern/preprocessing.rs659
-rw-r--r--components/script/dom/urlpattern/tokenizer.rs524
-rw-r--r--components/script_bindings/webidls/URLPattern.webidl8
-rw-r--r--components/shared/constellation/structured_data/serializable.rs4
-rw-r--r--components/shared/net/filemanager_thread.rs2
-rw-r--r--tests/wpt/meta/MANIFEST.json2
-rw-r--r--tests/wpt/meta/urlpattern/urlpattern.any.js.ini18
-rw-r--r--tests/wpt/meta/urlpattern/urlpattern.https.any.js.ini18
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json7
-rw-r--r--tests/wpt/mozilla/tests/mozilla/slice-blob-twice-crash.html5
-rw-r--r--tests/wpt/tests/domparsing/XMLSerializer-serializeToString.html4
39 files changed, 592 insertions, 2865 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 6940195ff30..c1ceccb3686 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2227,7 +2227,7 @@ dependencies = [
[[package]]
name = "fontsan"
version = "0.5.2"
-source = "git+https://github.com/servo/fontsan#138bdb0451c4ea02a303caddc1a6c1fd654ae927"
+source = "git+https://github.com/servo/fontsan#c0d0b5333117901e1c31bc3c502c384115b93e6f"
dependencies = [
"cc",
"glob",
@@ -6323,6 +6323,7 @@ dependencies = [
"unicode-bidi",
"unicode-segmentation",
"url",
+ "urlpattern",
"utf-8",
"uuid",
"webdriver",
@@ -6828,6 +6829,7 @@ dependencies = [
"unicode-bidi",
"unicode-script",
"url",
+ "urlpattern",
"uuid",
"webrender_api",
"wr_malloc_size_of",
@@ -8011,6 +8013,47 @@ dependencies = [
]
[[package]]
+name = "unic-char-property"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a8c57a407d9b6fa02b4795eb81c5b6652060a15a7903ea981f3d723e6c0be221"
+dependencies = [
+ "unic-char-range",
+]
+
+[[package]]
+name = "unic-char-range"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0398022d5f700414f6b899e10b8348231abf9173fa93144cbc1a43b9793c1fbc"
+
+[[package]]
+name = "unic-common"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80d7ff825a6a654ee85a63e80f92f054f904f21e7d12da4e22f9834a4aaa35bc"
+
+[[package]]
+name = "unic-ucd-ident"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e230a37c0381caa9219d67cf063aa3a375ffed5bf541a452db16e744bdab6987"
+dependencies = [
+ "unic-char-property",
+ "unic-char-range",
+ "unic-ucd-version",
+]
+
+[[package]]
+name = "unic-ucd-version"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96bd2f2237fe450fcd0a1d2f5f4e91711124f7857ba2e964247776ebeeb7b0c4"
+dependencies = [
+ "unic-common",
+]
+
+[[package]]
name = "unicase"
version = "2.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -8091,6 +8134,18 @@ dependencies = [
]
[[package]]
+name = "urlpattern"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70acd30e3aa1450bc2eece896ce2ad0d178e9c079493819301573dae3c37ba6d"
+dependencies = [
+ "regex",
+ "serde",
+ "unic-ucd-ident",
+ "url",
+]
+
+[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/Cargo.toml b/Cargo.toml
index a82fb8aea73..b7ba61f2145 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -162,6 +162,7 @@ unicode-properties = { version = "0.1.3", features = ["emoji"] }
unicode-script = "0.5"
unicode-segmentation = "1.12.0"
url = "2.5"
+urlpattern = "0.3"
uuid = { version = "1.12.1", features = ["v4"] }
webdriver = "0.51.0"
webgpu_traits = { path = "components/shared/webgpu" }
diff --git a/components/layout/construct_modern.rs b/components/layout/construct_modern.rs
index 22f179d146c..1489d82635b 100644
--- a/components/layout/construct_modern.rs
+++ b/components/layout/construct_modern.rs
@@ -12,7 +12,7 @@ use style::selector_parser::PseudoElement;
use crate::PropagatedBoxTreeData;
use crate::context::LayoutContext;
-use crate::dom::{BoxSlot, NodeExt};
+use crate::dom::BoxSlot;
use crate::dom_traversal::{Contents, NodeAndStyleInfo, TraversalHandler};
use crate::flow::inline::construct::InlineFormattingContextBuilder;
use crate::flow::{BlockContainer, BlockFormattingContext};
@@ -24,32 +24,32 @@ use crate::layout_box_base::LayoutBoxBase;
use crate::style_ext::DisplayGeneratingBox;
/// A builder used for both flex and grid containers.
-pub(crate) struct ModernContainerBuilder<'a, 'dom, Node> {
+pub(crate) struct ModernContainerBuilder<'a, 'dom> {
context: &'a LayoutContext<'a>,
- info: &'a NodeAndStyleInfo<Node>,
+ info: &'a NodeAndStyleInfo<'dom>,
propagated_data: PropagatedBoxTreeData,
- contiguous_text_runs: Vec<ModernContainerTextRun<'dom, Node>>,
+ contiguous_text_runs: Vec<ModernContainerTextRun<'dom>>,
/// To be run in parallel with rayon in `finish`
- jobs: Vec<ModernContainerJob<'dom, Node>>,
+ jobs: Vec<ModernContainerJob<'dom>>,
has_text_runs: bool,
}
-enum ModernContainerJob<'dom, Node> {
+enum ModernContainerJob<'dom> {
ElementOrPseudoElement {
- info: NodeAndStyleInfo<Node>,
+ info: NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
},
- TextRuns(Vec<ModernContainerTextRun<'dom, Node>>),
+ TextRuns(Vec<ModernContainerTextRun<'dom>>),
}
-struct ModernContainerTextRun<'dom, Node> {
- info: NodeAndStyleInfo<Node>,
+struct ModernContainerTextRun<'dom> {
+ info: NodeAndStyleInfo<'dom>,
text: Cow<'dom, str>,
}
-impl<Node> ModernContainerTextRun<'_, Node> {
+impl ModernContainerTextRun<'_> {
/// <https://drafts.csswg.org/css-text/#white-space>
fn is_only_document_white_space(&self) -> bool {
// FIXME: is this the right definition? See
@@ -73,11 +73,8 @@ pub(crate) struct ModernItem<'dom> {
pub formatting_context: IndependentFormattingContext,
}
-impl<'dom, Node: 'dom> TraversalHandler<'dom, Node> for ModernContainerBuilder<'_, 'dom, Node>
-where
- Node: NodeExt<'dom>,
-{
- fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {
+impl<'dom> TraversalHandler<'dom> for ModernContainerBuilder<'_, 'dom> {
+ fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: Cow<'dom, str>) {
self.contiguous_text_runs.push(ModernContainerTextRun {
info: info.clone(),
text,
@@ -87,7 +84,7 @@ where
/// Or pseudo-element
fn handle_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -103,13 +100,10 @@ where
}
}
-impl<'a, 'dom, Node: 'dom> ModernContainerBuilder<'a, 'dom, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl<'a, 'dom> ModernContainerBuilder<'a, 'dom> {
pub fn new(
context: &'a LayoutContext<'a>,
- info: &'a NodeAndStyleInfo<Node>,
+ info: &'a NodeAndStyleInfo<'dom>,
propagated_data: PropagatedBoxTreeData,
) -> Self {
ModernContainerBuilder {
@@ -165,7 +159,7 @@ where
let block_formatting_context = BlockFormattingContext::from_block_container(
BlockContainer::InlineFormattingContext(inline_formatting_context),
);
- let info: &NodeAndStyleInfo<_> = &*anonymous_info;
+ let info: &NodeAndStyleInfo = &anonymous_info;
let formatting_context = IndependentFormattingContext {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
contents: IndependentFormattingContextContents::NonReplaced(
diff --git a/components/layout/dom.rs b/components/layout/dom.rs
index 8f2697e670a..4400d78feb1 100644
--- a/components/layout/dom.rs
+++ b/components/layout/dom.rs
@@ -11,6 +11,7 @@ use base::id::{BrowsingContextId, PipelineId};
use html5ever::{local_name, ns};
use malloc_size_of_derive::MallocSizeOf;
use pixels::Image;
+use script::layout_dom::ServoLayoutNode;
use script_layout_interface::wrapper_traits::{
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
@@ -158,34 +159,31 @@ impl Drop for BoxSlot<'_> {
}
}
-pub(crate) trait NodeExt<'dom>: 'dom + LayoutNode<'dom> {
+pub(crate) trait NodeExt<'dom> {
/// Returns the image if it’s loaded, and its size in image pixels
/// adjusted for `image_density`.
- fn as_image(self) -> Option<(Option<Arc<Image>>, PhysicalSize<f64>)>;
- fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
- fn as_iframe(self) -> Option<(PipelineId, BrowsingContextId)>;
- fn as_video(self) -> Option<(Option<webrender_api::ImageKey>, Option<PhysicalSize<f64>>)>;
- fn as_typeless_object_with_data_attribute(self) -> Option<String>;
- fn style(self, context: &LayoutContext) -> ServoArc<ComputedValues>;
-
- fn layout_data_mut(self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
- fn layout_data(self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
+ fn as_image(&self) -> Option<(Option<Arc<Image>>, PhysicalSize<f64>)>;
+ fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)>;
+ fn as_iframe(&self) -> Option<(PipelineId, BrowsingContextId)>;
+ fn as_video(&self) -> Option<(Option<webrender_api::ImageKey>, Option<PhysicalSize<f64>>)>;
+ fn as_typeless_object_with_data_attribute(&self) -> Option<String>;
+ fn style(&self, context: &LayoutContext) -> ServoArc<ComputedValues>;
+
+ fn layout_data_mut(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData>;
+ fn layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>>;
fn element_box_slot(&self) -> BoxSlot<'dom>;
fn pseudo_element_box_slot(&self, which: PseudoElement) -> BoxSlot<'dom>;
- fn unset_pseudo_element_box(self, which: PseudoElement);
+ fn unset_pseudo_element_box(&self, which: PseudoElement);
/// Remove boxes for the element itself, and its `:before` and `:after` if any.
- fn unset_all_boxes(self);
+ fn unset_all_boxes(&self);
fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment>;
- fn invalidate_cached_fragment(self);
+ fn invalidate_cached_fragment(&self);
}
-impl<'dom, LayoutNodeType> NodeExt<'dom> for LayoutNodeType
-where
- LayoutNodeType: 'dom + LayoutNode<'dom>,
-{
- fn as_image(self) -> Option<(Option<Arc<Image>>, PhysicalSize<f64>)> {
+impl<'dom> NodeExt<'dom> for ServoLayoutNode<'dom> {
+ fn as_image(&self) -> Option<(Option<Arc<Image>>, PhysicalSize<f64>)> {
let node = self.to_threadsafe();
let (resource, metadata) = node.image_data()?;
let (width, height) = resource
@@ -201,7 +199,7 @@ where
Some((resource, PhysicalSize::new(width, height)))
}
- fn as_video(self) -> Option<(Option<webrender_api::ImageKey>, Option<PhysicalSize<f64>>)> {
+ fn as_video(&self) -> Option<(Option<webrender_api::ImageKey>, Option<PhysicalSize<f64>>)> {
let node = self.to_threadsafe();
let data = node.media_data()?;
let natural_size = if let Some(frame) = data.current_frame {
@@ -216,7 +214,7 @@ where
))
}
- fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
+ fn as_canvas(&self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
let node = self.to_threadsafe();
let canvas_data = node.canvas_data()?;
let source = canvas_data.source;
@@ -226,7 +224,7 @@ where
))
}
- fn as_iframe(self) -> Option<(PipelineId, BrowsingContextId)> {
+ fn as_iframe(&self) -> Option<(PipelineId, BrowsingContextId)> {
let node = self.to_threadsafe();
match (node.iframe_pipeline_id(), node.iframe_browsing_context_id()) {
(Some(pipeline_id), Some(browsing_context_id)) => {
@@ -236,8 +234,10 @@ where
}
}
- fn as_typeless_object_with_data_attribute(self) -> Option<String> {
- if self.type_id() != ScriptLayoutNodeType::Element(LayoutElementType::HTMLObjectElement) {
+ fn as_typeless_object_with_data_attribute(&self) -> Option<String> {
+ if LayoutNode::type_id(self) !=
+ ScriptLayoutNodeType::Element(LayoutElementType::HTMLObjectElement)
+ {
return None;
}
@@ -253,15 +253,15 @@ where
.map(|string| string.to_owned())
}
- fn style(self, context: &LayoutContext) -> ServoArc<ComputedValues> {
+ fn style(&self, context: &LayoutContext) -> ServoArc<ComputedValues> {
self.to_threadsafe().style(context.shared_context())
}
- fn layout_data_mut(self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
- if LayoutNode::layout_data(&self).is_none() {
+ fn layout_data_mut(&self) -> AtomicRefMut<'dom, InnerDOMLayoutData> {
+ if LayoutNode::layout_data(self).is_none() {
self.initialize_layout_data::<DOMLayoutData>();
}
- LayoutNode::layout_data(&self)
+ LayoutNode::layout_data(self)
.unwrap()
.as_any()
.downcast_ref::<DOMLayoutData>()
@@ -270,8 +270,8 @@ where
.borrow_mut()
}
- fn layout_data(self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
- LayoutNode::layout_data(&self).map(|data| {
+ fn layout_data(&self) -> Option<AtomicRef<'dom, InnerDOMLayoutData>> {
+ LayoutNode::layout_data(self).map(|data| {
data.as_any()
.downcast_ref::<DOMLayoutData>()
.unwrap()
@@ -298,7 +298,7 @@ where
BoxSlot::new(cell.clone())
}
- fn unset_pseudo_element_box(self, pseudo_element_type: PseudoElement) {
+ fn unset_pseudo_element_box(&self, pseudo_element_type: PseudoElement) {
let data = self.layout_data_mut();
let cell = match pseudo_element_type {
PseudoElement::Before => &data.pseudo_before_box,
@@ -312,7 +312,7 @@ where
*cell.borrow_mut() = None;
}
- fn unset_all_boxes(self) {
+ fn unset_all_boxes(&self) {
let data = self.layout_data_mut();
*data.self_box.borrow_mut() = None;
*data.pseudo_before_box.borrow_mut() = None;
@@ -322,7 +322,7 @@ where
// for DOM descendants of elements with `display: none`.
}
- fn invalidate_cached_fragment(self) {
+ fn invalidate_cached_fragment(&self) {
let data = self.layout_data_mut();
if let Some(data) = data.self_box.borrow_mut().as_mut() {
data.invalidate_cached_fragment();
@@ -330,7 +330,7 @@ where
}
fn fragments_for_pseudo(&self, pseudo_element: Option<PseudoElement>) -> Vec<Fragment> {
- NodeExt::layout_data(*self)
+ NodeExt::layout_data(self)
.and_then(|layout_data| {
layout_data
.for_pseudo(pseudo_element)
diff --git a/components/layout/dom_traversal.rs b/components/layout/dom_traversal.rs
index 42101e3edbc..a75d699a1b3 100644
--- a/components/layout/dom_traversal.rs
+++ b/components/layout/dom_traversal.rs
@@ -8,11 +8,14 @@ use std::iter::FusedIterator;
use fonts::ByteIndex;
use html5ever::{LocalName, local_name};
use range::Range;
-use script_layout_interface::wrapper_traits::{ThreadSafeLayoutElement, ThreadSafeLayoutNode};
+use script::layout_dom::ServoLayoutNode;
+use script_layout_interface::wrapper_traits::{
+ LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
+};
use script_layout_interface::{LayoutElementType, LayoutNodeType};
use selectors::Element as SelectorsElement;
use servo_arc::Arc as ServoArc;
-use style::dom::{TElement, TShadowRoot};
+use style::dom::{NodeInfo, TElement, TNode, TShadowRoot};
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use style::values::generics::counters::{Content, ContentItem};
@@ -28,15 +31,15 @@ use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside, DisplayOuts
/// A data structure used to pass and store related layout information together to
/// avoid having to repeat the same arguments in argument lists.
#[derive(Clone)]
-pub(crate) struct NodeAndStyleInfo<Node> {
- pub node: Node,
+pub(crate) struct NodeAndStyleInfo<'dom> {
+ pub node: ServoLayoutNode<'dom>,
pub pseudo_element_type: Option<PseudoElement>,
pub style: ServoArc<ComputedValues>,
}
-impl<'dom, Node: NodeExt<'dom>> NodeAndStyleInfo<Node> {
+impl<'dom> NodeAndStyleInfo<'dom> {
fn new_with_pseudo(
- node: Node,
+ node: ServoLayoutNode<'dom>,
pseudo_element_type: PseudoElement,
style: ServoArc<ComputedValues>,
) -> Self {
@@ -47,7 +50,7 @@ impl<'dom, Node: NodeExt<'dom>> NodeAndStyleInfo<Node> {
}
}
- pub(crate) fn new(node: Node, style: ServoArc<ComputedValues>) -> Self {
+ pub(crate) fn new(node: ServoLayoutNode<'dom>, style: ServoArc<ComputedValues>) -> Self {
Self {
node,
pseudo_element_type: None,
@@ -86,11 +89,8 @@ impl<'dom, Node: NodeExt<'dom>> NodeAndStyleInfo<Node> {
}
}
-impl<'dom, Node> From<&NodeAndStyleInfo<Node>> for BaseFragmentInfo
-where
- Node: NodeExt<'dom>,
-{
- fn from(info: &NodeAndStyleInfo<Node>) -> Self {
+impl<'dom> From<&NodeAndStyleInfo<'dom>> for BaseFragmentInfo {
+ fn from(info: &NodeAndStyleInfo<'dom>) -> Self {
let node = info.node;
let pseudo = info.pseudo_element_type;
let threadsafe_node = node.to_threadsafe();
@@ -174,29 +174,24 @@ pub(super) enum PseudoElementContentItem {
Replaced(ReplacedContents),
}
-pub(super) trait TraversalHandler<'dom, Node>
-where
- Node: 'dom,
-{
- fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>);
+pub(super) trait TraversalHandler<'dom> {
+ fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: Cow<'dom, str>);
/// Or pseudo-element
fn handle_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
);
}
-fn traverse_children_of<'dom, Node>(
- parent_element: Node,
+fn traverse_children_of<'dom>(
+ parent_element: ServoLayoutNode<'dom>,
context: &LayoutContext,
- handler: &mut impl TraversalHandler<'dom, Node>,
-) where
- Node: NodeExt<'dom>,
-{
+ handler: &mut impl TraversalHandler<'dom>,
+) {
traverse_eager_pseudo_element(PseudoElement::Before, parent_element, context, handler);
let is_text_input_element = matches!(
@@ -240,13 +235,11 @@ fn traverse_children_of<'dom, Node>(
traverse_eager_pseudo_element(PseudoElement::After, parent_element, context, handler);
}
-fn traverse_element<'dom, Node>(
- element: Node,
+fn traverse_element<'dom>(
+ element: ServoLayoutNode<'dom>,
context: &LayoutContext,
- handler: &mut impl TraversalHandler<'dom, Node>,
-) where
- Node: NodeExt<'dom>,
-{
+ handler: &mut impl TraversalHandler<'dom>,
+) {
// Clear any existing pseudo-element box slot, because markers are not handled like
// `::before`` and `::after`. They are processed during box tree creation.
element.unset_pseudo_element_box(PseudoElement::Marker);
@@ -286,14 +279,12 @@ fn traverse_element<'dom, Node>(
}
}
-fn traverse_eager_pseudo_element<'dom, Node>(
+fn traverse_eager_pseudo_element<'dom>(
pseudo_element_type: PseudoElement,
- node: Node,
+ node: ServoLayoutNode<'dom>,
context: &LayoutContext,
- handler: &mut impl TraversalHandler<'dom, Node>,
-) where
- Node: NodeExt<'dom>,
-{
+ handler: &mut impl TraversalHandler<'dom>,
+) {
assert!(pseudo_element_type.is_eager());
// First clear any old contents from the node.
@@ -329,14 +320,12 @@ fn traverse_eager_pseudo_element<'dom, Node>(
}
}
-fn traverse_pseudo_element_contents<'dom, Node>(
- info: &NodeAndStyleInfo<Node>,
+fn traverse_pseudo_element_contents<'dom>(
+ info: &NodeAndStyleInfo<'dom>,
context: &LayoutContext,
- handler: &mut impl TraversalHandler<'dom, Node>,
+ handler: &mut impl TraversalHandler<'dom>,
items: Vec<PseudoElementContentItem>,
-) where
- Node: NodeExt<'dom>,
-{
+) {
let mut anonymous_info = None;
for item in items {
match item {
@@ -396,14 +385,12 @@ impl std::convert::TryFrom<Contents> for NonReplacedContents {
}
impl NonReplacedContents {
- pub(crate) fn traverse<'dom, Node>(
+ pub(crate) fn traverse<'dom>(
self,
context: &LayoutContext,
- info: &NodeAndStyleInfo<Node>,
- handler: &mut impl TraversalHandler<'dom, Node>,
- ) where
- Node: NodeExt<'dom>,
- {
+ info: &NodeAndStyleInfo<'dom>,
+ handler: &mut impl TraversalHandler<'dom>,
+ ) {
match self {
NonReplacedContents::OfElement | NonReplacedContents::OfTextControl => {
traverse_children_of(info.node, context, handler)
@@ -427,14 +414,11 @@ where
}
/// <https://www.w3.org/TR/CSS2/generate.html#propdef-content>
-fn generate_pseudo_element_content<'dom, Node>(
+fn generate_pseudo_element_content(
pseudo_element_style: &ComputedValues,
- element: Node,
+ element: ServoLayoutNode<'_>,
context: &LayoutContext,
-) -> Vec<PseudoElementContentItem>
-where
- Node: NodeExt<'dom>,
-{
+) -> Vec<PseudoElementContentItem> {
match &pseudo_element_style.get_counters().content {
Content::Items(items) => {
let mut vec = vec![];
@@ -517,18 +501,14 @@ where
}
}
-pub enum ChildNodeIterator<Node> {
+pub enum ChildNodeIterator<'dom> {
/// Iterating over the children of a node
- Node(Option<Node>),
+ Node(Option<ServoLayoutNode<'dom>>),
/// Iterating over the assigned nodes of a `HTMLSlotElement`
- Slottables(<Vec<Node> as IntoIterator>::IntoIter),
+ Slottables(<Vec<ServoLayoutNode<'dom>> as IntoIterator>::IntoIter),
}
-#[allow(clippy::unnecessary_to_owned)] // Clippy is wrong.
-pub(crate) fn iter_child_nodes<'dom, Node>(parent: Node) -> ChildNodeIterator<Node>
-where
- Node: NodeExt<'dom>,
-{
+pub(crate) fn iter_child_nodes(parent: ServoLayoutNode<'_>) -> ChildNodeIterator<'_> {
if let Some(element) = parent.as_element() {
if let Some(shadow) = element.shadow_root() {
return iter_child_nodes(shadow.as_node());
@@ -536,6 +516,7 @@ where
let slotted_nodes = element.slotted_nodes();
if !slotted_nodes.is_empty() {
+ #[allow(clippy::unnecessary_to_owned)] // Clippy is wrong.
return ChildNodeIterator::Slottables(slotted_nodes.to_owned().into_iter());
}
}
@@ -544,11 +525,8 @@ where
ChildNodeIterator::Node(first)
}
-impl<'dom, Node> Iterator for ChildNodeIterator<Node>
-where
- Node: NodeExt<'dom>,
-{
- type Item = Node;
+impl<'dom> Iterator for ChildNodeIterator<'dom> {
+ type Item = ServoLayoutNode<'dom>;
fn next(&mut self) -> Option<Self::Item> {
match self {
@@ -562,4 +540,4 @@ where
}
}
-impl<'dom, Node> FusedIterator for ChildNodeIterator<Node> where Node: NodeExt<'dom> {}
+impl FusedIterator for ChildNodeIterator<'_> {}
diff --git a/components/layout/flexbox/mod.rs b/components/layout/flexbox/mod.rs
index e1f8213f1e9..27b69bf289f 100644
--- a/components/layout/flexbox/mod.rs
+++ b/components/layout/flexbox/mod.rs
@@ -17,7 +17,7 @@ use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::construct_modern::{ModernContainerBuilder, ModernItemKind};
use crate::context::LayoutContext;
-use crate::dom::{LayoutBox, NodeExt};
+use crate::dom::LayoutBox;
use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::{BaseFragmentInfo, Fragment};
@@ -98,9 +98,9 @@ pub(crate) struct FlexContainer {
}
impl FlexContainer {
- pub fn construct<'dom>(
+ pub fn construct(
context: &LayoutContext,
- info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
+ info: &NodeAndStyleInfo<'_>,
contents: NonReplacedContents,
propagated_data: PropagatedBoxTreeData,
) -> Self {
diff --git a/components/layout/flow/construct.rs b/components/layout/flow/construct.rs
index 5ed567f513b..a50464123bc 100644
--- a/components/layout/flow/construct.rs
+++ b/components/layout/flow/construct.rs
@@ -33,16 +33,13 @@ use crate::style_ext::{ComputedValuesExt, DisplayGeneratingBox, DisplayInside, D
use crate::table::{AnonymousTableContent, Table};
impl BlockFormattingContext {
- pub(crate) fn construct<'dom, Node>(
+ pub(crate) fn construct(
context: &LayoutContext,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'_>,
contents: NonReplacedContents,
propagated_data: PropagatedBoxTreeData,
is_list_item: bool,
- ) -> Self
- where
- Node: NodeExt<'dom>,
- {
+ ) -> Self {
Self::from_block_container(BlockContainer::construct(
context,
info,
@@ -61,8 +58,8 @@ impl BlockFormattingContext {
}
}
-struct BlockLevelJob<'dom, Node> {
- info: NodeAndStyleInfo<Node>,
+struct BlockLevelJob<'dom> {
+ info: NodeAndStyleInfo<'dom>,
box_slot: BoxSlot<'dom>,
propagated_data: PropagatedBoxTreeData,
kind: BlockLevelCreator,
@@ -111,12 +108,12 @@ enum IntermediateBlockContainer {
///
/// This builder starts from the first child of a given DOM node
/// and does a preorder traversal of all of its inclusive siblings.
-pub(crate) struct BlockContainerBuilder<'dom, 'style, Node> {
+pub(crate) struct BlockContainerBuilder<'dom, 'style> {
context: &'style LayoutContext<'style>,
/// This NodeAndStyleInfo contains the root node, the corresponding pseudo
/// content designator, and the block container style.
- info: &'style NodeAndStyleInfo<Node>,
+ info: &'style NodeAndStyleInfo<'dom>,
/// The list of block-level boxes to be built for the final block container.
///
@@ -131,7 +128,7 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style, Node> {
/// doesn't have a next sibling, we either reached the end of the container
/// root or there are ongoing inline-level boxes
/// (see `handle_block_level_element`).
- block_level_boxes: Vec<BlockLevelJob<'dom, Node>>,
+ block_level_boxes: Vec<BlockLevelJob<'dom>>,
/// Whether or not this builder has yet produced a block which would be
/// be considered the first line for the purposes of `text-indent`.
@@ -144,25 +141,22 @@ pub(crate) struct BlockContainerBuilder<'dom, 'style, Node> {
/// The [`NodeAndStyleInfo`] to use for anonymous block boxes pushed to the list of
/// block-level boxes, lazily initialized (see `end_ongoing_inline_formatting_context`).
- anonymous_box_info: Option<NodeAndStyleInfo<Node>>,
+ anonymous_box_info: Option<NodeAndStyleInfo<'dom>>,
/// A collection of content that is being added to an anonymous table. This is
/// composed of any sequence of internal table elements or table captions that
/// are found outside of a table.
- anonymous_table_content: Vec<AnonymousTableContent<'dom, Node>>,
+ anonymous_table_content: Vec<AnonymousTableContent<'dom>>,
}
impl BlockContainer {
- pub fn construct<'dom, Node>(
+ pub fn construct(
context: &LayoutContext,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'_>,
contents: NonReplacedContents,
propagated_data: PropagatedBoxTreeData,
is_list_item: bool,
- ) -> BlockContainer
- where
- Node: NodeExt<'dom>,
- {
+ ) -> BlockContainer {
let mut builder = BlockContainerBuilder::new(context, info, propagated_data);
if is_list_item {
@@ -186,13 +180,10 @@ impl BlockContainer {
}
}
-impl<'dom, 'style, Node> BlockContainerBuilder<'dom, 'style, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl<'dom, 'style> BlockContainerBuilder<'dom, 'style> {
pub(crate) fn new(
context: &'style LayoutContext,
- info: &'style NodeAndStyleInfo<Node>,
+ info: &'style NodeAndStyleInfo<'dom>,
propagated_data: PropagatedBoxTreeData,
) -> Self {
BlockContainerBuilder {
@@ -274,7 +265,7 @@ where
false => self.propagated_data,
};
- let contents: Vec<AnonymousTableContent<'dom, Node>> =
+ let contents: Vec<AnonymousTableContent<'dom>> =
self.anonymous_table_content.drain(..).collect();
let last_text = match contents.last() {
Some(AnonymousTableContent::Text(info, text)) => Some((info.clone(), text.clone())),
@@ -312,13 +303,10 @@ where
}
}
-impl<'dom, Node> TraversalHandler<'dom, Node> for BlockContainerBuilder<'dom, '_, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl<'dom> TraversalHandler<'dom> for BlockContainerBuilder<'dom, '_> {
fn handle_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -359,7 +347,7 @@ where
}
}
- fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {
+ fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: Cow<'dom, str>) {
if text.is_empty() {
return;
}
@@ -379,14 +367,11 @@ where
}
}
-impl<'dom, Node> BlockContainerBuilder<'dom, '_, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl<'dom> BlockContainerBuilder<'dom, '_> {
fn handle_list_item_marker_inside(
&mut self,
- marker_info: &NodeAndStyleInfo<Node>,
- container_info: &NodeAndStyleInfo<Node>,
+ marker_info: &NodeAndStyleInfo<'dom>,
+ container_info: &NodeAndStyleInfo<'dom>,
contents: Vec<crate::dom_traversal::PseudoElementContentItem>,
) {
// TODO: We do not currently support saving box slots for ::marker pseudo-elements
@@ -411,8 +396,8 @@ where
fn handle_list_item_marker_outside(
&mut self,
- marker_info: &NodeAndStyleInfo<Node>,
- container_info: &NodeAndStyleInfo<Node>,
+ marker_info: &NodeAndStyleInfo<'dom>,
+ container_info: &NodeAndStyleInfo<'dom>,
contents: Vec<crate::dom_traversal::PseudoElementContentItem>,
list_item_style: Arc<ComputedValues>,
) {
@@ -439,7 +424,7 @@ where
fn handle_inline_level_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display_inside: DisplayInside,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -497,7 +482,7 @@ where
fn handle_block_level_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display_inside: DisplayInside,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -565,7 +550,7 @@ where
fn handle_absolutely_positioned_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display_inside: DisplayInside,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -597,7 +582,7 @@ where
fn handle_float_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display_inside: DisplayInside,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -670,10 +655,7 @@ where
}
}
-impl<'dom, Node> BlockLevelJob<'dom, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl BlockLevelJob<'_> {
fn finish(self, context: &LayoutContext) -> ArcRefCell<BlockLevelBox> {
let info = &self.info;
let block_level_box = match self.kind {
@@ -747,14 +729,7 @@ where
}
impl IntermediateBlockContainer {
- fn finish<'dom, Node>(
- self,
- context: &LayoutContext,
- info: &NodeAndStyleInfo<Node>,
- ) -> BlockContainer
- where
- Node: NodeExt<'dom>,
- {
+ fn finish(self, context: &LayoutContext, info: &NodeAndStyleInfo<'_>) -> BlockContainer {
match self {
IntermediateBlockContainer::Deferred {
contents,
diff --git a/components/layout/flow/float.rs b/components/layout/flow/float.rs
index dbc50c07603..f1ae2b4459a 100644
--- a/components/layout/flow/float.rs
+++ b/components/layout/flow/float.rs
@@ -22,7 +22,6 @@ use style::properties::ComputedValues;
use style::values::computed::Clear as StyleClear;
use crate::context::LayoutContext;
-use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::{BoxFragment, CollapsedMargin};
@@ -885,9 +884,9 @@ impl FloatBandLink {
impl FloatBox {
/// Creates a new float box.
- pub fn construct<'dom>(
+ pub fn construct(
context: &LayoutContext,
- info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
+ info: &NodeAndStyleInfo<'_>,
display_inside: DisplayInside,
contents: Contents,
propagated_data: PropagatedBoxTreeData,
diff --git a/components/layout/flow/inline/construct.rs b/components/layout/flow/inline/construct.rs
index 61292701a9f..74b0cf4ea7d 100644
--- a/components/layout/flow/inline/construct.rs
+++ b/components/layout/flow/inline/construct.rs
@@ -17,7 +17,6 @@ use super::{InlineBox, InlineBoxIdentifier, InlineBoxes, InlineFormattingContext
use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
-use crate::dom::NodeExt;
use crate::dom_traversal::NodeAndStyleInfo;
use crate::flow::float::FloatBox;
use crate::formatting_contexts::IndependentFormattingContext;
@@ -225,11 +224,7 @@ impl InlineFormattingContextBuilder {
(identifier, block_in_inline_splits)
}
- pub(crate) fn push_text<'dom, Node: NodeExt<'dom>>(
- &mut self,
- text: Cow<'dom, str>,
- info: &NodeAndStyleInfo<Node>,
- ) {
+ pub(crate) fn push_text<'dom>(&mut self, text: Cow<'dom, str>, info: &NodeAndStyleInfo<'dom>) {
let white_space_collapse = info.style.clone_white_space_collapse();
let collapsed = WhitespaceCollapse::new(
text.chars(),
diff --git a/components/layout/flow/inline/inline_box.rs b/components/layout/flow/inline/inline_box.rs
index de79f876340..1c953c13074 100644
--- a/components/layout/flow/inline/inline_box.rs
+++ b/components/layout/flow/inline/inline_box.rs
@@ -12,7 +12,6 @@ use super::{InlineContainerState, InlineContainerStateFlags, inline_container_ne
use crate::ContainingBlock;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
-use crate::dom::NodeExt;
use crate::dom_traversal::NodeAndStyleInfo;
use crate::fragment_tree::BaseFragmentInfo;
use crate::layout_box_base::LayoutBoxBase;
@@ -35,7 +34,7 @@ pub(crate) struct InlineBox {
}
impl InlineBox {
- pub(crate) fn new<'dom, Node: NodeExt<'dom>>(info: &NodeAndStyleInfo<Node>) -> Self {
+ pub(crate) fn new(info: &NodeAndStyleInfo) -> Self {
Self {
base: LayoutBoxBase::new(info.into(), info.style.clone()),
// This will be assigned later, when the box is actually added to the IFC.
diff --git a/components/layout/flow/root.rs b/components/layout/flow/root.rs
index bb9ff1d337a..e813777b6fe 100644
--- a/components/layout/flow/root.rs
+++ b/components/layout/flow/root.rs
@@ -6,12 +6,13 @@ use app_units::Au;
use atomic_refcell::AtomicRef;
use compositing_traits::display_list::AxesScrollSensitivity;
use malloc_size_of_derive::MallocSizeOf;
+use script::layout_dom::ServoLayoutNode;
use script_layout_interface::wrapper_traits::{
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
use script_layout_interface::{LayoutElementType, LayoutNodeType};
use servo_arc::Arc;
-use style::dom::OpaqueNode;
+use style::dom::{NodeInfo, OpaqueNode, TNode};
use style::properties::ComputedValues;
use style::values::computed::Overflow;
use style_traits::CSSPixel;
@@ -47,10 +48,7 @@ pub struct BoxTree {
}
impl BoxTree {
- pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
- where
- Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
- {
+ pub fn construct(context: &LayoutContext, root_element: ServoLayoutNode<'_>) -> Self {
let boxes = construct_for_root_element(context, root_element);
// Zero box for `:root { display: none }`, one for the root element otherwise.
@@ -129,10 +127,7 @@ impl BoxTree {
/// * how intrinsic content sizes are computed eagerly makes it hard
/// to update those sizes for ancestors of the node from which we
/// made an incremental update.
- pub fn update<'dom, Node>(context: &LayoutContext, mut dirty_node: Node) -> bool
- where
- Node: 'dom + Copy + LayoutNode<'dom> + Send + Sync,
- {
+ pub fn update(context: &LayoutContext, mut dirty_node: ServoLayoutNode<'_>) -> bool {
#[allow(clippy::enum_variant_names)]
enum UpdatePoint {
AbsolutelyPositionedBlockLevelBox(ArcRefCell<BlockLevelBox>),
@@ -141,12 +136,9 @@ impl BoxTree {
AbsolutelyPositionedTaffyLevelBox(ArcRefCell<TaffyItemBox>),
}
- fn update_point<'dom, Node>(
- node: Node,
- ) -> Option<(Arc<ComputedValues>, DisplayInside, UpdatePoint)>
- where
- Node: NodeExt<'dom>,
- {
+ fn update_point(
+ node: ServoLayoutNode<'_>,
+ ) -> Option<(Arc<ComputedValues>, DisplayInside, UpdatePoint)> {
if !node.is_element() {
return None;
}
@@ -162,7 +154,7 @@ impl BoxTree {
return None;
}
- let layout_data = node.layout_data()?;
+ let layout_data = NodeExt::layout_data(&node)?;
if layout_data.pseudo_before_box.borrow().is_some() {
return None;
}
@@ -301,9 +293,9 @@ impl BoxTree {
}
}
-fn construct_for_root_element<'dom>(
+fn construct_for_root_element(
context: &LayoutContext,
- root_element: impl NodeExt<'dom>,
+ root_element: ServoLayoutNode<'_>,
) -> Vec<ArcRefCell<BlockLevelBox>> {
let info = NodeAndStyleInfo::new(root_element, root_element.style(context));
let box_style = info.style.get_box();
@@ -456,7 +448,7 @@ pub struct CanvasBackground {
}
impl CanvasBackground {
- fn for_root_element<'dom>(context: &LayoutContext, root_element: impl NodeExt<'dom>) -> Self {
+ fn for_root_element(context: &LayoutContext, root_element: ServoLayoutNode<'_>) -> Self {
let root_style = root_element.style(context);
let mut style = root_style;
diff --git a/components/layout/formatting_contexts.rs b/components/layout/formatting_contexts.rs
index 4982d0dae1a..04a8c60f692 100644
--- a/components/layout/formatting_contexts.rs
+++ b/components/layout/formatting_contexts.rs
@@ -4,12 +4,12 @@
use app_units::Au;
use malloc_size_of_derive::MallocSizeOf;
+use script::layout_dom::ServoLayoutElement;
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use crate::context::LayoutContext;
-use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::flexbox::FlexContainer;
use crate::flow::BlockFormattingContext;
@@ -69,9 +69,9 @@ impl Baselines {
}
impl IndependentFormattingContext {
- pub fn construct<'dom, Node: NodeExt<'dom>>(
+ pub fn construct(
context: &LayoutContext,
- node_and_style_info: &NodeAndStyleInfo<Node>,
+ node_and_style_info: &NodeAndStyleInfo,
display_inside: DisplayInside,
contents: Contents,
propagated_data: PropagatedBoxTreeData,
@@ -111,11 +111,11 @@ impl IndependentFormattingContext {
let table_grid_style = context
.shared_context()
.stylist
- .style_for_anonymous::<Node::ConcreteElement>(
- &context.shared_context().guards,
- &PseudoElement::ServoTableGrid,
- &node_and_style_info.style,
- );
+ .style_for_anonymous::<ServoLayoutElement>(
+ &context.shared_context().guards,
+ &PseudoElement::ServoTableGrid,
+ &node_and_style_info.style,
+ );
base_fragment_info.flags.insert(FragmentFlags::DO_NOT_PAINT);
IndependentNonReplacedContents::Table(Table::construct(
context,
diff --git a/components/layout/lists.rs b/components/layout/lists.rs
index d5a1f863865..8c653cb6858 100644
--- a/components/layout/lists.rs
+++ b/components/layout/lists.rs
@@ -7,18 +7,14 @@ use style::properties::style_structs;
use style::values::computed::Image;
use crate::context::LayoutContext;
-use crate::dom::NodeExt;
use crate::dom_traversal::{NodeAndStyleInfo, PseudoElementContentItem};
use crate::replaced::ReplacedContents;
/// <https://drafts.csswg.org/css-lists/#content-property>
-pub(crate) fn make_marker<'dom, Node>(
+pub(crate) fn make_marker<'dom>(
context: &LayoutContext,
- info: &NodeAndStyleInfo<Node>,
-) -> Option<(NodeAndStyleInfo<Node>, Vec<PseudoElementContentItem>)>
-where
- Node: NodeExt<'dom>,
-{
+ info: &NodeAndStyleInfo<'dom>,
+) -> Option<(NodeAndStyleInfo<'dom>, Vec<PseudoElementContentItem>)> {
let marker_info = info.pseudo(context, style::selector_parser::PseudoElement::Marker)?;
let style = &marker_info.style;
let list_style = style.get_list();
diff --git a/components/layout/positioned.rs b/components/layout/positioned.rs
index ff361396fa3..bb5386dc696 100644
--- a/components/layout/positioned.rs
+++ b/components/layout/positioned.rs
@@ -16,7 +16,6 @@ use style::values::specified::align::AlignFlags;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
-use crate::dom::NodeExt;
use crate::dom_traversal::{Contents, NodeAndStyleInfo};
use crate::formatting_contexts::{
IndependentFormattingContext, IndependentFormattingContextContents,
@@ -57,9 +56,9 @@ impl AbsolutelyPositionedBox {
Self { context }
}
- pub fn construct<'dom>(
+ pub fn construct(
context: &LayoutContext,
- node_info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
+ node_info: &NodeAndStyleInfo,
display_inside: DisplayInside,
contents: Contents,
) -> Self {
diff --git a/components/layout/query.rs b/components/layout/query.rs
index e78acdd0ca8..ca9db9ceaf1 100644
--- a/components/layout/query.rs
+++ b/components/layout/query.rs
@@ -9,6 +9,7 @@ use app_units::Au;
use euclid::default::{Point2D, Rect};
use euclid::{SideOffsets2D, Size2D};
use itertools::Itertools;
+use script::layout_dom::ServoLayoutNode;
use script_layout_interface::wrapper_traits::{
LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
@@ -20,7 +21,7 @@ use style::computed_values::position::T as Position;
use style::computed_values::visibility::T as Visibility;
use style::computed_values::white_space_collapse::T as WhiteSpaceCollapseValue;
use style::context::{QuirksMode, SharedStyleContext, StyleContext, ThreadLocalStyleContext};
-use style::dom::{OpaqueNode, TElement};
+use style::dom::{NodeInfo, OpaqueNode, TElement, TNode};
use style::properties::style_structs::Font;
use style::properties::{
ComputedValues, Importance, LonghandId, PropertyDeclarationBlock, PropertyDeclarationId,
@@ -46,7 +47,7 @@ use crate::fragment_tree::{
};
use crate::taffy::SpecificTaffyGridInfo;
-pub fn process_content_box_request<'dom>(node: impl LayoutNode<'dom> + 'dom) -> Option<Rect<Au>> {
+pub fn process_content_box_request(node: ServoLayoutNode<'_>) -> Option<Rect<Au>> {
let rects: Vec<_> = node
.fragments_for_pseudo(None)
.iter()
@@ -61,7 +62,7 @@ pub fn process_content_box_request<'dom>(node: impl LayoutNode<'dom> + 'dom) ->
}))
}
-pub fn process_content_boxes_request<'dom>(node: impl LayoutNode<'dom> + 'dom) -> Vec<Rect<Au>> {
+pub fn process_content_boxes_request(node: ServoLayoutNode<'_>) -> Vec<Rect<Au>> {
node.fragments_for_pseudo(None)
.iter()
.filter_map(Fragment::cumulative_border_box_rect)
@@ -69,7 +70,7 @@ pub fn process_content_boxes_request<'dom>(node: impl LayoutNode<'dom> + 'dom) -
.collect()
}
-pub fn process_client_rect_request<'dom>(node: impl LayoutNode<'dom> + 'dom) -> Rect<i32> {
+pub fn process_client_rect_request(node: ServoLayoutNode<'_>) -> Rect<i32> {
node.fragments_for_pseudo(None)
.first()
.map(Fragment::client_rect)
@@ -77,8 +78,8 @@ pub fn process_client_rect_request<'dom>(node: impl LayoutNode<'dom> + 'dom) ->
}
/// <https://drafts.csswg.org/cssom-view/#scrolling-area>
-pub fn process_node_scroll_area_request<'dom>(
- requested_node: Option<impl LayoutNode<'dom> + 'dom>,
+pub fn process_node_scroll_area_request(
+ requested_node: Option<ServoLayoutNode<'_>>,
fragment_tree: Option<Arc<FragmentTree>>,
) -> Rect<i32> {
let Some(tree) = fragment_tree else {
@@ -105,9 +106,9 @@ pub fn process_node_scroll_area_request<'dom>(
/// Return the resolved value of property for a given (pseudo)element.
/// <https://drafts.csswg.org/cssom/#resolved-value>
-pub fn process_resolved_style_request<'dom>(
+pub fn process_resolved_style_request(
context: &SharedStyleContext,
- node: impl LayoutNode<'dom> + 'dom,
+ node: ServoLayoutNode<'_>,
pseudo: &Option<PseudoElement>,
property: &PropertyId,
) -> String {
@@ -361,9 +362,9 @@ fn resolve_grid_template(
}
}
-pub fn process_resolved_style_request_for_unstyled_node<'dom>(
+pub fn process_resolved_style_request_for_unstyled_node(
context: &SharedStyleContext,
- node: impl LayoutNode<'dom>,
+ node: ServoLayoutNode<'_>,
pseudo: &Option<PseudoElement>,
property: &PropertyId,
) -> String {
@@ -434,9 +435,7 @@ struct OffsetParentFragments {
}
/// <https://www.w3.org/TR/2016/WD-cssom-view-1-20160317/#dom-htmlelement-offsetparent>
-fn offset_parent_fragments<'dom>(
- node: impl LayoutNode<'dom> + 'dom,
-) -> Option<OffsetParentFragments> {
+fn offset_parent_fragments(node: ServoLayoutNode<'_>) -> Option<OffsetParentFragments> {
// 1. If any of the following holds true return null and terminate this algorithm:
// * The element does not have an associated CSS layout box.
// * The element is the root element.
@@ -498,9 +497,7 @@ fn offset_parent_fragments<'dom>(
}
#[inline]
-pub fn process_offset_parent_query<'dom>(
- node: impl LayoutNode<'dom> + 'dom,
-) -> Option<OffsetParentResponse> {
+pub fn process_offset_parent_query(node: ServoLayoutNode<'_>) -> Option<OffsetParentResponse> {
// Only consider the first fragment of the node found as per a
// possible interpretation of the specification: "[...] return the
// y-coordinate of the top border edge of the first CSS layout box
@@ -580,7 +577,7 @@ pub fn process_offset_parent_query<'dom>(
}
/// <https://html.spec.whatwg.org/multipage/#get-the-text-steps>
-pub fn get_the_text_steps<'dom>(node: impl LayoutNode<'dom>) -> String {
+pub fn get_the_text_steps(node: ServoLayoutNode<'_>) -> String {
// Step 1: If element is not being rendered or if the user agent is a non-CSS user agent, then
// return element's descendant text content.
// This is taken care of in HTMLElemnent code
@@ -668,8 +665,8 @@ impl Default for RenderedTextCollectionState {
}
/// <https://html.spec.whatwg.org/multipage/#rendered-text-collection-steps>
-fn rendered_text_collection_steps<'dom>(
- node: impl LayoutNode<'dom>,
+fn rendered_text_collection_steps(
+ node: ServoLayoutNode<'_>,
state: &mut RenderedTextCollectionState,
) -> Vec<InnerOrOuterTextItem> {
// Step 1. Let items be the result of running the rendered text collection
diff --git a/components/layout/replaced.rs b/components/layout/replaced.rs
index bbebc57aa97..0cc95c1a87d 100644
--- a/components/layout/replaced.rs
+++ b/components/layout/replaced.rs
@@ -13,10 +13,12 @@ use euclid::{Scale, Size2D};
use malloc_size_of_derive::MallocSizeOf;
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
use pixels::Image;
+use script::layout_dom::ServoLayoutNode;
use script_layout_interface::IFrameSize;
use servo_arc::Arc as ServoArc;
use style::Zero;
use style::computed_values::object_fit::T as ObjectFit;
+use style::dom::TNode;
use style::logical_geometry::{Direction, WritingMode};
use style::properties::ComputedValues;
use style::servo::url::ComputedUrl;
@@ -120,7 +122,7 @@ pub(crate) enum ReplacedContentKind {
}
impl ReplacedContents {
- pub fn for_element<'dom>(element: impl NodeExt<'dom>, context: &LayoutContext) -> Option<Self> {
+ pub fn for_element(element: ServoLayoutNode<'_>, context: &LayoutContext) -> Option<Self> {
if let Some(ref data_attribute_string) = element.as_typeless_object_with_data_attribute() {
if let Some(url) = try_to_parse_image_data_url(data_attribute_string) {
return Self::from_image_url(
@@ -184,8 +186,8 @@ impl ReplacedContents {
})
}
- pub fn from_image_url<'dom>(
- element: impl NodeExt<'dom>,
+ pub fn from_image_url(
+ element: ServoLayoutNode<'_>,
context: &LayoutContext,
image_url: &ComputedUrl,
) -> Option<Self> {
@@ -213,8 +215,8 @@ impl ReplacedContents {
None
}
- pub fn from_image<'dom>(
- element: impl NodeExt<'dom>,
+ pub fn from_image(
+ element: ServoLayoutNode<'_>,
context: &LayoutContext,
image: &ComputedImage,
) -> Option<Self> {
diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs
index 56e11320be4..8370e9aeb89 100644
--- a/components/layout/table/construct.rs
+++ b/components/layout/table/construct.rs
@@ -8,7 +8,7 @@ use std::iter::repeat;
use atomic_refcell::AtomicRef;
use log::warn;
-use script_layout_interface::wrapper_traits::ThreadSafeLayoutNode;
+use script_layout_interface::wrapper_traits::{LayoutNode, ThreadSafeLayoutNode};
use servo_arc::Arc;
use style::properties::ComputedValues;
use style::properties::style_structs::Font;
@@ -22,7 +22,7 @@ use super::{
use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::context::LayoutContext;
-use crate::dom::{BoxSlot, LayoutBox, NodeExt};
+use crate::dom::{BoxSlot, LayoutBox};
use crate::dom_traversal::{Contents, NodeAndStyleInfo, NonReplacedContents, TraversalHandler};
use crate::flow::{BlockContainerBuilder, BlockFormattingContext};
use crate::formatting_contexts::{
@@ -50,17 +50,17 @@ impl ResolvedSlotAndLocation<'_> {
}
}
-pub(crate) enum AnonymousTableContent<'dom, Node> {
- Text(NodeAndStyleInfo<Node>, Cow<'dom, str>),
+pub(crate) enum AnonymousTableContent<'dom> {
+ Text(NodeAndStyleInfo<'dom>, Cow<'dom, str>),
Element {
- info: NodeAndStyleInfo<Node>,
+ info: NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
},
}
-impl<Node> AnonymousTableContent<'_, Node> {
+impl AnonymousTableContent<'_> {
fn is_whitespace_only(&self) -> bool {
match self {
Self::Element { .. } => false,
@@ -74,9 +74,9 @@ impl<Node> AnonymousTableContent<'_, Node> {
}
impl Table {
- pub(crate) fn construct<'dom>(
+ pub(crate) fn construct(
context: &LayoutContext,
- info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
+ info: &NodeAndStyleInfo,
grid_style: Arc<ComputedValues>,
contents: NonReplacedContents,
propagated_data: PropagatedBoxTreeData,
@@ -91,15 +91,12 @@ impl Table {
traversal.finish()
}
- pub(crate) fn construct_anonymous<'dom, Node>(
+ pub(crate) fn construct_anonymous<'dom>(
context: &LayoutContext,
- parent_info: &NodeAndStyleInfo<Node>,
- contents: Vec<AnonymousTableContent<'dom, Node>>,
+ parent_info: &NodeAndStyleInfo<'dom>,
+ contents: Vec<AnonymousTableContent<'dom>>,
propagated_data: PropagatedBoxTreeData,
- ) -> (NodeAndStyleInfo<Node>, IndependentFormattingContext)
- where
- Node: crate::dom::NodeExt<'dom>,
- {
+ ) -> (NodeAndStyleInfo<'dom>, IndependentFormattingContext) {
let table_info = parent_info
.pseudo(context, PseudoElement::ServoAnonymousTable)
.expect("Should never fail to create anonymous table info.");
@@ -645,9 +642,9 @@ impl TableBuilder {
}
}
-pub(crate) struct TableBuilderTraversal<'style, 'dom, Node> {
+pub(crate) struct TableBuilderTraversal<'style, 'dom> {
context: &'style LayoutContext<'style>,
- info: &'style NodeAndStyleInfo<Node>,
+ info: &'style NodeAndStyleInfo<'dom>,
/// The value of the [`PropagatedBoxTreeData`] to use, either for the row group
/// if processing one or for the table itself if outside a row group.
@@ -657,19 +654,16 @@ pub(crate) struct TableBuilderTraversal<'style, 'dom, Node> {
/// into another struct so that we can write unit tests against the builder.
builder: TableBuilder,
- current_anonymous_row_content: Vec<AnonymousTableContent<'dom, Node>>,
+ current_anonymous_row_content: Vec<AnonymousTableContent<'dom>>,
/// The index of the current row group, if there is one.
current_row_group_index: Option<usize>,
}
-impl<'style, 'dom, Node> TableBuilderTraversal<'style, 'dom, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl<'style, 'dom> TableBuilderTraversal<'style, 'dom> {
pub(crate) fn new(
context: &'style LayoutContext<'style>,
- info: &'style NodeAndStyleInfo<Node>,
+ info: &'style NodeAndStyleInfo<'dom>,
grid_style: Arc<ComputedValues>,
propagated_data: PropagatedBoxTreeData,
) -> Self {
@@ -745,11 +739,8 @@ where
}
}
-impl<'dom, Node: 'dom> TraversalHandler<'dom, Node> for TableBuilderTraversal<'_, 'dom, Node>
-where
- Node: NodeExt<'dom>,
-{
- fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {
+impl<'dom> TraversalHandler<'dom> for TableBuilderTraversal<'_, 'dom> {
+ fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: Cow<'dom, str>) {
self.current_anonymous_row_content
.push(AnonymousTableContent::Text(info.clone(), text));
}
@@ -757,7 +748,7 @@ where
/// <https://html.spec.whatwg.org/multipage/#forming-a-table>
fn handle_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -916,26 +907,23 @@ where
}
}
-struct TableRowBuilder<'style, 'builder, 'dom, 'a, Node> {
- table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom, Node>,
+struct TableRowBuilder<'style, 'builder, 'dom, 'a> {
+ table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom>,
/// The [`NodeAndStyleInfo`] of this table row, which we use to
/// construct anonymous table cells.
- info: &'a NodeAndStyleInfo<Node>,
+ info: &'a NodeAndStyleInfo<'dom>,
- current_anonymous_cell_content: Vec<AnonymousTableContent<'dom, Node>>,
+ current_anonymous_cell_content: Vec<AnonymousTableContent<'dom>>,
/// The [`PropagatedBoxTreeData`] to use for all children of this row.
propagated_data: PropagatedBoxTreeData,
}
-impl<'style, 'builder, 'dom, 'a, Node: 'dom> TableRowBuilder<'style, 'builder, 'dom, 'a, Node>
-where
- Node: NodeExt<'dom>,
-{
+impl<'style, 'builder, 'dom, 'a> TableRowBuilder<'style, 'builder, 'dom, 'a> {
fn new(
- table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom, Node>,
- info: &'a NodeAndStyleInfo<Node>,
+ table_traversal: &'builder mut TableBuilderTraversal<'style, 'dom>,
+ info: &'a NodeAndStyleInfo<'dom>,
propagated_data: PropagatedBoxTreeData,
) -> Self {
table_traversal.builder.start_row();
@@ -996,11 +984,8 @@ where
}
}
-impl<'dom, Node: 'dom> TraversalHandler<'dom, Node> for TableRowBuilder<'_, '_, 'dom, '_, Node>
-where
- Node: NodeExt<'dom>,
-{
- fn handle_text(&mut self, info: &NodeAndStyleInfo<Node>, text: Cow<'dom, str>) {
+impl<'dom> TraversalHandler<'dom> for TableRowBuilder<'_, '_, 'dom, '_> {
+ fn handle_text(&mut self, info: &NodeAndStyleInfo<'dom>, text: Cow<'dom, str>) {
self.current_anonymous_cell_content
.push(AnonymousTableContent::Text(info.clone(), text));
}
@@ -1008,7 +993,7 @@ where
/// <https://html.spec.whatwg.org/multipage/#algorithm-for-processing-rows>
fn handle_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -1091,14 +1076,11 @@ struct TableColumnGroupBuilder {
columns: Vec<ArcRefCell<TableTrack>>,
}
-impl<'dom, Node: 'dom> TraversalHandler<'dom, Node> for TableColumnGroupBuilder
-where
- Node: NodeExt<'dom>,
-{
- fn handle_text(&mut self, _info: &NodeAndStyleInfo<Node>, _text: Cow<'dom, str>) {}
+impl<'dom> TraversalHandler<'dom> for TableColumnGroupBuilder {
+ fn handle_text(&mut self, _info: &NodeAndStyleInfo<'dom>, _text: Cow<'dom, str>) {}
fn handle_element(
&mut self,
- info: &NodeAndStyleInfo<Node>,
+ info: &NodeAndStyleInfo<'dom>,
display: DisplayGeneratingBox,
_contents: Contents,
box_slot: BoxSlot<'dom>,
@@ -1134,9 +1116,9 @@ impl From<DisplayLayoutInternal> for TableTrackGroupType {
}
}
-fn add_column<'dom, Node: NodeExt<'dom>>(
+fn add_column(
collection: &mut Vec<ArcRefCell<TableTrack>>,
- column_info: &NodeAndStyleInfo<Node>,
+ column_info: &NodeAndStyleInfo,
group_index: Option<usize>,
is_anonymous: bool,
) -> ArcRefCell<TableTrack> {
diff --git a/components/layout/taffy/mod.rs b/components/layout/taffy/mod.rs
index b1ff753ea78..50873fc3e66 100644
--- a/components/layout/taffy/mod.rs
+++ b/components/layout/taffy/mod.rs
@@ -15,7 +15,7 @@ use crate::PropagatedBoxTreeData;
use crate::cell::ArcRefCell;
use crate::construct_modern::{ModernContainerBuilder, ModernItemKind};
use crate::context::LayoutContext;
-use crate::dom::{LayoutBox, NodeExt};
+use crate::dom::LayoutBox;
use crate::dom_traversal::{NodeAndStyleInfo, NonReplacedContents};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::Fragment;
@@ -29,9 +29,9 @@ pub(crate) struct TaffyContainer {
}
impl TaffyContainer {
- pub fn construct<'dom>(
+ pub fn construct(
context: &LayoutContext,
- info: &NodeAndStyleInfo<impl NodeExt<'dom>>,
+ info: &NodeAndStyleInfo,
contents: NonReplacedContents,
propagated_data: PropagatedBoxTreeData,
) -> Self {
diff --git a/components/malloc_size_of/Cargo.toml b/components/malloc_size_of/Cargo.toml
index f6f25075ed6..a24bc70a211 100644
--- a/components/malloc_size_of/Cargo.toml
+++ b/components/malloc_size_of/Cargo.toml
@@ -35,6 +35,7 @@ tokio = { workspace = true, features = ["sync"] }
unicode-bidi = { workspace = true }
unicode-script = { workspace = true }
url = { workspace = true }
+urlpattern = { workspace = true }
uuid = { workspace = true }
webrender_api = { workspace = true }
wr_malloc_size_of = { workspace = true }
diff --git a/components/malloc_size_of/lib.rs b/components/malloc_size_of/lib.rs
index 52523af7cb1..accd0aaf243 100644
--- a/components/malloc_size_of/lib.rs
+++ b/components/malloc_size_of/lib.rs
@@ -753,6 +753,7 @@ malloc_size_of_is_0!(style::queries::values::PrefersColorScheme);
malloc_size_of_is_0!(taffy::Layout);
malloc_size_of_is_0!(unicode_bidi::Level);
malloc_size_of_is_0!(unicode_script::Script);
+malloc_size_of_is_0!(urlpattern::UrlPattern);
macro_rules! malloc_size_of_is_webrender_malloc_size_of(
($($ty:ty),+) => (
diff --git a/components/net/fetch/methods.rs b/components/net/fetch/methods.rs
index b1ad01b81e0..65c173fce3b 100644
--- a/components/net/fetch/methods.rs
+++ b/components/net/fetch/methods.rs
@@ -737,7 +737,7 @@ impl RangeRequestBounds {
RangeRequestBounds::Final(pos) => {
if let Some(len) = len {
if pos.start <= len as i64 {
- return Ok(pos.clone());
+ return Ok(*pos);
}
}
Err("Tried to process RangeRequestBounds::Final without len")
diff --git a/components/script/Cargo.toml b/components/script/Cargo.toml
index 1aa821cdbd3..ea1ec52f911 100644
--- a/components/script/Cargo.toml
+++ b/components/script/Cargo.toml
@@ -132,6 +132,7 @@ tracing = { workspace = true, optional = true }
unicode-bidi = { workspace = true }
unicode-segmentation = { workspace = true }
url = { workspace = true }
+urlpattern = { workspace = true }
utf-8 = "0.7"
uuid = { workspace = true, features = ["serde"] }
webdriver = { workspace = true }
diff --git a/components/script/dom/blob.rs b/components/script/dom/blob.rs
index 27aa382c3fc..c5c5c480707 100644
--- a/components/script/dom/blob.rs
+++ b/components/script/dom/blob.rs
@@ -7,7 +7,7 @@ use std::ptr;
use std::rc::Rc;
use base::id::{BlobId, BlobIndex};
-use constellation_traits::BlobImpl;
+use constellation_traits::{BlobData, BlobImpl};
use dom_struct::dom_struct;
use encoding_rs::UTF_8;
use js::jsapi::JSObject;
@@ -33,7 +33,7 @@ use crate::dom::readablestream::ReadableStream;
use crate::realms::{AlreadyInRealm, InRealm};
use crate::script_runtime::CanGc;
-// https://w3c.github.io/FileAPI/#blob
+/// <https://w3c.github.io/FileAPI/#dfn-Blob>
#[dom_struct]
pub(crate) struct Blob {
reflector_: Reflector,
@@ -198,7 +198,7 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
self.get_stream(can_gc)
}
- // https://w3c.github.io/FileAPI/#slice-method-algo
+ /// <https://w3c.github.io/FileAPI/#slice-method-algo>
fn Slice(
&self,
start: Option<i64>,
@@ -206,11 +206,24 @@ impl BlobMethods<crate::DomTypeHolder> for Blob {
content_type: Option<DOMString>,
can_gc: CanGc,
) -> DomRoot<Blob> {
- let type_string =
- normalize_type_string(content_type.unwrap_or(DOMString::from("")).as_ref());
- let rel_pos = RelativePos::from_opts(start, end);
- let blob_impl = BlobImpl::new_sliced(rel_pos, self.blob_id, type_string);
- Blob::new(&self.global(), blob_impl, can_gc)
+ let global = self.global();
+ let type_string = normalize_type_string(&content_type.unwrap_or_default());
+
+ // If our parent is already a sliced blob then we reference the data from the grandparent instead,
+ // to keep the blob ancestry chain short.
+ let (parent, range) = match *global.get_blob_data(&self.blob_id) {
+ BlobData::Sliced(grandparent, parent_range) => {
+ let range = RelativePos {
+ start: parent_range.start + start.unwrap_or_default(),
+ end: end.map(|end| end + parent_range.start).or(parent_range.end),
+ };
+ (grandparent, range)
+ },
+ _ => (self.blob_id, RelativePos::from_opts(start, end)),
+ };
+
+ let blob_impl = BlobImpl::new_sliced(range, parent, type_string);
+ Blob::new(&global, blob_impl, can_gc)
}
// https://w3c.github.io/FileAPI/#text-method-algo
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 527d03eed4e..98c4c3ed53d 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -2,7 +2,7 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-use std::cell::{Cell, OnceCell};
+use std::cell::{Cell, OnceCell, Ref};
use std::collections::hash_map::Entry;
use std::collections::{HashMap, VecDeque};
use std::ops::Index;
@@ -1821,12 +1821,8 @@ impl GlobalScope {
/// In the case of a File-backed blob, this might incur synchronous read and caching.
pub(crate) fn get_blob_bytes(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
let parent = {
- let blob_state = self.blob_state.borrow();
- let blob_info = blob_state
- .get(blob_id)
- .expect("get_blob_bytes for an unknown blob.");
- match blob_info.blob_impl.blob_data() {
- BlobData::Sliced(parent, rel_pos) => Some((*parent, rel_pos.clone())),
+ match *self.get_blob_data(blob_id) {
+ BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
_ => None,
}
};
@@ -1840,14 +1836,24 @@ impl GlobalScope {
}
}
+ /// Retrieve information about a specific blob from the blob store
+ ///
+ /// # Panics
+ /// This function panics if there is no blob with the given ID.
+ pub(crate) fn get_blob_data<'a>(&'a self, blob_id: &BlobId) -> Ref<'a, BlobData> {
+ Ref::map(self.blob_state.borrow(), |blob_state| {
+ blob_state
+ .get(blob_id)
+ .expect("get_blob_impl called for a unknown blob")
+ .blob_impl
+ .blob_data()
+ })
+ }
+
/// Get bytes from a non-sliced blob
fn get_blob_bytes_non_sliced(&self, blob_id: &BlobId) -> Result<Vec<u8>, ()> {
- let blob_state = self.blob_state.borrow();
- let blob_info = blob_state
- .get(blob_id)
- .expect("get_blob_bytes_non_sliced called for a unknown blob.");
- match blob_info.blob_impl.blob_data() {
- BlobData::File(f) => {
+ match *self.get_blob_data(blob_id) {
+ BlobData::File(ref f) => {
let (buffer, is_new_buffer) = match f.get_cache() {
Some(bytes) => (bytes, false),
None => {
@@ -1863,7 +1869,7 @@ impl GlobalScope {
Ok(buffer)
},
- BlobData::Memory(s) => Ok(s.clone()),
+ BlobData::Memory(ref s) => Ok(s.clone()),
BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
}
}
@@ -1876,12 +1882,8 @@ impl GlobalScope {
/// TODO: merge with `get_blob_bytes` by way of broader integration with blob streams.
fn get_blob_bytes_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
let parent = {
- let blob_state = self.blob_state.borrow();
- let blob_info = blob_state
- .get(blob_id)
- .expect("get_blob_bytes_or_file_id for an unknown blob.");
- match blob_info.blob_impl.blob_data() {
- BlobData::Sliced(parent, rel_pos) => Some((*parent, rel_pos.clone())),
+ match *self.get_blob_data(blob_id) {
+ BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
_ => None,
}
};
@@ -1906,16 +1908,12 @@ impl GlobalScope {
/// tweaked for integration with streams.
/// TODO: merge with `get_blob_bytes` by way of broader integration with blob streams.
fn get_blob_bytes_non_sliced_or_file_id(&self, blob_id: &BlobId) -> BlobResult {
- let blob_state = self.blob_state.borrow();
- let blob_info = blob_state
- .get(blob_id)
- .expect("get_blob_bytes_non_sliced_or_file_id called for a unknown blob.");
- match blob_info.blob_impl.blob_data() {
- BlobData::File(f) => match f.get_cache() {
+ match *self.get_blob_data(blob_id) {
+ BlobData::File(ref f) => match f.get_cache() {
Some(bytes) => BlobResult::Bytes(bytes.clone()),
None => BlobResult::File(f.get_id(), f.get_size() as usize),
},
- BlobData::Memory(s) => BlobResult::Bytes(s.clone()),
+ BlobData::Memory(ref s) => BlobResult::Bytes(s.clone()),
BlobData::Sliced(_, _) => panic!("This blob doesn't have a parent."),
}
}
@@ -1931,39 +1929,27 @@ impl GlobalScope {
/// <https://w3c.github.io/FileAPI/#dfn-size>
pub(crate) fn get_blob_size(&self, blob_id: &BlobId) -> u64 {
- let blob_state = self.blob_state.borrow();
let parent = {
- let blob_info = blob_state
- .get(blob_id)
- .expect("get_blob_size called for a unknown blob.");
- match blob_info.blob_impl.blob_data() {
- BlobData::Sliced(parent, rel_pos) => Some((*parent, rel_pos.clone())),
+ match *self.get_blob_data(blob_id) {
+ BlobData::Sliced(parent, rel_pos) => Some((parent, rel_pos)),
_ => None,
}
};
match parent {
Some((parent_id, rel_pos)) => {
- let parent_info = blob_state
- .get(&parent_id)
- .expect("Parent of blob whose size is unknown.");
- let parent_size = match parent_info.blob_impl.blob_data() {
- BlobData::File(f) => f.get_size(),
- BlobData::Memory(v) => v.len() as u64,
+ let parent_size = match *self.get_blob_data(&parent_id) {
+ BlobData::File(ref f) => f.get_size(),
+ BlobData::Memory(ref v) => v.len() as u64,
BlobData::Sliced(_, _) => panic!("Blob ancestry should be only one level."),
};
rel_pos.to_abs_range(parent_size as usize).len() as u64
},
- None => {
- let blob_info = blob_state
- .get(blob_id)
- .expect("Blob whose size is unknown.");
- match blob_info.blob_impl.blob_data() {
- BlobData::File(f) => f.get_size(),
- BlobData::Memory(v) => v.len() as u64,
- BlobData::Sliced(_, _) => {
- panic!("It was previously checked that this blob does not have a parent.")
- },
- }
+ None => match *self.get_blob_data(blob_id) {
+ BlobData::File(ref f) => f.get_size(),
+ BlobData::Memory(ref v) => v.len() as u64,
+ BlobData::Sliced(_, _) => {
+ panic!("It was previously checked that this blob does not have a parent.")
+ },
},
}
}
@@ -1979,7 +1965,7 @@ impl GlobalScope {
blob_info.has_url = true;
match blob_info.blob_impl.blob_data() {
- BlobData::Sliced(parent, rel_pos) => Some((*parent, rel_pos.clone())),
+ BlobData::Sliced(parent, rel_pos) => Some((*parent, *rel_pos)),
_ => None,
}
};
@@ -2020,12 +2006,8 @@ impl GlobalScope {
let origin = get_blob_origin(&self.get_url());
let (tx, rx) = profile_ipc::channel(self.time_profiler_chan().clone()).unwrap();
- let msg = FileManagerThreadMsg::AddSlicedURLEntry(
- *parent_file_id,
- rel_pos.clone(),
- tx,
- origin.clone(),
- );
+ let msg =
+ FileManagerThreadMsg::AddSlicedURLEntry(*parent_file_id, *rel_pos, tx, origin.clone());
self.send_to_file_manager(msg);
match rx.recv().expect("File manager thread is down.") {
Ok(new_id) => {
diff --git a/components/script/dom/servoparser/html.rs b/components/script/dom/servoparser/html.rs
index 07848c87678..7fd0429612a 100644
--- a/components/script/dom/servoparser/html.rs
+++ b/components/script/dom/servoparser/html.rs
@@ -302,11 +302,10 @@ pub(crate) fn serialize_html_fragment<S: Serializer>(
serializer.write_processing_instruction(pi.target(), &data)?;
},
- NodeTypeId::DocumentFragment(_) => {},
+ NodeTypeId::DocumentFragment(_) | NodeTypeId::Attr => {},
NodeTypeId::Document(_) => panic!("Can't serialize Document node itself"),
NodeTypeId::Element(_) => panic!("Element shouldn't appear here"),
- NodeTypeId::Attr => panic!("Attr shouldn't appear here"),
},
SerializationCommand::SerializeShadowRoot(shadow_root) => {
// Shadow roots are serialized as template elements with a fixed set of
diff --git a/components/script/dom/urlpattern.rs b/components/script/dom/urlpattern.rs
new file mode 100644
index 00000000000..c811d3a9a70
--- /dev/null
+++ b/components/script/dom/urlpattern.rs
@@ -0,0 +1,204 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
+
+use dom_struct::dom_struct;
+use js::rust::HandleObject;
+use script_bindings::codegen::GenericUnionTypes::USVStringOrURLPatternInit;
+use script_bindings::error::{Error, Fallible};
+use script_bindings::reflector::Reflector;
+use script_bindings::root::DomRoot;
+use script_bindings::script_runtime::CanGc;
+use script_bindings::str::USVString;
+
+use crate::dom::bindings::codegen::Bindings::URLPatternBinding;
+use crate::dom::bindings::codegen::Bindings::URLPatternBinding::URLPatternMethods;
+use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
+use crate::dom::globalscope::GlobalScope;
+
+/// <https://urlpattern.spec.whatwg.org/#urlpattern>
+#[dom_struct]
+pub(crate) struct URLPattern {
+ reflector: Reflector,
+
+ /// <https://urlpattern.spec.whatwg.org/#urlpattern-associated-url-pattern>
+ #[no_trace]
+ associated_url_pattern: urlpattern::UrlPattern,
+}
+
+impl URLPattern {
+ #[cfg_attr(crown, allow(crown::unrooted_must_root))]
+ fn new_inherited(associated_url_pattern: urlpattern::UrlPattern) -> URLPattern {
+ URLPattern {
+ reflector: Reflector::new(),
+ associated_url_pattern,
+ }
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#urlpattern-initialize>
+ pub(crate) fn initialize(
+ global: &GlobalScope,
+ proto: Option<HandleObject>,
+ input: USVStringOrURLPatternInit,
+ base_url: Option<USVString>,
+ options: &URLPatternBinding::URLPatternOptions,
+ can_gc: CanGc,
+ ) -> Fallible<DomRoot<URLPattern>> {
+ // The section below converts from servos types to the types used in the urlpattern crate
+ let base_url = base_url.map(|usv_string| usv_string.0);
+ let input = bindings_to_third_party::map_urlpattern_input(input, base_url.clone());
+ let options = urlpattern::UrlPatternOptions {
+ ignore_case: options.ignoreCase,
+ };
+
+ // Parse and initialize the URL pattern.
+ let pattern_init =
+ urlpattern::quirks::process_construct_pattern_input(input, base_url.as_deref())
+ .map_err(|error| Error::Type(format!("{error}")))?;
+
+ let pattern = urlpattern::UrlPattern::parse(pattern_init, options)
+ .map_err(|error| Error::Type(format!("{error}")))?;
+
+ let url_pattern = reflect_dom_object_with_proto(
+ Box::new(URLPattern::new_inherited(pattern)),
+ global,
+ proto,
+ can_gc,
+ );
+ Ok(url_pattern)
+ }
+}
+
+impl URLPatternMethods<crate::DomTypeHolder> for URLPattern {
+ // <https://urlpattern.spec.whatwg.org/#dom-urlpattern-urlpattern>
+ fn Constructor(
+ global: &GlobalScope,
+ proto: Option<HandleObject>,
+ can_gc: CanGc,
+ input: USVStringOrURLPatternInit,
+ base_url: USVString,
+ options: &URLPatternBinding::URLPatternOptions,
+ ) -> Fallible<DomRoot<URLPattern>> {
+ URLPattern::initialize(global, proto, input, Some(base_url), options, can_gc)
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-urlpattern-input-options>
+ fn Constructor_(
+ global: &GlobalScope,
+ proto: Option<HandleObject>,
+ can_gc: CanGc,
+ input: USVStringOrURLPatternInit,
+ options: &URLPatternBinding::URLPatternOptions,
+ ) -> Fallible<DomRoot<URLPattern>> {
+ // Step 1. Run initialize given this, input, null, and options.
+ URLPattern::initialize(global, proto, input, None, options, can_gc)
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol>
+ fn Protocol(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s protocol component’s pattern string.
+ USVString(self.associated_url_pattern.protocol().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-username>
+ fn Username(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s username component’s pattern string.
+ USVString(self.associated_url_pattern.username().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-password>
+ fn Password(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s password component’s pattern string.
+ USVString(self.associated_url_pattern.password().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname>
+ fn Hostname(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s hostname component’s pattern string.
+ USVString(self.associated_url_pattern.hostname().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-port>
+ fn Port(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s port component’s pattern string.
+ USVString(self.associated_url_pattern.port().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname>
+ fn Pathname(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s pathname component’s pattern string.
+ USVString(self.associated_url_pattern.pathname().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-search>
+ fn Search(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s search component’s pattern string.
+ USVString(self.associated_url_pattern.search().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash>
+ fn Hash(&self) -> USVString {
+ // Step 1. Return this’s associated URL pattern’s hash component’s pattern string.
+ USVString(self.associated_url_pattern.hash().to_owned())
+ }
+
+ /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-hasregexpgroups>
+ fn HasRegExpGroups(&self) -> bool {
+ // Step 1. If this’s associated URL pattern’s has regexp groups, then return true.
+ // Step 2. Return false.
+ self.associated_url_pattern.has_regexp_groups()
+ }
+}
+
+mod bindings_to_third_party {
+ use crate::dom::urlpattern::USVStringOrURLPatternInit;
+
+ pub(super) fn map_urlpattern_input(
+ input: USVStringOrURLPatternInit,
+ base_url: Option<String>,
+ ) -> urlpattern::quirks::StringOrInit {
+ match input {
+ USVStringOrURLPatternInit::USVString(usv_string) => {
+ urlpattern::quirks::StringOrInit::String(usv_string.0)
+ },
+ USVStringOrURLPatternInit::URLPatternInit(pattern_init) => {
+ let pattern_init = urlpattern::quirks::UrlPatternInit {
+ protocol: pattern_init
+ .protocol
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ username: pattern_init
+ .username
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ password: pattern_init
+ .password
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ hostname: pattern_init
+ .hostname
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ port: pattern_init
+ .port
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ pathname: pattern_init
+ .pathname
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ search: pattern_init
+ .search
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ hash: pattern_init
+ .hash
+ .as_ref()
+ .map(|usv_string| usv_string.to_string()),
+ base_url,
+ };
+ urlpattern::quirks::StringOrInit::Init(pattern_init)
+ },
+ }
+ }
+}
diff --git a/components/script/dom/urlpattern/mod.rs b/components/script/dom/urlpattern/mod.rs
deleted file mode 100644
index e92963c672b..00000000000
--- a/components/script/dom/urlpattern/mod.rs
+++ /dev/null
@@ -1,810 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-mod pattern_parser;
-mod preprocessing;
-mod tokenizer;
-
-use std::ptr;
-
-use dom_struct::dom_struct;
-use js::jsapi::{Heap, JSObject, RegExpFlag_IgnoreCase, RegExpFlag_UnicodeSets, RegExpFlags};
-use js::rust::HandleObject;
-use pattern_parser::parse_a_pattern_string;
-use preprocessing::{
- canonicalize_a_hash, canonicalize_a_hostname, canonicalize_a_password, canonicalize_a_pathname,
- canonicalize_a_port, canonicalize_a_protocol, canonicalize_a_search, canonicalize_a_username,
- escape_a_regexp_string, process_a_url_pattern_init,
-};
-use script_bindings::error::{Error, Fallible};
-use script_bindings::reflector::Reflector;
-use script_bindings::root::DomRoot;
-use script_bindings::script_runtime::CanGc;
-use script_bindings::str::USVString;
-
-use crate::dom::bindings::cell::RefCell;
-use crate::dom::bindings::codegen::Bindings::URLPatternBinding::{
- URLPatternInit, URLPatternMethods, URLPatternOptions,
-};
-use crate::dom::bindings::reflector::reflect_dom_object_with_proto;
-use crate::dom::globalscope::GlobalScope;
-use crate::dom::htmlinputelement::new_js_regex;
-
-/// <https://urlpattern.spec.whatwg.org/#full-wildcard-regexp-value>
-const FULL_WILDCARD_REGEXP_VALUE: &str = ".*";
-
-/// <https://urlpattern.spec.whatwg.org/#urlpattern>
-#[dom_struct]
-pub(crate) struct URLPattern {
- reflector: Reflector,
-
- /// <https://urlpattern.spec.whatwg.org/#urlpattern-associated-url-pattern>
- associated_url_pattern: RefCell<URLPatternInternal>,
-}
-
-#[derive(JSTraceable, MallocSizeOf)]
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-struct URLPatternInternal {
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-protocol-component>
- protocol: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-username-component>
- username: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-password-component>
- password: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-hostname-component>
- hostname: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-port-component>
- port: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-pathname-component>
- pathname: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-search-component>
- search: Component,
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-hash-component>
- hash: Component,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#component>
-#[derive(JSTraceable, MallocSizeOf)]
-#[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)]
-struct Component {
- /// <https://urlpattern.spec.whatwg.org/#component-pattern-string>
- pattern_string: USVString,
-
- /// <https://urlpattern.spec.whatwg.org/#component-regular-expression>
- #[ignore_malloc_size_of = "mozjs"]
- regular_expression: Box<Heap<*mut JSObject>>,
-
- /// <https://urlpattern.spec.whatwg.org/#component-group-name-list>
- group_name_list: Vec<USVString>,
-
- /// <https://urlpattern.spec.whatwg.org/#component-has-regexp-groups>
- has_regexp_groups: bool,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#part>
-#[derive(Debug)]
-struct Part {
- /// <https://urlpattern.spec.whatwg.org/#part-type>
- part_type: PartType,
-
- /// <https://urlpattern.spec.whatwg.org/#part-value>
- value: String,
-
- /// <https://urlpattern.spec.whatwg.org/#part-modifier>
- modifier: PartModifier,
-
- /// <https://urlpattern.spec.whatwg.org/#part-name>
- name: String,
-
- /// <https://urlpattern.spec.whatwg.org/#part-prefix>
- prefix: String,
-
- /// <https://urlpattern.spec.whatwg.org/#part-suffix>
- suffix: String,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#part-type>
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-enum PartType {
- /// <https://urlpattern.spec.whatwg.org/#part-type-fixed-text>
- FixedText,
-
- /// <https://urlpattern.spec.whatwg.org/#part-type-regexp>
- Regexp,
-
- /// <https://urlpattern.spec.whatwg.org/#part-type-segment-wildcard>
- SegmentWildcard,
-
- /// <https://urlpattern.spec.whatwg.org/#part-type-full-wildcard>
- FullWildcard,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#part-modifier>
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-#[allow(dead_code)] // Parser is not implemented yet
-enum PartModifier {
- /// <https://urlpattern.spec.whatwg.org/#part-modifier-none>
- None,
-
- /// <https://urlpattern.spec.whatwg.org/#part-modifier-optional>
- Optional,
-
- /// <https://urlpattern.spec.whatwg.org/#part-modifier-zero-or-more>
- ZeroOrMore,
-
- /// <https://urlpattern.spec.whatwg.org/#part-modifier-one-or-more>
- OneOrMore,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#options>
-#[derive(Clone, Copy, Default)]
-#[allow(dead_code)] // Parser is not fully implemented yet
-struct Options {
- /// <https://urlpattern.spec.whatwg.org/#options-delimiter-code-point>
- delimiter_code_point: Option<char>,
-
- /// <https://urlpattern.spec.whatwg.org/#options-prefix-code-point>
- prefix_code_point: Option<char>,
-
- /// <https://urlpattern.spec.whatwg.org/#options-ignore-case>
- ignore_case: bool,
-}
-
-impl Component {
- fn new_unrooted() -> Self {
- Self {
- pattern_string: Default::default(),
- regular_expression: Heap::boxed(ptr::null_mut()),
- group_name_list: Default::default(),
- has_regexp_groups: false,
- }
- }
-}
-
-impl URLPattern {
- #[cfg_attr(crown, allow(crown::unrooted_must_root))]
- fn new_inherited() -> URLPattern {
- let associated_url_pattern = URLPatternInternal {
- protocol: Component::new_unrooted(),
- username: Component::new_unrooted(),
- password: Component::new_unrooted(),
- hostname: Component::new_unrooted(),
- port: Component::new_unrooted(),
- pathname: Component::new_unrooted(),
- search: Component::new_unrooted(),
- hash: Component::new_unrooted(),
- };
-
- URLPattern {
- reflector: Reflector::new(),
- associated_url_pattern: RefCell::new(associated_url_pattern),
- }
- }
-
- #[cfg_attr(crown, allow(crown::unrooted_must_root))]
- pub(crate) fn new_with_proto(
- global: &GlobalScope,
- proto: Option<HandleObject>,
- can_gc: CanGc,
- ) -> DomRoot<URLPattern> {
- reflect_dom_object_with_proto(Box::new(URLPattern::new_inherited()), global, proto, can_gc)
- }
-
- /// <https://urlpattern.spec.whatwg.org/#urlpattern-initialize>
- fn initialize(
- global: &GlobalScope,
- proto: Option<HandleObject>,
- input: &URLPatternInit,
- options: &URLPatternOptions,
- can_gc: CanGc,
- ) -> Fallible<DomRoot<URLPattern>> {
- // Step 1. Set this’s associated URL pattern to the result of create given input, baseURL, and options.
- let pattern = URLPattern::new_with_proto(global, proto, can_gc);
- URLPatternInternal::create(
- input,
- options,
- &mut pattern.associated_url_pattern.borrow_mut(),
- )?;
-
- Ok(pattern)
- }
-}
-
-impl URLPatternMethods<crate::DomTypeHolder> for URLPattern {
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-urlpattern-input-options>
- fn Constructor(
- global: &GlobalScope,
- proto: Option<HandleObject>,
- can_gc: CanGc,
- input: &URLPatternInit,
- options: &URLPatternOptions,
- ) -> Fallible<DomRoot<URLPattern>> {
- // Step 1. Run initialize given this, input, null, and options.
- URLPattern::initialize(global, proto, input, options, can_gc)
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol>
- fn Protocol(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s protocol component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .protocol
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-username>
- fn Username(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s username component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .username
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-password>
- fn Password(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s password component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .password
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-hostname>
- fn Hostname(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s hostname component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .hostname
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-port>
- fn Port(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s port component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .port
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-pathname>
- fn Pathname(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s pathname component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .pathname
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-search>
- fn Search(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s search component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .search
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-hash>
- fn Hash(&self) -> USVString {
- // Step 1. Return this’s associated URL pattern’s hash component’s pattern string.
- self.associated_url_pattern
- .borrow()
- .hash
- .pattern_string
- .clone()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-hasregexpgroups>
- fn HasRegExpGroups(&self) -> bool {
- // Step 1. If this’s associated URL pattern’s has regexp groups, then return true.
- // Step 2. Return false.
- self.associated_url_pattern.borrow().has_regexp_groups()
- }
-}
-
-impl URLPatternInternal {
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-create>
- fn create(input: &URLPatternInit, options: &URLPatternOptions, out: &mut Self) -> Fallible<()> {
- // Step 1. Let init be null.
- // Step 2. If input is a scalar value string then:
- // NOTE: We don't support strings as input yet
- // Step 3. Otherwise:
- // Step 3.1 Assert: input is a URLPatternInit.
- // Step 3.2 If baseURL is not null, then throw a TypeError.
- if input.baseURL.is_some() {
- return Err(Error::Type("baseURL must be none".into()));
- }
-
- // Step 3.3 Set init to input.
- let init = input;
-
- // Step 4. Let processedInit be the result of process a URLPatternInit given init, "pattern", null, null,
- // null, null, null, null, null, and null.
- let mut processed_init = process_a_url_pattern_init(init, PatternInitType::Pattern)?;
-
- // Step 5. For each componentName of « "protocol", "username", "password", "hostname", "port",
- // "pathname", "search", "hash" »:
- // Step 5.1 If processedInit[componentName] does not exist, then set processedInit[componentName] to "*".
- // NOTE: We do this later on
-
- // Step 6. If processedInit["protocol"] is a special scheme and processedInit["port"] is a string
- // which represents its corresponding default port in radix-10 using ASCII digits then set
- // processedInit["port"] to the empty string.
- let default_port = processed_init
- .protocol
- .as_deref()
- .and_then(default_port_for_special_scheme);
- let given_port = processed_init
- .port
- .as_deref()
- .map(str::parse)
- .transpose()
- .ok()
- .flatten();
- if default_port.is_some() && default_port == given_port {
- processed_init.port = Some(Default::default());
- }
-
- // Step 7. Let urlPattern be a new URL pattern.
- // NOTE: We construct the pattern provided as the out parameter.
-
- // Step 8. Set urlPattern’s protocol component to the result of compiling a component given
- // processedInit["protocol"], canonicalize a protocol, and default options.
- Component::compile(
- processed_init.protocol.as_deref().unwrap_or("*"),
- Box::new(canonicalize_a_protocol),
- Options::default(),
- &mut out.protocol,
- )?;
-
- // Step 9. Set urlPattern’s username component to the result of compiling a component given
- // processedInit["username"], canonicalize a username, and default options.
- Component::compile(
- processed_init.username.as_deref().unwrap_or("*"),
- Box::new(|i| Ok(canonicalize_a_username(i))),
- Options::default(),
- &mut out.username,
- )?;
-
- // Step 10. Set urlPattern’s password component to the result of compiling a component given
- // processedInit["password"], canonicalize a password, and default options.
- Component::compile(
- processed_init.password.as_deref().unwrap_or("*"),
- Box::new(|i| Ok(canonicalize_a_password(i))),
- Options::default(),
- &mut out.password,
- )?;
-
- // FIXME: Steps 11 and 12: Compile host pattern correctly
- Component::compile(
- processed_init.hostname.as_deref().unwrap_or("*"),
- Box::new(canonicalize_a_hostname),
- Options::HOSTNAME,
- &mut out.hostname,
- )?;
-
- // Step 13. Set urlPattern’s port component to the result of compiling a component given
- // processedInit["port"], canonicalize a port, and default options.
- Component::compile(
- processed_init.port.as_deref().unwrap_or("*"),
- Box::new(|i| canonicalize_a_port(i, None)),
- Options::default(),
- &mut out.port,
- )?;
-
- // FIXME: Step 14: respect ignore case option from here on out
- let _ = options;
-
- // FIXME: Steps 15-16: Compile path pattern correctly
- Component::compile(
- processed_init.pathname.as_deref().unwrap_or("*"),
- Box::new(|i| Ok(canonicalize_a_pathname(i))),
- Options::PATHNAME,
- &mut out.pathname,
- )?;
-
- // Step 17. Set urlPattern’s search component to the result of compiling a component given
- // processedInit["search"], canonicalize a search, and compileOptions.
- Component::compile(
- processed_init.search.as_deref().unwrap_or("*"),
- Box::new(|i| Ok(canonicalize_a_search(i))),
- Options::default(),
- &mut out.search,
- )?;
-
- // Step 18. Set urlPattern’s hash component to the result of compiling a component given
- // processedInit["hash"], canonicalize a hash, and compileOptions.
- Component::compile(
- processed_init.hash.as_deref().unwrap_or("*"),
- Box::new(|i| Ok(canonicalize_a_hash(i))),
- Options::default(),
- &mut out.hash,
- )?;
-
- // Step 19. Return urlPattern.
- // NOTE: not necessary since we use an out parameter
- Ok(())
- }
-
- /// <https://urlpattern.spec.whatwg.org/#url-pattern-has-regexp-groups>
- fn has_regexp_groups(&self) -> bool {
- self.protocol.has_regexp_groups ||
- self.username.has_regexp_groups ||
- self.password.has_regexp_groups ||
- self.hostname.has_regexp_groups ||
- self.port.has_regexp_groups ||
- self.pathname.has_regexp_groups ||
- self.search.has_regexp_groups ||
- self.hash.has_regexp_groups
- }
-}
-
-impl Component {
- /// <https://urlpattern.spec.whatwg.org/#compile-a-component>
- fn compile(
- input: &str,
- encoding_callback: EncodingCallback,
- options: Options,
- out: &mut Self,
- ) -> Fallible<()> {
- // Step 1. Let part list be the result of running parse a pattern string given input, options,
- // and encoding callback.
- let part_list = parse_a_pattern_string(input, options, encoding_callback)?;
-
- // Step 2. Let (regular expression string, name list) be the result of running generate a regular expression and
- // name list given part list and options.
- let (regular_expression_string, name_list) =
- generate_a_regular_expression_and_name_list(&part_list, options);
-
- log::debug!("Compiled {input:?} (URLPattern) to {regular_expression_string:?} (Regex)");
-
- // Step 3. Let flags be an empty string.
- // Step 4. If options’s ignore case is true then set flags to "vi".
- let flags = if options.ignore_case {
- RegExpFlags {
- flags_: RegExpFlag_UnicodeSets | RegExpFlag_IgnoreCase,
- }
- }
- // Step 5. Otherwise set flags to "v"
- else {
- RegExpFlags {
- flags_: RegExpFlag_UnicodeSets,
- }
- };
-
- // Step 6. Let regular expression be RegExpCreate(regular expression string, flags).
- // If this throws an exception, catch it, and throw a TypeError.
- let cx = GlobalScope::get_cx();
- rooted!(in(*cx) let mut regular_expression: *mut JSObject = ptr::null_mut());
- let succeeded = new_js_regex(
- cx,
- &regular_expression_string,
- flags,
- regular_expression.handle_mut(),
- );
- if !succeeded {
- return Err(Error::Type(format!(
- "Failed to compile {regular_expression_string:?} as a regular expression"
- )));
- }
-
- // TODO Step 7. Let pattern string be the result of running generate a pattern string given
- // part list and options.
- let pattern_string = Default::default();
-
- // Step 8. Let has regexp groups be false.
- // Step 9. For each part of part list:
- // Step 9.1 If part’s type is "regexp", then set has regexp groups to true.
- let has_regexp_groups = part_list
- .iter()
- .any(|part| part.part_type == PartType::Regexp);
-
- // Step 10. Return a new component whose pattern string is pattern string, regular expression
- // is regular expression, group name list is name list, and has regexp groups is has regexp groups.
- out.pattern_string = pattern_string;
- out.regular_expression.set(*regular_expression.handle());
- out.group_name_list = name_list;
- out.has_regexp_groups = has_regexp_groups;
-
- Ok(())
- }
-}
-
-/// <https://urlpattern.spec.whatwg.org/#generate-a-regular-expression-and-name-list>
-fn generate_a_regular_expression_and_name_list(
- part_list: &[Part],
- options: Options,
-) -> (String, Vec<USVString>) {
- // Step 1. Let result be "^".
- let mut result = String::from("^");
-
- // Step 2. Let name list be a new list.
- let mut name_list = vec![];
-
- // Step 3. For each part of part list:
- for part in part_list {
- // Step 3.1 If part’s type is "fixed-text":
- if part.part_type == PartType::FixedText {
- // Step 3.1.1 If part’s modifier is "none", then append the result of running escape a regexp string given
- // part’s value to the end of result.
- if part.modifier == PartModifier::None {
- result.push_str(&escape_a_regexp_string(&part.value));
- }
- // Step 3.1.2 Otherwise:
- else {
- // Step 3.1.2.1 Append "(?:" to the end of result.
- result.push_str("(?:");
-
- // Step 3.1.2.2 Append the result of running escape a regexp string given part’s value
- // to the end of result.
- result.push_str(&escape_a_regexp_string(&part.value));
-
- // Step 3.1.2.3 Append ")" to the end of result.
- result.push(')');
-
- // Step 3.1.2.4 Append the result of running convert a modifier to a string given part’s
- // modifier to the end of result.
- result.push_str(part.modifier.convert_to_string());
- }
-
- // Step 3.1.3 Continue.
- continue;
- }
-
- // Step 3.2 Assert: part’s name is not the empty string.
- debug_assert!(!part.name.is_empty());
-
- // Step 3.3 Append part’s name to name list.
- name_list.push(USVString(part.name.to_string()));
-
- // Step 3.4 Let regexp value be part’s value.
- let mut regexp_value = part.value.clone();
-
- // Step 3.5 If part’s type is "segment-wildcard", then set regexp value to the result of running
- // generate a segment wildcard regexp given options.
- if part.part_type == PartType::SegmentWildcard {
- regexp_value = generate_a_segment_wildcard_regexp(options);
- }
- // Step 3.6 Otherwise if part’s type is "full-wildcard", then set regexp value to full wildcard regexp value.
- else if part.part_type == PartType::FullWildcard {
- regexp_value = FULL_WILDCARD_REGEXP_VALUE.into();
- }
-
- // Step 3.7 If part’s prefix is the empty string and part’s suffix is the empty string:
- if part.prefix.is_empty() && part.suffix.is_empty() {
- // Step 3.7.1 If part’s modifier is "none" or "optional", then:
- if matches!(part.modifier, PartModifier::None | PartModifier::Optional) {
- // Step 3.7.1.1 Append "(" to the end of result.
- result.push('(');
-
- // Step 3.7.1.2 Append regexp value to the end of result.
- result.push_str(&regexp_value);
-
- // Step 3.7.1.3 Append ")" to the end of result.
- result.push(')');
-
- // Step 3.7.1.4 Append the result of running convert a modifier to a string given part’s modifier
- // to the end of result.
- result.push_str(part.modifier.convert_to_string());
- }
- // Step 3.7.2 Otherwise:
- else {
- // Step 3.7.2.1 Append "((?:" to the end of result.
- result.push_str("((?:");
-
- // Step 3.7.2.2 Append regexp value to the end of result.
- result.push_str(&regexp_value);
-
- // Step 3.7.2.3 Append ")" to the end of result.
- result.push(')');
-
- // Step 3.7.2.4 Append the result of running convert a modifier to a string given part’s modifier
- // to the end of result.
- result.push_str(part.modifier.convert_to_string());
-
- // Step 3.7.2.5 Append ")" to the end of result.
- result.push(')');
- }
-
- // Step 3.7.3 Continue.
- continue;
- }
-
- // Step 3.8 If part’s modifier is "none" or "optional":
- if matches!(part.modifier, PartModifier::None | PartModifier::Optional) {
- // Step 3.8.1 Append "(?:" to the end of result.
- result.push_str("(?:");
-
- // Step 3.8.2 Append the result of running escape a regexp string given part’s prefix
- // to the end of result.
- result.push_str(&escape_a_regexp_string(&part.prefix));
-
- // Step 3.8.3 Append "(" to the end of result.
- result.push('(');
-
- // Step 3.8.4 Append regexp value to the end of result.
- result.push_str(&regexp_value);
-
- // Step 3.8.5 Append ")" to the end of result.
- result.push(')');
-
- // Step 3.8.6 Append the result of running escape a regexp string given part’s suffix
- // to the end of result.
- result.push_str(&escape_a_regexp_string(&part.suffix));
-
- // Step 3.8.7 Append ")" to the end of result.
- result.push(')');
-
- // Step 3.8.8 Append the result of running convert a modifier to a string given part’s modifier to
- // the end of result.
- result.push_str(part.modifier.convert_to_string());
-
- // Step 3.8.9 Continue.
- continue;
- }
-
- // Step 3.9 Assert: part’s modifier is "zero-or-more" or "one-or-more".
- debug_assert!(matches!(
- part.modifier,
- PartModifier::ZeroOrMore | PartModifier::OneOrMore
- ));
-
- // Step 3.10 Assert: part’s prefix is not the empty string or part’s suffix is not the empty string.
- debug_assert!(!part.prefix.is_empty() || !part.suffix.is_empty());
-
- // Step 3.11 Append "(?:" to the end of result.
- result.push_str("(?:");
-
- // Step 3.12 Append the result of running escape a regexp string given part’s prefix to the end of result.
- result.push_str(&escape_a_regexp_string(&part.prefix));
-
- // Step 3.13 Append "((?:" to the end of result.
- result.push_str("((?:");
-
- // Step 3.14 Append regexp value to the end of result.
- result.push_str(&regexp_value);
-
- // Step 3.15 Append ")(?:" to the end of result.
- result.push_str(")(?:");
-
- // Step 3.16 Append the result of running escape a regexp string given part’s suffix to the end of result.
- result.push_str(&escape_a_regexp_string(&part.suffix));
-
- // Step 3.17 Append the result of running escape a regexp string given part’s prefix to the end of result.
- result.push_str(&escape_a_regexp_string(&part.prefix));
-
- // Step 3.18 Append "(?:" to the end of result.
- result.push_str("(?:");
-
- // Step 3.19 Append regexp value to the end of result.
- result.push_str(&regexp_value);
-
- // Step 3.20 Append "))*)" to the end of result.
- result.push_str("))*)");
-
- // Step 3.21 Append the result of running escape a regexp string given part’s suffix to the end of result.
- result.push_str(&escape_a_regexp_string(&part.suffix));
-
- // Step 3.22 Append ")" to the end of result.
- result.push(')');
-
- // Step 3.23 If part’s modifier is "zero-or-more" then append "?" to the end of result.
- if part.modifier == PartModifier::ZeroOrMore {
- result.push('?');
- }
- }
-
- // Step 4. Append "$" to the end of result.
- result.push('$');
-
- // Step 5. Return (result, name list).
- (result, name_list)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#encoding-callback>
-type EncodingCallback = Box<dyn Fn(&str) -> Fallible<String>>;
-
-// FIXME: Deduplicate this with the url crate
-/// <https://url.spec.whatwg.org/#special-scheme>
-fn default_port_for_special_scheme(scheme: &str) -> Option<u16> {
- match scheme {
- "ftp" => Some(21),
- "http" | "ws" => Some(80),
- "https" | "wss" => Some(443),
- _ => None,
- }
-}
-
-/// <https://url.spec.whatwg.org/#special-scheme>
-fn is_special_scheme(scheme: &str) -> bool {
- matches!(scheme, "ftp" | "http" | "https" | "ws" | "wss")
-}
-
-/// <https://urlpattern.spec.whatwg.org/#generate-a-segment-wildcard-regexp>
-fn generate_a_segment_wildcard_regexp(options: Options) -> String {
- // Step 1. Let result be "[^".
- let mut result = String::from("[^");
-
- // Step 2. Append the result of running escape a regexp string given options’s
- // delimiter code point to the end of result.
- result.push_str(&escape_a_regexp_string(
- &options
- .delimiter_code_point
- .map(|c| c.to_string())
- .unwrap_or_default(),
- ));
-
- // Step 3. Append "]+?" to the end of result.
- result.push_str("]+?");
-
- // Step 4. Return result.
- result
-}
-
-impl PartModifier {
- /// <https://urlpattern.spec.whatwg.org/#convert-a-modifier-to-a-string>
- fn convert_to_string(&self) -> &'static str {
- match self {
- // Step 1. If modifier is "zero-or-more", then return "*".
- Self::ZeroOrMore => "*",
- // Step 2. If modifier is "optional", then return "?".
- Self::Optional => "?",
- // Step 3. If modifier is "one-or-more", then return "+".
- Self::OneOrMore => "+",
- // Step 4. Return the empty string.
- _ => "",
- }
- }
-}
-
-impl Options {
- /// <https://urlpattern.spec.whatwg.org/#hostname-options>
- const HOSTNAME: Self = Self {
- delimiter_code_point: Some('.'),
- prefix_code_point: None,
- ignore_case: false,
- };
-
- /// <https://urlpattern.spec.whatwg.org/#pathname-options>
- const PATHNAME: Self = Self {
- delimiter_code_point: Some('/'),
- prefix_code_point: Some('/'),
- ignore_case: false,
- };
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-enum PatternInitType {
- Pattern,
- Url,
-}
-
-impl Part {
- fn new(part_type: PartType, value: String, modifier: PartModifier) -> Self {
- Self {
- part_type,
- value,
- modifier,
- name: String::new(),
- prefix: String::new(),
- suffix: String::new(),
- }
- }
-}
diff --git a/components/script/dom/urlpattern/pattern_parser.rs b/components/script/dom/urlpattern/pattern_parser.rs
deleted file mode 100644
index 3147c5649f4..00000000000
--- a/components/script/dom/urlpattern/pattern_parser.rs
+++ /dev/null
@@ -1,473 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use script_bindings::error::{Error, Fallible};
-
-use crate::dom::urlpattern::tokenizer::{Token, TokenType, TokenizePolicy, tokenize};
-use crate::dom::urlpattern::{
- EncodingCallback, FULL_WILDCARD_REGEXP_VALUE, Options, Part, PartModifier, PartType,
- generate_a_segment_wildcard_regexp,
-};
-
-/// <https://urlpattern.spec.whatwg.org/#parse-a-pattern-string>
-pub(super) fn parse_a_pattern_string(
- input: &str,
- options: Options,
- encoding_callback: EncodingCallback,
-) -> Fallible<Vec<Part>> {
- // Step 1. Let parser be a new pattern parser whose encoding callback is encoding callback and
- // segment wildcard regexp is the result of running generate a segment wildcard regexp given options.
- let mut parser = PatternParser::new(
- generate_a_segment_wildcard_regexp(options),
- encoding_callback,
- );
-
- // Step 2. Set parser’s token list to the result of running tokenize given input and "strict".
- parser.token_list = tokenize(input, TokenizePolicy::Strict)?;
-
- // Step 3. While parser’s index is less than parser’s token list’s size:
- while parser.index < parser.token_list.len() {
- // Step 3.1 Let char token be the result of running try to consume a token given parser and "char".
- let char_token = parser.try_to_consume_a_token(TokenType::Char);
-
- // Step 3.2 Let name token be the result of running try to consume a token given parser and "name".
- let mut name_token = parser.try_to_consume_a_token(TokenType::Name);
-
- // Step 3.3 Let regexp or wildcard token be the result of running try to consume a
- // regexp or wildcard token given parser and name token.
- let mut regexp_or_wildcard_token =
- parser.try_to_consume_a_regexp_or_wildcard_token(name_token);
-
- // Step 3.4 If name token is not null or regexp or wildcard token is not null:
- if name_token.is_some() || regexp_or_wildcard_token.is_some() {
- // Step 3.4.1 Let prefix be the empty string.
- let mut prefix = "";
-
- // Step 3.4.2 If char token is not null then set prefix to char token’s value.
- if let Some(char_token) = char_token {
- prefix = char_token.value;
- }
-
- // Step 3.4.3 If prefix is not the empty string and not options’s prefix code point:
- let prefix_is_prefix_code_point = options.prefix_code_point.is_some_and(|c| {
- let mut buffer = [0; 4];
- prefix == c.encode_utf8(&mut buffer)
- });
- if !prefix.is_empty() && !prefix_is_prefix_code_point {
- // Step 3.4.3.1 Append prefix to the end of parser’s pending fixed value.
- parser.pending_fixed_value.push_str(prefix);
-
- // Step 3.4.3.2 Set prefix to the empty string.
- prefix = "";
- }
-
- // Step 3.4.4 Run maybe add a part from the pending fixed value given parser.
- parser.maybe_add_a_part_from_the_pending_fixed_value()?;
-
- // Step 3.4.5 Let modifier token be the result of running try to consume a modifier token given parser.
- let modifier_token = parser.try_to_consume_a_modifier_token();
-
- // Step 3.4.6 Run add a part given parser, prefix, name token, regexp or wildcard token,
- // the empty string, and modifier token.
- parser.add_a_part(
- prefix,
- name_token,
- regexp_or_wildcard_token,
- "",
- modifier_token,
- )?;
-
- // Step 3.4.7 Continue.
- continue;
- }
-
- // Step 3.5 Let fixed token be char token.
- let mut fixed_token = char_token;
-
- // Step 3.6 If fixed token is null, then set fixed token to the result of running
- // try to consume a token given parser and "escaped-char".
- if fixed_token.is_none() {
- fixed_token = parser.try_to_consume_a_token(TokenType::EscapedChar);
- }
-
- // Step 3.7 If fixed token is not null:
- if let Some(fixed_token) = fixed_token {
- // Step 3.7.1 Append fixed token’s value to parser’s pending fixed value.
- parser.pending_fixed_value.push_str(fixed_token.value);
-
- // Step 3.7.2 Continue.
- continue;
- }
-
- // Step 3.8 Let open token be the result of running try to consume a token given parser and "open".
- let open_token = parser.try_to_consume_a_token(TokenType::Open);
-
- // Step 3.9 If open token is not null:
- if open_token.is_some() {
- // Step 3.9.1 Let prefix be the result of running consume text given parser.
- let prefix = parser.consume_text();
-
- // Step 3.9.2 Set name token to the result of running try to consume a token given parser and "name".
- name_token = parser.try_to_consume_a_token(TokenType::Name);
-
- // Step 3.9.3 Set regexp or wildcard token to the result of running try to consume a regexp or wildcard
- // token given parser and name token.
- regexp_or_wildcard_token = parser.try_to_consume_a_regexp_or_wildcard_token(name_token);
-
- // Step 3.9.4 Let suffix be the result of running consume text given parser.
- let suffix = parser.consume_text();
-
- // Step 3.9.5 Run consume a required token given parser and "close".
- parser.consume_a_required_token(TokenType::Close)?;
-
- // Step 3.9.6 Let modifier token be the result of running try to consume a modifier token given parser.
- let modifier_token = parser.try_to_consume_a_modifier_token();
-
- // Step 3.9.7 Run add a part given parser, prefix, name token, regexp or wildcard token,
- // suffix, and modifier token.
- parser.add_a_part(
- &prefix,
- name_token,
- regexp_or_wildcard_token,
- &suffix,
- modifier_token,
- )?;
-
- // Step 3.9.8 Continue.
- continue;
- }
-
- // Step 3.10 Run maybe add a part from the pending fixed value given parser.
- parser.maybe_add_a_part_from_the_pending_fixed_value()?;
-
- // Step 3.11 Run consume a required token given parser and "end".
- parser.consume_a_required_token(TokenType::End)?;
- }
-
- Ok(parser.part_list)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#pattern-parser>
-struct PatternParser<'a> {
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-token-list>
- token_list: Vec<Token<'a>>,
-
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-encoding-callback>
- encoding_callback: EncodingCallback,
-
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-segment-wildcard-regexp>
- segment_wildcard_regexp: String,
-
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-part-list>
- part_list: Vec<Part>,
-
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-pending-fixed-value>
- pending_fixed_value: String,
-
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-index>
- index: usize,
-
- /// <https://urlpattern.spec.whatwg.org/#pattern-parser-next-numeric-name>
- next_numeric_name: usize,
-}
-
-impl<'a> PatternParser<'a> {
- fn new(segment_wildcard_regexp: String, encoding_callback: EncodingCallback) -> Self {
- Self {
- token_list: vec![],
- segment_wildcard_regexp,
- part_list: vec![],
- pending_fixed_value: String::new(),
- index: 0,
- next_numeric_name: 0,
- encoding_callback,
- }
- }
-
- /// <https://urlpattern.spec.whatwg.org/#try-to-consume-a-token>
- fn try_to_consume_a_token(&mut self, token_type: TokenType) -> Option<Token<'a>> {
- // Step 1. Assert: parser’s index is less than parser’s token list size.
- debug_assert!(self.index < self.token_list.len());
-
- // Step 2. Let next token be parser’s token list[parser’s index].
- let next_token = self.token_list[self.index];
-
- // Step 3. If next token’s type is not type return null.
- if next_token.token_type != token_type {
- return None;
- }
-
- // Step 4. Increment parser’s index by 1.
- self.index += 1;
-
- // Step 5. Return next token.
- Some(next_token)
- }
-
- /// <https://urlpattern.spec.whatwg.org/#try-to-consume-a-modifier-token>
- fn try_to_consume_a_modifier_token(&mut self) -> Option<Token<'a>> {
- // Step 1. Let token be the result of running try to consume a token given parser and "other-modifier".
- let token = self.try_to_consume_a_token(TokenType::OtherModifier);
-
- // Step 2. If token is not null, then return token.
- if token.is_some() {
- return token;
- }
-
- // Step 3. Set token to the result of running try to consume a token given parser and "asterisk".
- let token = self.try_to_consume_a_token(TokenType::Asterisk);
-
- // Step 4. Return token.
- token
- }
-
- /// <https://urlpattern.spec.whatwg.org/#consume-a-required-token>
- fn consume_a_required_token(&mut self, token_type: TokenType) -> Fallible<Token<'a>> {
- // Step 1. Let result be the result of running try to consume a token given parser and type.
- let result = self.try_to_consume_a_token(token_type);
-
- // Step 2. If result is null, then throw a TypeError.
- let Some(result) = result else {
- return Err(Error::Type(format!(
- "Missing required token {token_type:?}"
- )));
- };
-
- // Step 3. Return result.
- Ok(result)
- }
-
- /// <https://urlpattern.spec.whatwg.org/#try-to-consume-a-regexp-or-wildcard-token>
- fn try_to_consume_a_regexp_or_wildcard_token(
- &mut self,
- name_token: Option<Token<'a>>,
- ) -> Option<Token<'a>> {
- // Step 1. Let token be the result of running try to consume a token given parser and "regexp".
- let mut token = self.try_to_consume_a_token(TokenType::Regexp);
-
- // Step 2. If name token is null and token is null, then set token to the result of running
- // try to consume a token given parser and "asterisk".
- if name_token.is_none() && token.is_none() {
- token = self.try_to_consume_a_token(TokenType::Asterisk);
- }
-
- // Step 3. Return token.
- token
- }
-
- /// <https://urlpattern.spec.whatwg.org/#maybe-add-a-part-from-the-pending-fixed-value>
- fn maybe_add_a_part_from_the_pending_fixed_value(&mut self) -> Fallible<()> {
- // Step 1. If parser’s pending fixed value is the empty string, then return.
- if self.pending_fixed_value.is_empty() {
- return Ok(());
- }
-
- // Step 2. Let encoded value be the result of running parser’s encoding callback
- // given parser’s pending fixed value.
- let encoded_value = (self.encoding_callback)(&self.pending_fixed_value)?;
-
- // Step 3. Set parser’s pending fixed value to the empty string.
- self.pending_fixed_value.clear();
-
- // Step 4. Let part be a new part whose type is "fixed-text", value is encoded value, and modifier is "none".
- let part = Part::new(PartType::FixedText, encoded_value, PartModifier::None);
-
- // Step 5. Append part to parser’s part list.
- self.part_list.push(part);
-
- Ok(())
- }
-
- /// <https://urlpattern.spec.whatwg.org/#add-a-part>
- fn add_a_part(
- &mut self,
- prefix: &str,
- name_token: Option<Token<'a>>,
- regexp_or_wildcard_token: Option<Token<'a>>,
- suffix: &str,
- modifier_token: Option<Token<'a>>,
- ) -> Fallible<()> {
- // Step 1. Let modifier be "none".
- let mut modifier = PartModifier::None;
-
- // Step 2. If modifier token is not null:
- if let Some(modifier_token) = modifier_token {
- // Step 2.1 If modifier token’s value is "?" then set modifier to "optional".
- if modifier_token.value == "?" {
- modifier = PartModifier::Optional;
- }
- // Step 2.2 Otherwise if modifier token’s value is "*" then set modifier to "zero-or-more".
- else if modifier_token.value == "*" {
- modifier = PartModifier::ZeroOrMore;
- }
- // Step 2.3 Otherwise if modifier token’s value is "+" then set modifier to "one-or-more".
- else if modifier_token.value == "+" {
- modifier = PartModifier::OneOrMore;
- }
- }
-
- // Step 3. If name token is null and regexp or wildcard token is null and modifier is "none":
- if name_token.is_none() &&
- regexp_or_wildcard_token.is_none() &&
- modifier == PartModifier::None
- {
- // Step 3.1 Append prefix to the end of parser’s pending fixed value.
- self.pending_fixed_value.push_str(prefix);
-
- // Step 3.2 Return
- return Ok(());
- }
-
- // Step 4. Run maybe add a part from the pending fixed value given parser.
- self.maybe_add_a_part_from_the_pending_fixed_value()?;
-
- // Step 5. If name token is null and regexp or wildcard token is null:
- if name_token.is_none() && regexp_or_wildcard_token.is_none() {
- // Step 5.1 Assert: suffix is the empty string.
- debug_assert!(suffix.is_empty());
-
- // Step 5.2 If prefix is the empty string, then return.
- if prefix.is_empty() {
- return Ok(());
- }
-
- // Step 5.3 Let encoded value be the result of running parser’s encoding callback given prefix.
- let encoded_value = (self.encoding_callback)(prefix)?;
-
- // Step 5.4 Let part be a new part whose type is "fixed-text",
- // value is encoded value, and modifier is modifier.
- let part = Part::new(PartType::FixedText, encoded_value, modifier);
-
- // Step 5.5 Append part to parser’s part list.
- self.part_list.push(part);
-
- // Step 6. Return.
- return Ok(());
- }
-
- // Step 6. Let regexp value be the empty string.
- let mut regexp_value = {
- // Step 7. If regexp or wildcard token is null, then set regexp value to parser’s segment wildcard regexp.
- match regexp_or_wildcard_token {
- None => self.segment_wildcard_regexp.clone(),
- Some(token) => {
- // Step 8. Otherwise if regexp or wildcard token’s type is "asterisk",
- // then set regexp value to the full wildcard regexp value.
- if token.token_type == TokenType::Asterisk {
- FULL_WILDCARD_REGEXP_VALUE.into()
- }
- // Step 9. Otherwise set regexp value to regexp or wildcard token’s value.
- else {
- token.value.to_owned()
- }
- },
- }
- };
-
- // Step 10. Let type be "regexp".
- let mut part_type = PartType::Regexp;
-
- // Step 11. If regexp value is parser’s segment wildcard regexp:
- if regexp_value == self.segment_wildcard_regexp {
- // Step 11.1 Set type to "segment-wildcard".
- part_type = PartType::SegmentWildcard;
-
- // Step 11.2 Set regexp value to the empty string.
- regexp_value.clear();
- }
- // Step 12. Otherwise if regexp value is the full wildcard regexp value:
- else if regexp_value == FULL_WILDCARD_REGEXP_VALUE {
- // Step 12.1 Set type to "full-wildcard".
- part_type = PartType::FullWildcard;
-
- // Step 12.2 Set regexp value to the empty string.
- regexp_value.clear();
- }
-
- // Step 13. Let name be the empty string.
- let mut name = String::new();
-
- // Step 14. If name token is not null, then set name to name token’s value.
- if let Some(name_token) = name_token {
- name = name_token.value.to_owned();
- }
- // Step 15. Otherwise if regexp or wildcard token is not null:
- else if regexp_or_wildcard_token.is_some() {
- // Step 15.1 Set name to parser’s next numeric name, serialized.
- name = self.next_numeric_name.to_string();
-
- // Step 15.2 Increment parser’s next numeric name by 1.
- self.next_numeric_name = self.next_numeric_name.wrapping_add(1);
- }
-
- // Step 16. If the result of running is a duplicate name given parser and name is true, then throw a TypeError.
- if self.is_a_duplicate_name(&name) {
- return Err(Error::Type(format!("Duplicate part name: {name:?}")));
- }
-
- // Step 17. Let encoded prefix be the result of running parser’s encoding callback given prefix.
- let encoded_prefix = (self.encoding_callback)(prefix)?;
-
- // Step 18. Let encoded suffix be the result of running parser’s encoding callback given suffix.
- let encoded_suffix = (self.encoding_callback)(suffix)?;
-
- // Step 19. Let part be a new part whose type is type, value is regexp value, modifier is modifier,
- // name is name, prefix is encoded prefix, and suffix is encoded suffix.
- let part = Part {
- part_type,
- value: regexp_value,
- modifier,
- name,
- prefix: encoded_prefix,
- suffix: encoded_suffix,
- };
-
- // Step 20. Append part to parser’s part list.
- self.part_list.push(part);
-
- Ok(())
- }
-
- // <https://urlpattern.spec.whatwg.org/#is-a-duplicate-name>
- fn is_a_duplicate_name(&self, name: &str) -> bool {
- // Step 1. For each part of parser’s part list:
- for part in &self.part_list {
- // Step 1.1 If part’s name is name, then return true.
- if part.name == name {
- return true;
- }
- }
-
- // Step 2. Return false.
- false
- }
-
- /// <https://urlpattern.spec.whatwg.org/#consume-text>
- fn consume_text(&mut self) -> String {
- // Step 1. Let result be the empty string.
- let mut result = String::new();
-
- // Step 2. While true:
- loop {
- // Step 2.1 Let token be the result of running try to consume a token given parser and "char".
- let mut token = self.try_to_consume_a_token(TokenType::Char);
-
- // Step 2.2 If token is null, then set token to the result of running
- // try to consume a token given parser and "escaped-char".
- if token.is_none() {
- token = self.try_to_consume_a_token(TokenType::EscapedChar);
- }
-
- // Step 2.3 If token is null, then break.
- let Some(token) = token else {
- break;
- };
-
- // Step 2.4 Append token’s value to the end of result.
- result.push_str(token.value);
- }
-
- result
- }
-}
diff --git a/components/script/dom/urlpattern/preprocessing.rs b/components/script/dom/urlpattern/preprocessing.rs
deleted file mode 100644
index 7fc3c136315..00000000000
--- a/components/script/dom/urlpattern/preprocessing.rs
+++ /dev/null
@@ -1,659 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use script_bindings::error::{Error, Fallible};
-use script_bindings::str::USVString;
-use url::Url;
-
-use crate::dom::bindings::codegen::Bindings::URLPatternBinding::URLPatternInit;
-use crate::dom::urlpattern::{PatternInitType, default_port_for_special_scheme, is_special_scheme};
-
-/// <https://urlpattern.spec.whatwg.org/#process-a-urlpatterninit>
-pub(super) fn process_a_url_pattern_init(
- init: &URLPatternInit,
- init_type: PatternInitType,
-) -> Fallible<URLPatternInit> {
- // Step 1. Let result be the result of creating a new URLPatternInit.
- let mut result = URLPatternInit::default();
-
- // TODO Step 2. If protocol is not null, set result["protocol"] to protocol.
- // TODO Step 3. If username is not null, set result["username"] to username.
- // TODO Step 4. If password is not null, set result["password"] to password.
- // TODO Step 5. If hostname is not null, set result["hostname"] to hostname.
- // TODO Step 6. If port is not null, set result["port"] to port.
- // TODO Step 7. If pathname is not null, set result["pathname"] to pathname.
- // TODO Step 8. If search is not null, set result["search"] to search.
- // TODO Step 9. If hash is not null, set result["hash"] to hash.
-
- // Step 10. Let baseURL be null.
- let mut base_url: Option<Url> = None;
-
- // Step 11. If init["baseURL"] exists:
- if let Some(init_base_url) = init.baseURL.as_ref() {
- // Step 11.1 Set baseURL to the result of running the basic URL parser on init["baseURL"].
- let Ok(parsed_base_url) = init_base_url.0.parse() else {
- // Step 11.2 If baseURL is failure, then throw a TypeError.
- return Err(Error::Type(format!(
- "Failed to parse {:?} as URL",
- init_base_url.0
- )));
- };
- let base_url = base_url.insert(parsed_base_url);
-
- // Step 11.3 If init["protocol"] does not exist, then set result["protocol"] to the result of
- // processing a base URL string given baseURL’s scheme and type.
- if init.protocol.is_none() {
- result.protocol = Some(USVString(process_a_base_url_string(
- base_url.scheme(),
- init_type,
- )));
- }
-
- // Step 11.4. If type is not "pattern" and init contains none of "protocol", "hostname",
- // "port" and "username", then set result["username"] to the result of processing a base URL string
- // given baseURL’s username and type.
- if init_type != PatternInitType::Pattern &&
- init.protocol.is_none() &&
- init.hostname.is_none() &&
- init.port.is_none() &&
- init.username.is_none()
- {
- result.username = Some(USVString(process_a_base_url_string(
- base_url.username(),
- init_type,
- )));
- }
-
- // Step 11.5 If type is not "pattern" and init contains none of "protocol", "hostname", "port",
- // "username" and "password", then set result["password"] to the result of processing a base URL string
- // given baseURL’s password and type.
- if init_type != PatternInitType::Pattern &&
- init.protocol.is_none() &&
- init.hostname.is_none() &&
- init.port.is_none() &&
- init.username.is_none() &&
- init.password.is_none()
- {
- result.password = Some(USVString(process_a_base_url_string(
- base_url.password().unwrap_or_default(),
- init_type,
- )));
- }
-
- // Step 11.6 If init contains neither "protocol" nor "hostname", then:
- if init.protocol.is_none() && init.hostname.is_none() {
- // Step 11.6.1 Let baseHost be the empty string.
- // Step 11.6.2 If baseURL’s host is not null, then set baseHost to its serialization.
- let base_host = base_url
- .host()
- .map(|host| host.to_string())
- .unwrap_or_default();
-
- // Step 11.6.3 Set result["hostname"] to the result of processing a base URL string given baseHost and type.
- result.hostname = Some(USVString(process_a_base_url_string(&base_host, init_type)));
- }
-
- // Step 11.7 If init contains none of "protocol", "hostname", and "port", then:
- if init.protocol.is_none() && init.hostname.is_none() && init.port.is_none() {
- match base_url.port() {
- // Step 11.7.1 If baseURL’s port is null, then set result["port"] to the empty string.
- None => {
- result.port = Some(USVString(String::new()));
- },
- // Step 11.7.2 Otherwise, set result["port"] to baseURL’s port, serialized.
- Some(port) => {
- result.port = Some(USVString(port.to_string()));
- },
- }
- }
-
- // Step 11.8 If init contains none of "protocol", "hostname", "port", and "pathname", then set
- // result["pathname"] to the result of processing a base URL string given the result of
- // URL path serializing baseURL and type.
- if init.protocol.is_none() &&
- init.hostname.is_none() &&
- init.port.is_none() &&
- init.pathname.is_none()
- {
- result.pathname = Some(USVString(process_a_base_url_string(
- base_url.path(),
- init_type,
- )));
- }
-
- // Step 11.9 If init contains none of "protocol", "hostname", "port", "pathname",
- // and "search", then:
- if init.protocol.is_none() &&
- init.hostname.is_none() &&
- init.port.is_none() &&
- init.pathname.is_none() &&
- init.search.is_none()
- {
- // Step 11.9.1 Let baseQuery be baseURL’s query.
- let base_query = base_url.query();
-
- // Step 11.9.2 If baseQuery is null, then set baseQuery to the empty string.
- let base_query = base_query.unwrap_or_default();
-
- // Step 11.9.3 Set result["search"] to the result of processing a base URL string given baseQuery and type.
- result.search = Some(USVString(process_a_base_url_string(base_query, init_type)));
- }
-
- // Step 11.10 If init contains none of "protocol", "hostname",
- // "port", "pathname", "search", and "hash", then:
- if init.protocol.is_none() &&
- init.hostname.is_none() &&
- init.port.is_none() &&
- init.pathname.is_none() &&
- init.search.is_none() &&
- init.hash.is_none()
- {
- // Step 11.10.1 Let baseFragment be baseURL’s fragment.
- let base_fragment = base_url.fragment();
-
- // Step 11.10.2 If baseFragment is null, then set baseFragment to the empty string.
- let base_fragment = base_fragment.unwrap_or_default();
-
- // Step 11.10.3 Set result["hash"] to the result of processing a base URL string
- // given baseFragment and type.
- result.hash = Some(USVString(process_a_base_url_string(
- base_fragment,
- init_type,
- )));
- }
- }
-
- // Step 12. If init["protocol"] exists, then set result["protocol"] to the result of process protocol for init
- // given init["protocol"] and type.
- if let Some(protocol) = &init.protocol {
- result.protocol = Some(USVString(process_a_protocol_for_init(protocol, init_type)?));
- }
-
- // Step 13. If init["username"] exists, then set result["username"] to the result of
- // process username for init given init["username"] and type.
- if let Some(username) = &init.username {
- result.username = Some(USVString(process_username_for_init(username, init_type)));
- }
-
- // Step 14. If init["password"] exists, then set result["password"] to the result of
- // process password for init given init["password"] and type.
- if let Some(password) = &init.password {
- result.password = Some(USVString(process_password_for_init(password, init_type)));
- }
-
- // Step 15. If init["hostname"] exists, then set result["hostname"] to the result of
- // process hostname for init given init["hostname"] and type.
- if let Some(hostname) = &init.hostname {
- result.hostname = Some(USVString(process_hostname_for_init(hostname, init_type)?));
- }
-
- // Step 16. Let resultProtocolString be result["protocol"] if it exists; otherwise the empty string.
- let result_protocol_string = result.protocol.as_deref().unwrap_or_default();
-
- // Step 17. If init["port"] exists, then set result["port"] to the result of process port for init
- // given init["port"], resultProtocolString, and type.
- if let Some(port) = &init.port {
- result.port = Some(USVString(process_port_for_init(
- port,
- result_protocol_string,
- init_type,
- )?));
- }
-
- // Step 18. If init["pathname"] exists:
- if let Some(path_name) = &init.pathname {
- // Step 18.1 Set result["pathname"] to init["pathname"].
- // NOTE: This is not necessary - the spec uses result["pathname"] in the following section,
- // but it could just as well use init["pathname"]. Storing the string in an intermediate
- // variable makes the code simpler
- let mut result_pathname = path_name.to_string();
-
- // Step 18.2 If the following are all true:
- // * baseURL is not null;
- // * baseURL does not have an opaque path; and
- // * the result of running is an absolute pathname given result["pathname"] and type is false,
- if let Some(base_url) = base_url {
- if !base_url.cannot_be_a_base() && !is_an_absolute_pathname(path_name, init_type) {
- // Step 18.2.1 Let baseURLPath be the result of running process a base URL string given the result
- // of URL path serializing baseURL and type.
- let base_url_path = process_a_base_url_string(base_url.path(), init_type);
-
- // Step 18.2.2 Let slash index be the index of the last U+002F (/) code point found in baseURLPath,
- // interpreted as a sequence of code points, or null if there are no instances of the code point.
- let slash_index = base_url_path.rfind('/');
-
- // Step 18.2.3 If slash index is not null:
- if let Some(slash_index) = slash_index {
- // Step 18.2.3.1 Let new pathname be the code point substring from 0 to slash index + 1
- // within baseURLPath.
- let mut new_pathname = base_url_path[..=slash_index].to_owned();
-
- // Step 18.2.3.2 Append result["pathname"] to the end of new pathname.
- new_pathname.push_str(path_name);
-
- // Step 18.2.3.3 Set result["pathname"] to new pathname.
- result_pathname = new_pathname;
- }
- }
- }
-
- // Step 18.3 Set result["pathname"] to the result of process pathname for init given result["pathname"],
- // resultProtocolString, and type.
- result.pathname = Some(USVString(process_pathname_for_init(
- &result_pathname,
- result_protocol_string,
- init_type,
- )?));
- }
-
- // Step 19. If init["search"] exists then set result["search"] to the result of
- // process search for init given init["search"] and type.
- if let Some(search) = &init.search {
- result.search = Some(USVString(process_search_for_init(search, init_type)));
- }
-
- // Step 20. If init["hash"] exists then set result["hash"] to the result of
- // process hash for init given init["hash"] and type.
- if let Some(hash) = &init.hash {
- result.hash = Some(USVString(process_hash_for_init(hash, init_type)));
- }
-
- // Step 21. Return result.
- Ok(result)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-protocol-for-init>
-fn process_a_protocol_for_init(input: &str, init_type: PatternInitType) -> Fallible<String> {
- // Step 1. Let strippedValue be the given value with a single trailing U+003A (:) removed, if any.
- let stripped_value = input.strip_suffix(':').unwrap_or(input);
-
- // Step 2. If type is "pattern" then return strippedValue.
- if init_type == PatternInitType::Pattern {
- return Ok(stripped_value.to_owned());
- }
-
- // Step 3. Return the result of running canonicalize a protocol given strippedValue.
- canonicalize_a_protocol(stripped_value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-username-for-init>
-fn process_username_for_init(value: &str, init_type: PatternInitType) -> String {
- // Step 1. If type is "pattern" then return value.
- if init_type == PatternInitType::Pattern {
- return value.to_owned();
- }
-
- // Step 2. Return the result of running canonicalize a username given value.
- canonicalize_a_username(value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-password-for-init>
-fn process_password_for_init(value: &str, init_type: PatternInitType) -> String {
- // Step 1. If type is "pattern" then return value.
- if init_type == PatternInitType::Pattern {
- return value.to_owned();
- }
-
- // Step 2. Return the result of running canonicalize a password given value.
- canonicalize_a_password(value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-hostname-for-init>
-fn process_hostname_for_init(value: &str, init_type: PatternInitType) -> Fallible<String> {
- // Step 1. If type is "pattern" then return value.
- if init_type == PatternInitType::Pattern {
- return Ok(value.to_owned());
- }
-
- // Step 2. Return the result of running canonicalize a hostname given value.
- canonicalize_a_hostname(value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-port-for-init>
-fn process_port_for_init(
- port_value: &str,
- protocol_value: &str,
- init_type: PatternInitType,
-) -> Fallible<String> {
- // Step 1. If type is "pattern" then return portValue.
- if init_type == PatternInitType::Pattern {
- return Ok(port_value.to_owned());
- }
-
- // Step 2. Return the result of running canonicalize a port given portValue and protocolValue.
- canonicalize_a_port(port_value, Some(protocol_value))
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-pathname-for-init>
-fn process_pathname_for_init(
- path_name_value: &str,
- protocol_value: &str,
- init_type: PatternInitType,
-) -> Fallible<String> {
- // Step 1. If type is "pattern" then return pathnameValue.
- if init_type == PatternInitType::Pattern {
- return Ok(path_name_value.to_owned());
- }
-
- // Step 2. If protocolValue is a special scheme or the empty string, then return the result of
- // running canonicalize a pathname given pathnameValue.
- if is_special_scheme(protocol_value) || protocol_value.is_empty() {
- return Ok(canonicalize_a_pathname(path_name_value));
- }
-
- // Step 2. Return the result of running canonicalize an opaque pathname given pathnameValue.
- canonicalize_an_opaque_pathname(path_name_value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-search-for-init>
-fn process_search_for_init(value: &str, init_type: PatternInitType) -> String {
- // Step 1. Let strippedValue be the given value with a single leading U+003F (?) removed, if any.
- let stripped_value = value.strip_prefix('?').unwrap_or(value);
-
- // Step 2. If type is "pattern" then return strippedValue.
- if init_type == PatternInitType::Pattern {
- return stripped_value.to_owned();
- }
-
- // Step 3. Return the result of running canonicalize a search given strippedValue.
- canonicalize_a_search(stripped_value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-hash-for-init>
-fn process_hash_for_init(value: &str, init_type: PatternInitType) -> String {
- // Step 1. Let strippedValue be the given value with a single leading U+0023 (#) removed, if any.
- let stripped_value = value.strip_prefix('#').unwrap_or(value);
-
- // Step 2. If type is "pattern" then return strippedValue.
- if init_type == PatternInitType::Pattern {
- return stripped_value.to_owned();
- }
-
- // Step 3. Return the result of running canonicalize a hash given strippedValue.
- canonicalize_a_hash(stripped_value)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#url-pattern-create-a-dummy-url>
-fn create_a_dummy_url() -> Url {
- // Step 1. Let dummyInput be "https://dummy.invalid/".
- let dummy_input = "https://dummy.invalid/";
-
- // Step 2. Return the result of running the basic URL parser on dummyInput.
- dummy_input
- .parse()
- .expect("parsing dummy input cannot fail")
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-protocol>
-pub(super) fn canonicalize_a_protocol(value: &str) -> Fallible<String> {
- // Step 1. If value is the empty string, return value.
- if value.is_empty() {
- return Ok(String::new());
- }
-
- // Step 2. Let parseResult be the result of running the basic URL parser
- // given value followed by "://dummy.invalid/".
- let Ok(parse_result) = Url::parse(&format!("{value}://dummy.invalid/")) else {
- // Step 3. If parseResult is failure, then throw a TypeError.
- return Err(Error::Type(format!(
- "Failed to canonicalize {value:?} as a protocol"
- )));
- };
-
- // Step 4. Return parseResult’s scheme.
- Ok(parse_result.scheme().to_owned())
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-username>
-pub(super) fn canonicalize_a_username(input: &str) -> String {
- // Step 1. If value is the empty string, return value.
- if input.is_empty() {
- return input.to_owned();
- }
-
- // Step 2. Let dummyURL be the result of creating a dummy URL.
- let mut dummy_url = create_a_dummy_url();
-
- // Step 3. Set the username given dummyURL and value.
- dummy_url.set_username(input).unwrap();
-
- // Step 4. Return dummyURL’s username.
- dummy_url.username().to_owned()
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-password>
-pub(super) fn canonicalize_a_password(input: &str) -> String {
- // Step 1. If value is the empty string, return value.
- if input.is_empty() {
- return input.to_owned();
- }
-
- // Step 2. Let dummyURL be the result of creating a dummy URL.
- let mut dummy_url = create_a_dummy_url();
-
- // Step 3. Set the password given dummyURL and value.
- dummy_url.set_password(Some(input)).unwrap();
-
- // Step 4. Return dummyURL’s password.
- dummy_url.password().unwrap().to_owned()
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-hostname>
-pub(super) fn canonicalize_a_hostname(input: &str) -> Fallible<String> {
- // Step 1. If value is the empty string, return value.
- if input.is_empty() {
- return Ok(String::new());
- }
-
- // Step 2. Let dummyURL be the result of creating a dummy URL.
- let mut dummy_url = create_a_dummy_url();
-
- // FIXME: The rest of the algorithm needs functionality that the url crate
- // does not expose. We need to figure out if there's a way around that or
- // if we want to reimplement that functionality here
-
- if dummy_url.set_host(Some(input)).is_err() {
- return Err(Error::Type(format!(
- "Failed to canonicalize hostname: {input:?}"
- )));
- }
-
- Ok(dummy_url.host_str().unwrap().to_owned())
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-port>
-pub(super) fn canonicalize_a_port(
- port_value: &str,
- protocol_value: Option<&str>,
-) -> Fallible<String> {
- // Step 1. If portValue is the empty string, return portValue.
- if port_value.is_empty() {
- return Ok(String::new());
- }
-
- // Step 2. Let dummyURL be the result of creating a dummy URL.
- let mut dummy_url = create_a_dummy_url();
-
- // Step 3. If protocolValue was given, then set dummyURL’s scheme to protocolValue.
- if let Some(protocol_value) = protocol_value {
- dummy_url.set_scheme(protocol_value).unwrap();
- }
-
- // Step 4. Let parseResult be the result of running basic URL parser given portValue
- // with dummyURL as url and port state as state override.
- // NOTE: The url crate does not expose these parsing concepts, so we try
- // to recreate the parsing step here.
- let port_value = port_value.trim();
- let Ok(port) = port_value.parse::<u16>() else {
- // Step 5. If parseResult is failure, then throw a TypeError.
- return Err(Error::Type(format!(
- "{port_value:?} is not a valid port number"
- )));
- };
-
- // Step 6. Return dummyURL’s port, serialized, or empty string if it is null.
- if let Some(scheme) = protocol_value {
- if default_port_for_special_scheme(scheme) == Some(port) {
- return Ok(String::new());
- }
- }
- Ok(port.to_string())
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-pathname>
-pub(super) fn canonicalize_a_pathname(value: &str) -> String {
- // Step 1. If value is the empty string, then return value.
- if value.is_empty() {
- return String::new();
- }
-
- // NOTE: This is not what the spec says, but the url crate does not expose the required functionality.
- // TODO: Investigate whether this is different in practice
- let mut dummy_url = create_a_dummy_url();
- dummy_url.set_path(value);
-
- dummy_url.path().to_owned()
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-an-opaque-pathname>
-pub(super) fn canonicalize_an_opaque_pathname(value: &str) -> Fallible<String> {
- // NOTE: The url crate doesn't expose the functionality needed by this algorithm.
- // Instead we create a url with an opaque path that is value and then return that opaque path,
- // which should be equivalent.
- let Ok(url) = Url::parse(&format!("foo:{value}")) else {
- return Err(Error::Type(format!(
- "Could not parse {value:?} as opaque path"
- )));
- };
-
- Ok(url.path().to_owned())
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-search>
-pub(super) fn canonicalize_a_search(value: &str) -> String {
- if value.is_empty() {
- return String::new();
- }
-
- let Ok(url) = Url::parse(&format!("http://example.com?{value}")) else {
- log::warn!("canonicalizing a search should never fail");
- return String::new();
- };
-
- url.query().unwrap_or_default().to_owned()
-}
-
-/// <https://urlpattern.spec.whatwg.org/#canonicalize-a-hash>
-pub(super) fn canonicalize_a_hash(value: &str) -> String {
- if value.is_empty() {
- return String::new();
- }
-
- let Ok(url) = Url::parse(&format!("http://example.com#{value}")) else {
- log::warn!("canonicalizing a hash should never fail");
- return String::new();
- };
-
- url.fragment().unwrap_or_default().to_owned()
-}
-
-/// <https://urlpattern.spec.whatwg.org/#is-an-absolute-pathname>
-fn is_an_absolute_pathname(input: &str, init_type: PatternInitType) -> bool {
- let mut chars = input.chars();
-
- // Step 1. If input is the empty string, then return false.
- let Some(first_char) = chars.next() else {
- return false;
- };
-
- // Step 2. If input[0] is U+002F (/), then return true.
- if first_char == '/' {
- return true;
- }
-
- // Step 3. If type is "url", then return false.
- if init_type == PatternInitType::Url {
- return false;
- }
-
- // Step 4. If input’s code point length is less than 2, then return false.
- let Some(second_char) = chars.next() else {
- return false;
- };
-
- // Step 5. If input[0] is U+005C (\) and input[1] is U+002F (/), then return true.
- if first_char == '\\' && second_char == '/' {
- return true;
- }
-
- // Step 6. If input[0] is U+007B ({) and input[1] is U+002F (/), then return true.
- if first_char == '{' && second_char == '/' {
- return true;
- }
-
- // Step 7. Return false.
- false
-}
-
-/// <https://urlpattern.spec.whatwg.org/#process-a-base-url-string>
-fn process_a_base_url_string(input: &str, init_type: PatternInitType) -> String {
- // Step 1. Assert: input is not null.
- // NOTE: The type system ensures that already
-
- // Step 2. If type is not "pattern" return input.
- if init_type != PatternInitType::Pattern {
- return input.to_owned();
- }
-
- // Step 3. Return the result of escaping a pattern string given input.
- escape_a_pattern_string(input)
-}
-
-/// Implements functionality that is shared between <https://urlpattern.spec.whatwg.org/#escape-a-pattern-string>
-/// and <https://urlpattern.spec.whatwg.org/#escape-a-regexp-string>.
-///
-/// These two algorithms are identical except for the set of characters that they escape, so implementing them
-/// seperately does not make sense.
-fn escape_a_string(input: &str, to_escape: &[char]) -> String {
- // Step 1. Assert: input is an ASCII string.
- debug_assert!(
- input.is_ascii(),
- "Expected input to be ASCII, got {input:?}"
- );
-
- // Step 2. Let result be the empty string.
- let mut result = String::with_capacity(input.len());
-
- // Step 3. Let index be 0.
- // Step 4. While index is less than input’s length:
- // Step 4.1 Let c be input[index].
- // Step 4.2 Increment index by 1.
- for c in input.chars() {
- // Step 4.3 If c is one of: [..] then append "\" to the end of result.
- if to_escape.contains(&c) {
- result.push('\\');
- }
-
- // Step 4.4 Append c to the end of result.
- result.push(c);
- }
-
- // Step 5. Return result.
- result
-}
-
-/// <https://urlpattern.spec.whatwg.org/#escape-a-pattern-string>
-fn escape_a_pattern_string(input: &str) -> String {
- escape_a_string(input, &['+', '*', '?', ':', '{', '}', '(', ')', '\\'])
-}
-
-/// <https://urlpattern.spec.whatwg.org/#escape-a-regexp-string>
-pub(super) fn escape_a_regexp_string(input: &str) -> String {
- escape_a_string(
- input,
- &[
- '.', '+', '*', '?', '^', '$', '{', '}', '(', ')', '[', ']', '|', '/', '\\',
- ],
- )
-}
diff --git a/components/script/dom/urlpattern/tokenizer.rs b/components/script/dom/urlpattern/tokenizer.rs
deleted file mode 100644
index e2d70217c3f..00000000000
--- a/components/script/dom/urlpattern/tokenizer.rs
+++ /dev/null
@@ -1,524 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
-
-use script_bindings::error::{Error, Fallible};
-
-/// <https://urlpattern.spec.whatwg.org/#tokenize>
-pub(super) fn tokenize(input: &str, policy: TokenizePolicy) -> Fallible<Vec<Token>> {
- // Step 1. Let tokenizer be a new tokenizer.
- // Step 2. Set tokenizer’s input to input.
- // Step 3. Set tokenizer’s policy to policy.
- let mut tokenizer = Tokenizer {
- input,
- policy,
- index: 0,
- next_index: 0,
- token_list: vec![],
- code_point: char::MIN,
- };
-
- // Step 4. While tokenizer’s index is less than tokenizer’s input’s code point length:
- while tokenizer.index < tokenizer.input.len() {
- // Step 4.1 Run seek and get the next code point given tokenizer and tokenizer’s index.
- tokenizer.seek_and_get_the_next_code_point(tokenizer.index);
-
- match tokenizer.code_point {
- // Step 4.2 If tokenizer’s code point is U+002A (*):
- '*' => {
- // Step 4.2.1 Run add a token with default position and length given tokenizer and "asterisk".
- tokenizer.add_a_token_with_default_position_and_length(TokenType::Asterisk);
-
- // Step 4.2.2 Continue.
- continue;
- },
- // Step 4.3 If tokenizer’s code point is U+002B (+) or U+003F (?):
- '+' | '?' => {
- // Step 4.3.1 Run add a token with default position and length given tokenizer and "other-modifier".
- tokenizer.add_a_token_with_default_position_and_length(TokenType::OtherModifier);
-
- // Step 4.3.2 Continue.
- continue;
- },
- // Step 4.4 If tokenizer’s code point is U+005C (\):
- '\\' => {
- // Step 4.4.1 If tokenizer’s index is equal to tokenizer’s input’s code point length − 1:
- if tokenizer.is_done() {
- // Step 4.4.1.1 Run process a tokenizing error given tokenizer, tokenizer’s next index,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(tokenizer.next_index, tokenizer.index)?;
-
- // Step 4.4.1.2 Continue.
- continue;
- }
-
- // Step 4.4.2 Let escaped index be tokenizer’s next index.
- let escaped_index = tokenizer.index;
-
- // Step 4.4.3 Run get the next code point given tokenizer.
- tokenizer.get_the_next_code_point();
-
- // Step 4.4.4 Run add a token with default length given tokenizer, "escaped-char",
- // tokenizer’s next index, and escaped index.
- tokenizer.add_a_token_with_default_length(
- TokenType::EscapedChar,
- tokenizer.next_index,
- escaped_index,
- );
-
- // Step 4.4.5 Continue.
- continue;
- },
- // Step 4.5 If tokenizer’s code point is U+007B ({):
- '{' => {
- // Step 4.5.1 Run add a token with default position and length given tokenizer and "open".
- tokenizer.add_a_token_with_default_position_and_length(TokenType::Open);
-
- // Step 4.5.2 Continue.
- continue;
- },
- // Step 4.6 If tokenizer’s code point is U+007D (}):
- '}' => {
- // Step 4.6.1 Run add a token with default position and length given tokenizer and "close".
- tokenizer.add_a_token_with_default_position_and_length(TokenType::Close);
-
- // Step 4.6.2 Continue.
- continue;
- },
- // Step 4.7 If tokenizer’s code point is U+003A (:):
- ':' => {
- // Step 4.7.1 Let name position be tokenizer’s next index.
- let mut name_position = tokenizer.next_index;
-
- // Step 4.7.2 Let name start be name position.
- let name_start = name_position;
-
- // Step 4.7.3 While name position is less than tokenizer’s input’s code point length:
- while name_position < tokenizer.input.len() {
- // Step 4.7.3.1 Run seek and get the next code point given tokenizer and name position.
- tokenizer.seek_and_get_the_next_code_point(name_position);
-
- // Step 4.7.3.2 Let first code point be true if name position equals name start
- // and false otherwise.
- let first_code_point = name_position == name_start;
-
- // Step 4.7.3.3 Let valid code point be the result of running is a valid name
- // code point given tokenizer’s code point and first code point.
- let valid_code_point =
- is_a_valid_name_code_point(tokenizer.code_point, first_code_point);
-
- // Step 4.7.3.4 If valid code point is false break.
- if !valid_code_point {
- break;
- }
-
- // Step 4.6.3.5 Set name position to tokenizer’s next index.
- name_position = tokenizer.next_index;
- }
-
- // Step 4.7.4 If name position is less than or equal to name start:
- if name_position <= name_start {
- // Step 4.7.4.1 Run process a tokenizing error given tokenizer, name start, and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(name_start, tokenizer.index)?;
-
- // Step 4.7.4.2 Continue.
- continue;
- }
-
- // Step 4.7.5 Run add a token with default length given tokenizer, "name", name position,
- // and name start.
- tokenizer.add_a_token_with_default_length(
- TokenType::Name,
- name_position,
- name_start,
- );
-
- // Step 4.7.6 Continue.
- continue;
- },
- // Step 4.8 If tokenizer’s code point is U+0028 (():
- '(' => {
- // Step 4.8.1 Let depth be 1.
- let mut depth = 1;
-
- // Step 4.8.2 Let regexp position be tokenizer’s next index.
- let mut regexp_position = tokenizer.next_index;
-
- // Step 4.8.3 Let regexp start be regexp position.
- let regexp_start = regexp_position;
-
- // Step 4.8.4 Let error be false.
- let mut error = false;
-
- // Step 4.8.5 While regexp position is less than tokenizer’s input’s code point length:
- while regexp_position < tokenizer.input.len() {
- // Step 4.8.5.1 Run seek and get the next code point given tokenizer and regexp position.
- tokenizer.seek_and_get_the_next_code_point(regexp_position);
-
- // Step 4.8.5.2 If tokenizer’s code point is not an ASCII code point:
- if !tokenizer.code_point.is_ascii() {
- // Step 4.8.5.1.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.5.1.2 Set error to true.
- error = true;
-
- // Step 4.8.5.1.2 Break.
- break;
- }
-
- // Step 4.8.5.3 If regexp position equals regexp start and tokenizer’s code point is U+003F (?):
- if regexp_position == regexp_start && tokenizer.code_point == '?' {
- // Step 4.8.5.3.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.5.3.2 Set error to true.
- error = true;
-
- // Step 4.8.5.3.3 Break.
- break;
- }
-
- // Step 4.8.5.4 If tokenizer’s code point is U+005C (\):
- if tokenizer.code_point == '\\' {
- // Step 4.8.5.4.1 If regexp position equals tokenizer’s input’s code point length − 1:
- if tokenizer.is_last_character(regexp_position) {
- // Step 4.8.5.4.1.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.5.4.1.2 Set error to true.
- error = true;
-
- // Step 4.8.5.4.1.3 Break
- break;
- }
-
- // Step 4.8.5.4.2 Run get the next code point given tokenizer.
- tokenizer.get_the_next_code_point();
-
- // Step 4.8.5.4.3 If tokenizer’s code point is not an ASCII code point:
- if !tokenizer.code_point.is_ascii() {
- // Step 4.8.5.4.3.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.5.4.3.2 Set error to true.
- error = true;
-
- // Step 4.8.5.4.3.3 Break
- break;
- }
-
- // Step 4.8.5.4.4 Set regexp position to tokenizer’s next index.
- regexp_position = tokenizer.next_index;
-
- // Step 4.8.5.4.5 Continue.
- continue;
- }
-
- // Step 4.8.5.5 If tokenizer’s code point is U+0029 ()):
- if tokenizer.code_point == ')' {
- // Step 4.8.5.5.1 Decrement depth by 1.
- depth -= 1;
-
- // Step 4.8.5.5.2 If depth is 0:
- if depth == 0 {
- // Step 4.8.5.5.2.1 Set regexp position to tokenizer’s next index.
- regexp_position = tokenizer.next_index;
-
- // Step 4.8.5.5.2.2 Break.
- break;
- }
- }
- // Step 4.8.5.6 Otherwise if tokenizer’s code point is U+0028 (():
- else if tokenizer.code_point == '(' {
- // Step 4.8.5.6.1 Increment depth by 1.
- depth += 1;
-
- // Step 4.8.5.6.2 If regexp position equals tokenizer’s input’s code point length − 1:
- if tokenizer.is_last_character(regexp_position) {
- // Step 4.8.5.6.2.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.5.6.2.2 Set error to true.
- error = true;
-
- // Step 4.8.5.6.2.3 Break
- break;
- }
-
- // Step 4.8.5.6.3 Let temporary position be tokenizer’s next index.
- let temporary_position = tokenizer.next_index;
-
- // Step 4.8.5.6.4 Run get the next code point given tokenizer.
- tokenizer.get_the_next_code_point();
-
- // Step 4.8.5.6.5 If tokenizer’s code point is not U+003F (?):
- if tokenizer.code_point != '?' {
- // Step 4.8.5.6.5.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.5.6.5.2 Set error to true.
- error = true;
-
- // Step 4.8.5.6.5.3 Break.
- break;
- }
-
- // Step 4.8.5.6.6 Set tokenizer’s next index to temporary position.
- tokenizer.next_index = temporary_position;
- }
-
- // Step 4.8.5.7 Set regexp position to tokenizer’s next index.
- regexp_position = tokenizer.next_index;
- }
-
- // Step 4.8.6 If error is true continue.
- if error {
- continue;
- }
-
- // Step 4.8.7 If depth is not zero:
- if depth != 0 {
- // Step 4.8.7.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.7.2 Continue.
- continue;
- }
-
- // Step 4.8.8 Let regexp length be regexp position − regexp start − 1.
- let regexp_length = regexp_position - regexp_start - 1;
-
- // Step 4.8.9 If regexp length is zero:
- if regexp_length == 0 {
- // Step 4.8.9.1 Run process a tokenizing error given tokenizer, regexp start,
- // and tokenizer’s index.
- tokenizer.process_a_tokenizing_error(regexp_start, tokenizer.index)?;
-
- // Step 4.8.9.2 Continue.
- continue;
- }
-
- // Step 4.8.10 Run add a token given tokenizer, "regexp", regexp position,
- // regexp start, and regexp length.
- tokenizer.add_a_token(
- TokenType::Regexp,
- regexp_position,
- regexp_start,
- regexp_length,
- );
-
- // Step 4.8.11 Continue.
- continue;
- },
- _ => {
- // Step 4.9 Run add a token with default position and length given tokenizer and "char".
- tokenizer.add_a_token_with_default_position_and_length(TokenType::Char);
- },
- }
- }
-
- // Step 5. Run add a token with default length given tokenizer, "end", tokenizer’s index, and tokenizer’s index.
- tokenizer.add_a_token_with_default_length(TokenType::End, tokenizer.index, tokenizer.index);
-
- // Step 6.Return tokenizer’s token list.
- Ok(tokenizer.token_list)
-}
-
-/// <https://urlpattern.spec.whatwg.org/#tokenizer>
-struct Tokenizer<'a> {
- /// <https://urlpattern.spec.whatwg.org/#tokenizer-input>
- input: &'a str,
-
- /// <https://urlpattern.spec.whatwg.org/#tokenizer-policy>
- policy: TokenizePolicy,
-
- /// <https://urlpattern.spec.whatwg.org/#tokenizer-index>
- ///
- /// Note that we deviate the from the spec and index bytes, not code points.
- index: usize,
-
- /// <https://urlpattern.spec.whatwg.org/#tokenizer-next-index>
- ///
- /// Note that we deviate the from the spec and index bytes, not code points.
- next_index: usize,
-
- /// <https://urlpattern.spec.whatwg.org/#tokenizer-token-list>
- token_list: Vec<Token<'a>>,
-
- /// <https://urlpattern.spec.whatwg.org/#tokenizer-code-point>
- code_point: char,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#token>
-#[derive(Clone, Copy, Debug)]
-#[allow(dead_code)] // index isn't used yet, because constructor strings aren't parsed
-pub(super) struct Token<'a> {
- /// <https://urlpattern.spec.whatwg.org/#token-index>
- pub(super) index: usize,
-
- /// <https://urlpattern.spec.whatwg.org/#token-value>
- pub(super) value: &'a str,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type>
- pub(super) token_type: TokenType,
-}
-
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub(super) enum TokenType {
- /// <https://urlpattern.spec.whatwg.org/#token-type-open>
- Open,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-close>
- Close,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-regexp>
- Regexp,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-name>
- Name,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-char>
- Char,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-escaped-char>
- EscapedChar,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-other-modifier>
- OtherModifier,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-asterisk>
- Asterisk,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-end>
- End,
-
- /// <https://urlpattern.spec.whatwg.org/#token-type-invalid-char>
- InvalidChar,
-}
-
-/// <https://urlpattern.spec.whatwg.org/#tokenize-policy>
-#[derive(Clone, Copy, Debug, Eq, PartialEq)]
-pub(super) enum TokenizePolicy {
- /// <https://urlpattern.spec.whatwg.org/#tokenize-policy-strict>
- Strict,
-
- /// <https://urlpattern.spec.whatwg.org/#tokenize-policy-lenient>
- Lenient,
-}
-
-impl Tokenizer<'_> {
- fn is_last_character(&self, position: usize) -> bool {
- self.input[position..].chars().count() == 1
- }
-
- fn is_done(&self) -> bool {
- self.input[self.next_index..].is_empty()
- }
-
- /// <https://urlpattern.spec.whatwg.org/#get-the-next-code-point>
- fn get_the_next_code_point(&mut self) {
- // Step 1. Set tokenizer’s code point to the Unicode code point in tokenizer’s
- // input at the position indicated by tokenizer’s next index.
- self.code_point = self.input[self.next_index..]
- .chars()
- .next()
- .expect("URLPattern tokenizer is trying to read out of bounds");
-
- // Step 2. Increment tokenizer’s next index by 1.
- // NOTE: Because our next_index is indexing bytes (not code points) we use
- // the utf8 length of the code point instead.
- self.next_index = self.next_index.wrapping_add(self.code_point.len_utf8());
- }
-
- /// <https://urlpattern.spec.whatwg.org/#seek-and-get-the-next-code-point>
- fn seek_and_get_the_next_code_point(&mut self, index: usize) {
- // Step 1. Set tokenizer’s next index to index.
- self.next_index = index;
-
- // Step 2. Run get the next code point given tokenizer.
- self.get_the_next_code_point();
- }
-
- /// <https://urlpattern.spec.whatwg.org/#add-a-token>
- fn add_a_token(
- &mut self,
- token_type: TokenType,
- next_position: usize,
- value_position: usize,
- value_length: usize,
- ) {
- // Step 1. Let token be a new token.
- // Step 2. Set token’s type to type.
- // Step 3. Set token’s index to tokenizer’s index.
- // Step 4. Set token’s value to the code point substring from value position
- // with length value length within tokenizer’s input.
- let token = Token {
- token_type,
- index: self.index,
- value: &self.input[value_position..][..value_length],
- };
-
- // Step 5. Append token to the back of tokenizer’s token list.
- self.token_list.push(token);
-
- // Step 6. Set tokenizer’s index to next position.
- self.index = next_position;
- }
-
- /// <https://urlpattern.spec.whatwg.org/#add-a-token-with-default-position-and-length>
- fn add_a_token_with_default_position_and_length(&mut self, token_type: TokenType) {
- // Step 1. Run add a token with default length given tokenizer, type,
- // tokenizer’s next index, and tokenizer’s index.
- self.add_a_token_with_default_length(token_type, self.next_index, self.index);
- }
-
- /// <https://urlpattern.spec.whatwg.org/#add-a-token-with-default-length>
- fn add_a_token_with_default_length(
- &mut self,
- token_type: TokenType,
- next_position: usize,
- value_position: usize,
- ) {
- // Step 1. Let computed length be next position − value position.
- let computed_length = next_position - value_position;
-
- // Step 2. Run add a token given tokenizer, type, next position, value position, and computed length.
- self.add_a_token(token_type, next_position, value_position, computed_length);
- }
-
- /// <https://urlpattern.spec.whatwg.org/#process-a-tokenizing-error>
- fn process_a_tokenizing_error(
- &mut self,
- next_position: usize,
- value_position: usize,
- ) -> Fallible<()> {
- // Step 1. If tokenizer’s policy is "strict", then throw a TypeError.
- if self.policy == TokenizePolicy::Strict {
- return Err(Error::Type("Failed to tokenize URL pattern".into()));
- }
-
- // Step 2. Assert: tokenizer’s policy is "lenient".
- debug_assert_eq!(self.policy, TokenizePolicy::Lenient);
-
- // Step 3. Run add a token with default length given tokenizer, "invalid-char",
- // next position, and value position.
- self.add_a_token_with_default_length(TokenType::InvalidChar, next_position, value_position);
-
- Ok(())
- }
-}
-
-/// <https://urlpattern.spec.whatwg.org/#is-a-valid-name-code-point>
-fn is_a_valid_name_code_point(code_point: char, first: bool) -> bool {
- // FIXME: implement this check
- _ = first;
- code_point.is_alphabetic()
-}
diff --git a/components/script_bindings/webidls/URLPattern.webidl b/components/script_bindings/webidls/URLPattern.webidl
index 85c0c468fb5..f61b65702bc 100644
--- a/components/script_bindings/webidls/URLPattern.webidl
+++ b/components/script_bindings/webidls/URLPattern.webidl
@@ -4,16 +4,16 @@
// https://urlpattern.spec.whatwg.org/#urlpattern
-typedef /* USVString or */ URLPatternInit URLPatternInput;
+typedef (USVString or URLPatternInit) URLPatternInput;
[Exposed=(Window,Worker), Pref="dom_urlpattern_enabled"]
interface URLPattern {
-// constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {});
+ [Throws] constructor(URLPatternInput input, USVString baseURL, optional URLPatternOptions options = {});
[Throws] constructor(optional URLPatternInput input = {}, optional URLPatternOptions options = {});
-// boolean test(optional URLPatternInput input = {}, optional USVString baseURL);
+ // [Throws] boolean test(optional URLPatternInput input = {}, optional USVString baseURL);
-// URLPatternResult? exec(optional URLPatternInput input = {}, optional USVString baseURL);
+ // [Throws] URLPatternResult? exec(optional URLPatternInput input = {}, optional USVString baseURL);
readonly attribute USVString protocol;
readonly attribute USVString username;
diff --git a/components/shared/constellation/structured_data/serializable.rs b/components/shared/constellation/structured_data/serializable.rs
index abc05ad5758..22370087665 100644
--- a/components/shared/constellation/structured_data/serializable.rs
+++ b/components/shared/constellation/structured_data/serializable.rs
@@ -221,9 +221,9 @@ impl BlobImpl {
}
/// Construct a BlobImpl from a slice of a parent.
- pub fn new_sliced(rel_pos: RelativePos, parent: BlobId, type_string: String) -> BlobImpl {
+ pub fn new_sliced(range: RelativePos, parent: BlobId, type_string: String) -> BlobImpl {
let blob_id = BlobId::new();
- let blob_data = BlobData::Sliced(parent, rel_pos);
+ let blob_data = BlobData::Sliced(parent, range);
BlobImpl {
blob_id,
type_string,
diff --git a/components/shared/net/filemanager_thread.rs b/components/shared/net/filemanager_thread.rs
index e55fbefcefc..0e9014e1670 100644
--- a/components/shared/net/filemanager_thread.rs
+++ b/components/shared/net/filemanager_thread.rs
@@ -39,7 +39,7 @@ pub enum FileTokenCheck {
/// Relative slice positions of a sequence,
/// whose semantic should be consistent with (start, end) parameters in
/// <https://w3c.github.io/FileAPI/#dfn-slice>
-#[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)]
+#[derive(Clone, Copy, Debug, Deserialize, MallocSizeOf, Serialize)]
pub struct RelativePos {
/// Relative to first byte if non-negative,
/// relative to one past last byte if negative,
diff --git a/tests/wpt/meta/MANIFEST.json b/tests/wpt/meta/MANIFEST.json
index 1469a123dd5..df2beac06bd 100644
--- a/tests/wpt/meta/MANIFEST.json
+++ b/tests/wpt/meta/MANIFEST.json
@@ -627813,7 +627813,7 @@
]
],
"XMLSerializer-serializeToString.html": [
- "6c294e464a5dc787abd4d10281ab2fe0555a0a3c",
+ "352a62c7d5db0710da6819bbc094ebfae46f4099",
[
null,
{}
diff --git a/tests/wpt/meta/urlpattern/urlpattern.any.js.ini b/tests/wpt/meta/urlpattern/urlpattern.any.js.ini
index 74d44f4fdb7..7248fced522 100644
--- a/tests/wpt/meta/urlpattern/urlpattern.any.js.ini
+++ b/tests/wpt/meta/urlpattern/urlpattern.any.js.ini
@@ -581,9 +581,6 @@
[Pattern: [{"pathname":"/foo/bar"}\] Inputs: ["./foo/bar","https://example.com"\]]
expected: FAIL
- [Pattern: [{"pathname":"/foo/bar"}\] Inputs: [{"pathname":"/foo/bar"},"https://example.com"\]]
- expected: FAIL
-
[Pattern: ["https://example.com:8080/foo?bar#baz"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
@@ -932,6 +929,12 @@
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
+ [Pattern: [{"hostname":"bad\\\\:hostname"}\] Inputs: undefined]
+ expected: FAIL
+
+ [Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
+ expected: FAIL
+
[urlpattern.any.sharedworker.html]
expected: ERROR
@@ -1519,9 +1522,6 @@
[Pattern: [{"pathname":"/foo/bar"}\] Inputs: ["./foo/bar","https://example.com"\]]
expected: FAIL
- [Pattern: [{"pathname":"/foo/bar"}\] Inputs: [{"pathname":"/foo/bar"},"https://example.com"\]]
- expected: FAIL
-
[Pattern: ["https://example.com:8080/foo?bar#baz"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
@@ -1870,6 +1870,12 @@
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
+ [Pattern: [{"hostname":"bad\\\\:hostname"}\] Inputs: undefined]
+ expected: FAIL
+
+ [Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
+ expected: FAIL
+
[urlpattern.any.serviceworker.html]
expected: ERROR
diff --git a/tests/wpt/meta/urlpattern/urlpattern.https.any.js.ini b/tests/wpt/meta/urlpattern/urlpattern.https.any.js.ini
index 1b230cf4b42..f1b0add7805 100644
--- a/tests/wpt/meta/urlpattern/urlpattern.https.any.js.ini
+++ b/tests/wpt/meta/urlpattern/urlpattern.https.any.js.ini
@@ -584,9 +584,6 @@
[Pattern: [{"pathname":"/foo/bar"}\] Inputs: ["./foo/bar","https://example.com"\]]
expected: FAIL
- [Pattern: [{"pathname":"/foo/bar"}\] Inputs: [{"pathname":"/foo/bar"},"https://example.com"\]]
- expected: FAIL
-
[Pattern: ["https://example.com:8080/foo?bar#baz"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
@@ -935,6 +932,12 @@
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
+ [Pattern: [{"hostname":"bad\\\\:hostname"}\] Inputs: undefined]
+ expected: FAIL
+
+ [Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
+ expected: FAIL
+
[urlpattern.https.any.worker.html]
[Pattern: [{"pathname":"/foo/bar"}\] Inputs: [{"pathname":"/foo/bar"}\]]
@@ -1519,9 +1522,6 @@
[Pattern: [{"pathname":"/foo/bar"}\] Inputs: ["./foo/bar","https://example.com"\]]
expected: FAIL
- [Pattern: [{"pathname":"/foo/bar"}\] Inputs: [{"pathname":"/foo/bar"},"https://example.com"\]]
- expected: FAIL
-
[Pattern: ["https://example.com:8080/foo?bar#baz"\] Inputs: [{"pathname":"/foo","search":"bar","hash":"baz","baseURL":"https://example.com:8080"}\]]
expected: FAIL
@@ -1870,6 +1870,12 @@
[Pattern: ["https://{sub.}?example{.com/}foo"\] Inputs: ["https://example.com/foo"\]]
expected: FAIL
+ [Pattern: [{"hostname":"bad\\\\:hostname"}\] Inputs: undefined]
+ expected: FAIL
+
+ [Pattern: [{"pathname":"/foo","baseURL":""}\] Inputs: undefined]
+ expected: FAIL
+
[urlpattern.https.any.serviceworker.html]
expected: ERROR
diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json
index 78b1ca5e8b3..7035ae424dc 100644
--- a/tests/wpt/mozilla/meta/MANIFEST.json
+++ b/tests/wpt/mozilla/meta/MANIFEST.json
@@ -60,6 +60,13 @@
{}
]
],
+ "slice-blob-twice-crash.html": [
+ "94227dcc74d80dae19b39df025708ffc24ee78c5",
+ [
+ null,
+ {}
+ ]
+ ],
"test-wait-crash.html": [
"2419da6af0c278a17b9ff974d4418f9e386ef3e0",
[
diff --git a/tests/wpt/mozilla/tests/mozilla/slice-blob-twice-crash.html b/tests/wpt/mozilla/tests/mozilla/slice-blob-twice-crash.html
new file mode 100644
index 00000000000..94227dcc74d
--- /dev/null
+++ b/tests/wpt/mozilla/tests/mozilla/slice-blob-twice-crash.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<script>
+ (new Blob()).slice().slice().size;
+</script>
+
diff --git a/tests/wpt/tests/domparsing/XMLSerializer-serializeToString.html b/tests/wpt/tests/domparsing/XMLSerializer-serializeToString.html
index 6c294e464a5..352a62c7d5d 100644
--- a/tests/wpt/tests/domparsing/XMLSerializer-serializeToString.html
+++ b/tests/wpt/tests/domparsing/XMLSerializer-serializeToString.html
@@ -256,6 +256,10 @@ test(function () {
root.setAttributeNS(XMLNS_URI, 'xmlns:foo', '');
assert_equals(serialize(root), '<root xmlns="" xmlns:foo=""/>');
}, 'Check if a prefix bound to an empty namespace URI ("no namespace") serialize');
+
+test(function() {
+ assert_equals(serialize(document.createAttribute("foobar")), "")
+}, 'Attribute nodes are serialized as the empty string')
</script>
</body>
</html>