aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/canvas/backend.rs63
-rw-r--r--components/canvas/canvas_data.rs14
-rw-r--r--components/canvas/raqote_backend.rs71
-rw-r--r--components/devtools/actors/inspector/node.rs15
-rw-r--r--components/layout/dom.rs12
-rw-r--r--components/layout/replaced.rs35
-rw-r--r--components/layout/table/construct.rs27
-rw-r--r--components/script/canvas_context.rs6
-rw-r--r--components/script/dom/canvasrenderingcontext2d.rs8
-rw-r--r--components/script/dom/element.rs24
-rw-r--r--components/script/dom/gpucanvascontext.rs3
-rw-r--r--components/script/dom/htmlcanvaselement.rs4
-rw-r--r--components/script/dom/htmltablecellelement.rs35
-rw-r--r--components/script/dom/htmltablecolelement.rs17
-rw-r--r--components/script/dom/macros.rs20
-rw-r--r--components/script/dom/node.rs45
-rw-r--r--components/script/dom/shadowroot.rs9
-rw-r--r--components/script/dom/webgl2renderingcontext.rs4
-rw-r--r--components/script/dom/webglrenderingcontext.rs8
-rw-r--r--components/script/dom/webgpu/gpucanvascontext.rs9
-rw-r--r--components/script/dom/window.rs8
-rw-r--r--components/script_bindings/codegen/Bindings.conf2
-rw-r--r--components/script_bindings/webidls/ShadowRoot.webidl2
-rw-r--r--components/servo/lib.rs8
-rw-r--r--components/shared/devtools/lib.rs9
-rw-r--r--components/shared/script_layout/lib.rs10
-rw-r--r--components/webdriver_server/actions.rs7
-rw-r--r--components/webdriver_server/capabilities.rs14
-rw-r--r--components/webdriver_server/lib.rs88
29 files changed, 308 insertions, 269 deletions
diff --git a/components/canvas/backend.rs b/components/canvas/backend.rs
index c83eebe3bee..53acbea8b8d 100644
--- a/components/canvas/backend.rs
+++ b/components/canvas/backend.rs
@@ -2,8 +2,12 @@
* 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 canvas_traits::canvas::{FillOrStrokeStyle, LineCapStyle, LineJoinStyle};
+use canvas_traits::canvas::{
+ CompositionOrBlending, FillOrStrokeStyle, LineCapStyle, LineJoinStyle,
+};
+use euclid::Angle;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
+use lyon_geom::Arc;
use style::color::AbsoluteColor;
use crate::canvas_data::{CanvasPaintState, Filter, TextRun};
@@ -14,10 +18,10 @@ pub(crate) trait Backend: Clone + Sized {
type Color: Clone;
type DrawOptions: DrawOptionsHelpers + Clone;
type CompositionOp;
- type CompositionOrBlending;
type DrawTarget: GenericDrawTarget<Self>;
type PathBuilder: GenericPathBuilder<Self>;
type SourceSurface;
+ type Bytes<'a>: AsRef<[u8]>;
type Path: PathHelpers<Self> + Clone;
type GradientStop;
type GradientStops;
@@ -39,7 +43,7 @@ pub(crate) trait Backend: Clone + Sized {
);
fn set_global_composition(
&mut self,
- op: Self::CompositionOrBlending,
+ op: CompositionOrBlending,
state: &mut CanvasPaintState<'_, Self>,
);
fn create_drawtarget(&self, size: Size2D<u64>) -> Self::DrawTarget;
@@ -95,7 +99,6 @@ pub(crate) trait GenericDrawTarget<B: Backend> {
fn pop_clip(&mut self);
fn push_clip(&mut self, path: &B::Path);
fn set_transform(&mut self, matrix: &Transform2D<f32>);
- fn snapshot(&self) -> B::SourceSurface;
fn stroke(
&mut self,
path: &B::Path,
@@ -118,7 +121,8 @@ pub(crate) trait GenericDrawTarget<B: Backend> {
stroke_options: &B::StrokeOptions,
draw_options: &B::DrawOptions,
);
- fn snapshot_data(&self) -> &[u8];
+ fn surface(&self) -> B::SourceSurface;
+ fn bytes(&'_ self) -> B::Bytes<'_>;
}
/// A generic PathBuilder that abstracts the interface for azure's and raqote's PathBuilder.
@@ -148,7 +152,54 @@ pub(crate) trait GenericPathBuilder<B: Backend> {
start_angle: f32,
end_angle: f32,
anticlockwise: bool,
- );
+ ) {
+ let mut start = Angle::radians(start_angle);
+ let mut end = Angle::radians(end_angle);
+
+ // Wrap angles mod 2 * PI if necessary
+ if !anticlockwise && start > end + Angle::two_pi() ||
+ anticlockwise && end > start + Angle::two_pi()
+ {
+ start = start.positive();
+ end = end.positive();
+ }
+
+ // Calculate the total arc we're going to sweep.
+ let sweep = match anticlockwise {
+ true => {
+ if end - start == Angle::two_pi() {
+ -Angle::two_pi()
+ } else if end > start {
+ -(Angle::two_pi() - (end - start))
+ } else {
+ -(start - end)
+ }
+ },
+ false => {
+ if start - end == Angle::two_pi() {
+ Angle::two_pi()
+ } else if start > end {
+ Angle::two_pi() - (start - end)
+ } else {
+ end - start
+ }
+ },
+ };
+
+ let arc: Arc<f32> = Arc {
+ center: origin,
+ radii: Vector2D::new(radius_x, radius_y),
+ start_angle: start,
+ sweep_angle: sweep,
+ x_rotation: Angle::radians(rotation_angle),
+ };
+
+ self.line_to(arc.from());
+
+ arc.for_each_quadratic_bezier(&mut |q| {
+ self.quadratic_curve_to(&q.ctrl, &q.to);
+ });
+ }
fn get_current_point(&mut self) -> Option<Point2D<f32>>;
fn line_to(&mut self, point: Point2D<f32>);
fn move_to(&mut self, point: Point2D<f32>);
diff --git a/components/canvas/canvas_data.rs b/components/canvas/canvas_data.rs
index 7d8b4a9cdbc..ea30589d0af 100644
--- a/components/canvas/canvas_data.rs
+++ b/components/canvas/canvas_data.rs
@@ -426,7 +426,7 @@ impl<'a, B: Backend> CanvasData<'a, B> {
flags: ImageDescriptorFlags::empty(),
};
let data =
- SerializableImageData::Raw(IpcSharedMemory::from_bytes(draw_target.snapshot_data()));
+ SerializableImageData::Raw(IpcSharedMemory::from_bytes(draw_target.bytes().as_ref()));
compositor_api.update_images(vec![ImageUpdate::AddImage(image_key, descriptor, data)]);
CanvasData {
state: backend.new_paint_state(),
@@ -1183,7 +1183,7 @@ impl<'a, B: Backend> CanvasData<'a, B> {
self.state.draw_options.set_alpha(alpha);
}
- pub(crate) fn set_global_composition(&mut self, op: B::CompositionOrBlending) {
+ pub(crate) fn set_global_composition(&mut self, op: CompositionOrBlending) {
self.backend.set_global_composition(op, &mut self.state);
}
@@ -1209,7 +1209,7 @@ impl<'a, B: Backend> CanvasData<'a, B> {
flags: ImageDescriptorFlags::empty(),
};
let data = SerializableImageData::Raw(IpcSharedMemory::from_bytes(
- self.drawtarget.snapshot_data(),
+ self.drawtarget.bytes().as_ref(),
));
self.compositor_api
@@ -1292,7 +1292,7 @@ impl<'a, B: Backend> CanvasData<'a, B> {
let mut new_draw_target = self.create_draw_target_for_shadow(&shadow_src_rect);
draw_shadow_source(&mut new_draw_target);
self.drawtarget.draw_surface_with_shadow(
- new_draw_target.snapshot(),
+ new_draw_target.surface(),
&Point2D::new(shadow_src_rect.origin.x, shadow_src_rect.origin.y),
&self.state.shadow_color,
&Vector2D::new(
@@ -1323,11 +1323,11 @@ impl<'a, B: Backend> CanvasData<'a, B> {
{
vec![]
} else {
- let bytes = self.drawtarget.snapshot_data();
- pixels::rgba8_get_rect(bytes, canvas_size, read_rect).to_vec()
+ pixels::rgba8_get_rect(self.drawtarget.bytes().as_ref(), canvas_size, read_rect)
+ .to_vec()
}
} else {
- self.drawtarget.snapshot_data().to_vec()
+ self.drawtarget.bytes().as_ref().to_vec()
};
Snapshot::from_vec(
diff --git a/components/canvas/raqote_backend.rs b/components/canvas/raqote_backend.rs
index e88de701336..efe0ffd05b8 100644
--- a/components/canvas/raqote_backend.rs
+++ b/components/canvas/raqote_backend.rs
@@ -7,12 +7,10 @@ use std::collections::HashMap;
use canvas_traits::canvas::*;
use cssparser::color::clamp_unit_f32;
-use euclid::Angle;
use euclid::default::{Point2D, Rect, Size2D, Transform2D, Vector2D};
use font_kit::font::Font;
use fonts::{ByteIndex, FontIdentifier, FontTemplateRefMethods};
use log::warn;
-use lyon_geom::Arc;
use range::Range;
use raqote::PathOp;
use style::color::AbsoluteColor;
@@ -40,10 +38,10 @@ impl Backend for RaqoteBackend {
type Color = raqote::SolidSource;
type DrawOptions = raqote::DrawOptions;
type CompositionOp = raqote::BlendMode;
- type CompositionOrBlending = CompositionOrBlending;
type DrawTarget = raqote::DrawTarget;
type PathBuilder = PathBuilder;
type SourceSurface = Vec<u8>; // TODO: See if we can avoid the alloc (probably?)
+ type Bytes<'a> = &'a [u8];
type Path = raqote::Path;
type GradientStop = raqote::GradientStop;
type GradientStops = Vec<raqote::GradientStop>;
@@ -84,7 +82,7 @@ impl Backend for RaqoteBackend {
fn set_global_composition(
&mut self,
- op: Self::CompositionOrBlending,
+ op: CompositionOrBlending,
state: &mut CanvasPaintState<'_, Self>,
) {
state.draw_options.blend_mode = op.to_raqote_style();
@@ -598,8 +596,8 @@ impl GenericDrawTarget<RaqoteBackend> for raqote::DrawTarget {
fn set_transform(&mut self, matrix: &Transform2D<f32>) {
self.set_transform(matrix);
}
- fn snapshot(&self) -> <RaqoteBackend as Backend>::SourceSurface {
- self.snapshot_data().to_vec()
+ fn surface(&self) -> <RaqoteBackend as Backend>::SourceSurface {
+ self.bytes().to_vec()
}
fn stroke(
&mut self,
@@ -658,7 +656,7 @@ impl GenericDrawTarget<RaqoteBackend> for raqote::DrawTarget {
);
}
#[allow(unsafe_code)]
- fn snapshot_data(&self) -> &[u8] {
+ fn bytes(&self) -> &[u8] {
let v = self.get_data();
unsafe { std::slice::from_raw_parts(v.as_ptr() as *const u8, std::mem::size_of_val(v)) }
}
@@ -701,6 +699,7 @@ impl GenericPathBuilder<RaqoteBackend> for PathBuilder {
anticlockwise,
);
}
+
fn bezier_curve_to(
&mut self,
control_point1: &Point2D<f32>,
@@ -716,66 +715,10 @@ impl GenericPathBuilder<RaqoteBackend> for PathBuilder {
control_point3.y,
);
}
+
fn close(&mut self) {
self.0.as_mut().unwrap().close();
}
- fn ellipse(
- &mut self,
- origin: Point2D<f32>,
- radius_x: f32,
- radius_y: f32,
- rotation_angle: f32,
- start_angle: f32,
- end_angle: f32,
- anticlockwise: bool,
- ) {
- let mut start = Angle::radians(start_angle);
- let mut end = Angle::radians(end_angle);
-
- // Wrap angles mod 2 * PI if necessary
- if !anticlockwise && start > end + Angle::two_pi() ||
- anticlockwise && end > start + Angle::two_pi()
- {
- start = start.positive();
- end = end.positive();
- }
-
- // Calculate the total arc we're going to sweep.
- let sweep = match anticlockwise {
- true => {
- if end - start == Angle::two_pi() {
- -Angle::two_pi()
- } else if end > start {
- -(Angle::two_pi() - (end - start))
- } else {
- -(start - end)
- }
- },
- false => {
- if start - end == Angle::two_pi() {
- Angle::two_pi()
- } else if start > end {
- Angle::two_pi() - (start - end)
- } else {
- end - start
- }
- },
- };
-
- let arc: Arc<f32> = Arc {
- center: origin,
- radii: Vector2D::new(radius_x, radius_y),
- start_angle: start,
- sweep_angle: sweep,
- x_rotation: Angle::radians(rotation_angle),
- };
-
- self.line_to(arc.from());
-
- arc.for_each_quadratic_bezier(&mut |q| {
- self.quadratic_curve_to(&q.ctrl, &q.to);
- });
- }
fn svg_arc(
&mut self,
diff --git a/components/devtools/actors/inspector/node.rs b/components/devtools/actors/inspector/node.rs
index 10ff9801844..a731f15b2d8 100644
--- a/components/devtools/actors/inspector/node.rs
+++ b/components/devtools/actors/inspector/node.rs
@@ -78,6 +78,18 @@ pub struct NodeActorMsg {
shadow_root_mode: Option<String>,
traits: HashMap<String, ()>,
attrs: Vec<AttrMsg>,
+
+ /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise
+ #[serde(skip_serializing_if = "Option::is_none")]
+ name: Option<String>,
+
+ /// The `DOCTYPE` public identifier if this is a `DocumentType` node, `None` otherwise
+ #[serde(skip_serializing_if = "Option::is_none")]
+ public_id: Option<String>,
+
+ /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise
+ #[serde(skip_serializing_if = "Option::is_none")]
+ system_id: Option<String>,
}
pub struct NodeActor {
@@ -276,6 +288,9 @@ impl NodeInfoToProtocol for NodeInfo {
value: attr.value,
})
.collect(),
+ name: self.doctype_name,
+ public_id: self.doctype_public_identifier,
+ system_id: self.doctype_system_identifier,
}
}
}
diff --git a/components/layout/dom.rs b/components/layout/dom.rs
index add4b3ac2d5..8f2697e670a 100644
--- a/components/layout/dom.rs
+++ b/components/layout/dom.rs
@@ -15,8 +15,7 @@ use script_layout_interface::wrapper_traits::{
LayoutDataTrait, LayoutNode, ThreadSafeLayoutElement, ThreadSafeLayoutNode,
};
use script_layout_interface::{
- GenericLayoutDataTrait, HTMLCanvasDataSource, LayoutElementType,
- LayoutNodeType as ScriptLayoutNodeType,
+ GenericLayoutDataTrait, LayoutElementType, LayoutNodeType as ScriptLayoutNodeType,
};
use servo_arc::Arc as ServoArc;
use style::properties::ComputedValues;
@@ -29,7 +28,7 @@ use crate::flow::BlockLevelBox;
use crate::flow::inline::InlineItem;
use crate::fragment_tree::Fragment;
use crate::geom::PhysicalSize;
-use crate::replaced::{CanvasInfo, CanvasSource};
+use crate::replaced::CanvasInfo;
use crate::table::TableLevelBox;
use crate::taffy::TaffyItemBox;
@@ -220,12 +219,7 @@ where
fn as_canvas(self) -> Option<(CanvasInfo, PhysicalSize<f64>)> {
let node = self.to_threadsafe();
let canvas_data = node.canvas_data()?;
- let source = match canvas_data.source {
- HTMLCanvasDataSource::WebGL(texture_id) => CanvasSource::WebGL(texture_id),
- HTMLCanvasDataSource::Image(image_key) => CanvasSource::Image(image_key),
- HTMLCanvasDataSource::WebGPU(image_key) => CanvasSource::WebGPU(image_key),
- HTMLCanvasDataSource::Empty => CanvasSource::Empty,
- };
+ let source = canvas_data.source;
Some((
CanvasInfo { source },
PhysicalSize::new(canvas_data.width.into(), canvas_data.height.into()),
diff --git a/components/layout/replaced.rs b/components/layout/replaced.rs
index b82fb947074..bbebc57aa97 100644
--- a/components/layout/replaced.rs
+++ b/components/layout/replaced.rs
@@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use std::cell::LazyCell;
-use std::fmt;
use std::sync::Arc;
use app_units::Au;
@@ -96,33 +95,9 @@ impl NaturalSizes {
}
}
-#[derive(MallocSizeOf)]
-pub(crate) enum CanvasSource {
- WebGL(ImageKey),
- Image(ImageKey),
- WebGPU(ImageKey),
- /// transparent black
- Empty,
-}
-
-impl fmt::Debug for CanvasSource {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- write!(
- f,
- "{}",
- match *self {
- CanvasSource::WebGL(_) => "WebGL",
- CanvasSource::Image(_) => "Image",
- CanvasSource::WebGPU(_) => "WebGPU",
- CanvasSource::Empty => "Empty",
- }
- )
- }
-}
-
#[derive(Debug, MallocSizeOf)]
pub(crate) struct CanvasInfo {
- pub source: CanvasSource,
+ pub source: Option<ImageKey>,
}
#[derive(Debug, MallocSizeOf)]
@@ -388,12 +363,10 @@ impl ReplacedContents {
return vec![];
}
- let image_key = match canvas_info.source {
- CanvasSource::WebGL(image_key) => image_key,
- CanvasSource::WebGPU(image_key) => image_key,
- CanvasSource::Image(image_key) => image_key,
- CanvasSource::Empty => return vec![],
+ let Some(image_key) = canvas_info.source else {
+ return vec![];
};
+
vec![Fragment::Image(ArcRefCell::new(ImageFragment {
base: self.base_fragment_info.into(),
style: style.clone(),
diff --git a/components/layout/table/construct.rs b/components/layout/table/construct.rs
index f20360d3b56..56e11320be4 100644
--- a/components/layout/table/construct.rs
+++ b/components/layout/table/construct.rs
@@ -1019,15 +1019,16 @@ where
DisplayLayoutInternal::TableCell => {
// This value will already have filtered out rowspan=0
// in quirks mode, so we don't have to worry about that.
- //
- // The HTML specification limits the parsed value of `rowspan` to
- // 65534 and `colspan` to 1000, so we also enforce the same limits
- // when dealing with arbitrary DOM elements (perhaps created via
- // script).
let (rowspan, colspan) = if info.pseudo_element_type.is_none() {
let node = info.node.to_threadsafe();
- let rowspan = node.get_rowspan().unwrap_or(1).min(65534) as usize;
- let colspan = node.get_colspan().unwrap_or(1).min(1000) as usize;
+ let rowspan = node.get_rowspan().unwrap_or(1) as usize;
+ let colspan = node.get_colspan().unwrap_or(1) as usize;
+
+ // The HTML specification clamps value of `rowspan` to [0, 65534] and
+ // `colspan` to [1, 1000].
+ assert!((1..=1000).contains(&colspan));
+ assert!((0..=65534).contains(&rowspan));
+
(rowspan, colspan)
} else {
(1, 1)
@@ -1140,21 +1141,19 @@ fn add_column<'dom, Node: NodeExt<'dom>>(
is_anonymous: bool,
) -> ArcRefCell<TableTrack> {
let span = if column_info.pseudo_element_type.is_none() {
- column_info
- .node
- .to_threadsafe()
- .get_span()
- .unwrap_or(1)
- .min(1000) as usize
+ column_info.node.to_threadsafe().get_span().unwrap_or(1)
} else {
1
};
+ // The HTML specification clamps value of `span` for `<col>` to [1, 1000].
+ assert!((1..=1000).contains(&span));
+
let column = ArcRefCell::new(TableTrack {
base: LayoutBoxBase::new(column_info.into(), column_info.style.clone()),
group_index,
is_anonymous,
});
- collection.extend(repeat(column.clone()).take(span));
+ collection.extend(repeat(column.clone()).take(span as usize));
column
}
diff --git a/components/script/canvas_context.rs b/components/script/canvas_context.rs
index d85877c0f41..0a7545e9594 100644
--- a/components/script/canvas_context.rs
+++ b/components/script/canvas_context.rs
@@ -6,8 +6,9 @@
use euclid::default::Size2D;
use script_bindings::root::Dom;
-use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
+use script_layout_interface::HTMLCanvasData;
use snapshot::Snapshot;
+use webrender_api::ImageKey;
use crate::dom::bindings::codegen::UnionTypes::HTMLCanvasElementOrOffscreenCanvas;
use crate::dom::bindings::inheritance::Castable;
@@ -19,7 +20,8 @@ use crate::dom::types::{
};
pub(crate) trait LayoutCanvasRenderingContextHelpers {
- fn canvas_data_source(self) -> HTMLCanvasDataSource;
+ /// `None` is rendered as transparent black (cleared canvas)
+ fn canvas_data_source(self) -> Option<ImageKey>;
}
pub(crate) trait LayoutHTMLCanvasElementHelpers {
diff --git a/components/script/dom/canvasrenderingcontext2d.rs b/components/script/dom/canvasrenderingcontext2d.rs
index 38bd38ad511..046d478e49d 100644
--- a/components/script/dom/canvasrenderingcontext2d.rs
+++ b/components/script/dom/canvasrenderingcontext2d.rs
@@ -7,9 +7,9 @@ use dom_struct::dom_struct;
use euclid::default::Size2D;
use profile_traits::ipc;
use script_bindings::inheritance::Castable;
-use script_layout_interface::HTMLCanvasDataSource;
use servo_url::ServoUrl;
use snapshot::Snapshot;
+use webrender_api::ImageKey;
use crate::canvas_context::{CanvasContext, CanvasHelpers, LayoutCanvasRenderingContextHelpers};
use crate::canvas_state::CanvasState;
@@ -98,13 +98,13 @@ impl CanvasRenderingContext2D {
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, CanvasRenderingContext2D> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
let canvas_state = &self.unsafe_get().canvas_state;
if canvas_state.is_paintable() {
- HTMLCanvasDataSource::Image(canvas_state.image_key())
+ Some(canvas_state.image_key())
} else {
- HTMLCanvasDataSource::Empty
+ None
}
}
}
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 2831fc3d8f0..c040078f707 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -3025,28 +3025,8 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
DomRoot::from_ref(self.upcast())
};
- // Step 3. Unsafely set HTML given target, this, and compliantHTML.
- // Let newChildren be the result of the HTML fragment parsing algorithm.
- let new_children = ServoParser::parse_html_fragment(self, html, true, can_gc);
-
- let context_document = {
- if let Some(template) = self.downcast::<HTMLTemplateElement>() {
- template.Content(can_gc).upcast::<Node>().owner_doc()
- } else {
- self.owner_document()
- }
- };
-
- // Let fragment be a new DocumentFragment whose node document is contextElement's node document.
- let frag = DocumentFragment::new(&context_document, can_gc);
-
- // For each node in newChildren, append node to fragment.
- for child in new_children {
- frag.upcast::<Node>().AppendChild(&child, can_gc).unwrap();
- }
-
- // Replace all with fragment within target.
- Node::replace_all(Some(frag.upcast()), &target, can_gc);
+ // Step 3. Unsafely set HTML given target, this, and compliantHTML
+ Node::unsafely_set_html(&target, self, html, can_gc);
}
/// <https://html.spec.whatwg.org/multipage/#dom-element-gethtml>
diff --git a/components/script/dom/gpucanvascontext.rs b/components/script/dom/gpucanvascontext.rs
index 5304d0f5d3b..2bdabf3e0ab 100644
--- a/components/script/dom/gpucanvascontext.rs
+++ b/components/script/dom/gpucanvascontext.rs
@@ -3,7 +3,6 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use dom_struct::dom_struct;
-use script_layout_interface::HTMLCanvasDataSource;
use crate::dom::bindings::codegen::Bindings::GPUCanvasContextBinding::GPUCanvasContextMethods;
use crate::dom::bindings::codegen::UnionTypes;
@@ -31,7 +30,7 @@ impl GPUCanvasContextMethods<crate::DomTypeHolder> for GPUCanvasContext {
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
unimplemented!()
}
}
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index cc6df183f42..56e008839ba 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -21,7 +21,7 @@ use image::{ColorType, ImageEncoder};
use ipc_channel::ipc::{self as ipcchan};
use js::error::throw_type_error;
use js::rust::{HandleObject, HandleValue};
-use script_layout_interface::{HTMLCanvasData, HTMLCanvasDataSource};
+use script_layout_interface::HTMLCanvasData;
use servo_media::streams::MediaStreamType;
use servo_media::streams::registry::MediaStreamId;
use snapshot::Snapshot;
@@ -201,7 +201,7 @@ impl LayoutHTMLCanvasElementHelpers for LayoutDom<'_, HTMLCanvasElement> {
Some(RenderingContext::WebGL2(context)) => context.to_layout().canvas_data_source(),
#[cfg(feature = "webgpu")]
Some(RenderingContext::WebGPU(context)) => context.to_layout().canvas_data_source(),
- Some(RenderingContext::Placeholder(_)) | None => HTMLCanvasDataSource::Empty,
+ Some(RenderingContext::Placeholder(_)) | None => None,
}
};
diff --git a/components/script/dom/htmltablecellelement.rs b/components/script/dom/htmltablecellelement.rs
index 4f312e928c4..8b553923230 100644
--- a/components/script/dom/htmltablecellelement.rs
+++ b/components/script/dom/htmltablecellelement.rs
@@ -70,13 +70,17 @@ impl HTMLTableCellElementMethods<crate::DomTypeHolder> for HTMLTableCellElement
make_uint_getter!(ColSpan, "colspan", DEFAULT_COLSPAN);
// https://html.spec.whatwg.org/multipage/#dom-tdth-colspan
- make_uint_setter!(SetColSpan, "colspan", DEFAULT_COLSPAN);
+ // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
+ // > the range [1, 1000], and its default value is 1.
+ make_clamped_uint_setter!(SetColSpan, "colspan", 1, 1000, 1);
// https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
make_uint_getter!(RowSpan, "rowspan", DEFAULT_ROWSPAN);
// https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan
- make_uint_setter!(SetRowSpan, "rowspan", DEFAULT_ROWSPAN);
+ // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
+ // > the range [0, 65534], and its default value is 1.
+ make_clamped_uint_setter!(SetRowSpan, "rowspan", 0, 65534, 1);
// https://html.spec.whatwg.org/multipage/#dom-tdth-bgcolor
make_getter!(BgColor, "bgcolor");
@@ -174,23 +178,26 @@ impl VirtualMethods for HTMLTableCellElement {
match *local_name {
local_name!("colspan") => {
let mut attr = AttrValue::from_u32(value.into(), DEFAULT_COLSPAN);
- if let AttrValue::UInt(_, ref mut val) = attr {
- if *val == 0 {
- *val = 1;
- }
+ if let AttrValue::UInt(_, ref mut value) = attr {
+ // From <https://html.spec.whatwg.org/multipage/#dom-tdth-colspan>:
+ // > The colSpan IDL attribute must reflect the colspan content attribute. It is clamped to
+ // > the range [1, 1000], and its default value is 1.
+ *value = (*value).clamp(1, 1000);
}
attr
},
local_name!("rowspan") => {
let mut attr = AttrValue::from_u32(value.into(), DEFAULT_ROWSPAN);
- if let AttrValue::UInt(_, ref mut val) = attr {
- if *val == 0 {
- let node = self.upcast::<Node>();
- let doc = node.owner_doc();
- // rowspan = 0 is not supported in quirks mode
- if doc.quirks_mode() != QuirksMode::NoQuirks {
- *val = 1;
- }
+ if let AttrValue::UInt(_, ref mut value) = attr {
+ // From <https://html.spec.whatwg.org/multipage/#dom-tdth-rowspan>:
+ // > The rowSpan IDL attribute must reflect the rowspan content attribute. It is clamped to
+ // > the range [0, 65534], and its default value is 1.
+ // Note that rowspan = 0 is not supported in quirks mode.
+ let document = self.upcast::<Node>().owner_doc();
+ if document.quirks_mode() != QuirksMode::NoQuirks {
+ *value = (*value).clamp(1, 65534);
+ } else {
+ *value = (*value).clamp(0, 65534);
}
}
attr
diff --git a/components/script/dom/htmltablecolelement.rs b/components/script/dom/htmltablecolelement.rs
index c7ad4afd944..9e8eecf1147 100644
--- a/components/script/dom/htmltablecolelement.rs
+++ b/components/script/dom/htmltablecolelement.rs
@@ -20,8 +20,6 @@ use crate::dom::node::Node;
use crate::dom::virtualmethods::VirtualMethods;
use crate::script_runtime::CanGc;
-const DEFAULT_SPAN: u32 = 1;
-
#[dom_struct]
pub(crate) struct HTMLTableColElement {
htmlelement: HTMLElement,
@@ -62,9 +60,11 @@ impl HTMLTableColElement {
impl HTMLTableColElementMethods<crate::DomTypeHolder> for HTMLTableColElement {
// <https://html.spec.whatwg.org/multipage/#attr-col-span>
- make_uint_getter!(Span, "span", DEFAULT_SPAN);
+ make_uint_getter!(Span, "span", 1);
// <https://html.spec.whatwg.org/multipage/#attr-col-span>
- make_uint_setter!(SetSpan, "span", DEFAULT_SPAN);
+ // > The span IDL attribute must reflect the content attribute of the same name. It is clamped
+ // > to the range [1, 1000], and its default value is 1.
+ make_clamped_uint_setter!(SetSpan, "span", 1, 1000, 1);
}
pub(crate) trait HTMLTableColElementLayoutHelpers<'dom> {
@@ -96,11 +96,12 @@ impl VirtualMethods for HTMLTableColElement {
fn parse_plain_attribute(&self, local_name: &LocalName, value: DOMString) -> AttrValue {
match *local_name {
local_name!("span") => {
- let mut attr = AttrValue::from_u32(value.into(), DEFAULT_SPAN);
+ let mut attr = AttrValue::from_u32(value.into(), 1);
if let AttrValue::UInt(_, ref mut val) = attr {
- if *val == 0 {
- *val = 1;
- }
+ // From <https://html.spec.whatwg.org/multipage/#attr-col-span>:
+ // > The span IDL attribute must reflect the content attribute of the same name.
+ // > It is clamped to the range [1, 1000], and its default value is 1.
+ *val = (*val).clamp(1, 1000);
}
attr
},
diff --git a/components/script/dom/macros.rs b/components/script/dom/macros.rs
index c2f5ba37c21..997341984c6 100644
--- a/components/script/dom/macros.rs
+++ b/components/script/dom/macros.rs
@@ -318,6 +318,26 @@ macro_rules! make_uint_setter(
);
#[macro_export]
+macro_rules! make_clamped_uint_setter(
+ ($attr:ident, $htmlname:tt, $min:expr, $max:expr, $default:expr) => (
+ fn $attr(&self, value: u32) {
+ use $crate::dom::bindings::inheritance::Castable;
+ use $crate::dom::element::Element;
+ use $crate::dom::values::UNSIGNED_LONG_MAX;
+ use $crate::script_runtime::CanGc;
+ let value = if value > UNSIGNED_LONG_MAX {
+ $default
+ } else {
+ value.clamp($min, $max)
+ };
+
+ let element = self.upcast::<Element>();
+ element.set_uint_attribute(&html5ever::local_name!($htmlname), value, CanGc::note())
+ }
+ );
+);
+
+#[macro_export]
macro_rules! make_limited_uint_setter(
($attr:ident, $htmlname:tt, $default:expr) => (
fn $attr(&self, value: u32) -> $crate::dom::bindings::error::ErrorResult {
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index 1117eff6d3c..e9d36a01426 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -110,7 +110,7 @@ use crate::dom::pointerevent::{PointerEvent, PointerId};
use crate::dom::processinginstruction::ProcessingInstruction;
use crate::dom::range::WeakRangeVec;
use crate::dom::raredata::NodeRareData;
-use crate::dom::servoparser::serialize_html_fragment;
+use crate::dom::servoparser::{ServoParser, serialize_html_fragment};
use crate::dom::shadowroot::{IsUserAgentWidget, LayoutShadowRootHelpers, ShadowRoot};
use crate::dom::stylesheetlist::StyleSheetListOwner;
use crate::dom::svgsvgelement::{LayoutSVGSVGElementHelpers, SVGSVGElement};
@@ -316,6 +316,34 @@ impl Node {
}
}
+ /// Implements the "unsafely set HTML" algorithm as specified in:
+ /// <https://html.spec.whatwg.org/multipage/#concept-unsafely-set-html>
+ pub fn unsafely_set_html(
+ target: &Node,
+ context_element: &Element,
+ html: DOMString,
+ can_gc: CanGc,
+ ) {
+ // Step 1. Let newChildren be the result of the HTML fragment parsing algorithm.
+ let new_children = ServoParser::parse_html_fragment(context_element, html, true, can_gc);
+
+ // Step 2. Let fragment be a new DocumentFragment whose node document is contextElement's node document.
+
+ let context_document = context_element.owner_document();
+ let fragment = DocumentFragment::new(&context_document, can_gc);
+
+ // Step 3. For each node in newChildren, append node to fragment.
+ for child in new_children {
+ fragment
+ .upcast::<Node>()
+ .AppendChild(&child, can_gc)
+ .unwrap();
+ }
+
+ // Step 4. Replace all with fragment within target.
+ Node::replace_all(Some(fragment.upcast()), target, can_gc);
+ }
+
pub(crate) fn clean_up_style_and_layout_data(&self) {
self.owner_doc().cancel_animations_for_node(self);
self.style_data.borrow_mut().take();
@@ -1283,6 +1311,21 @@ impl Node {
is_shadow_host,
shadow_root_mode,
display,
+ doctype_name: self
+ .downcast::<DocumentType>()
+ .map(DocumentType::name)
+ .cloned()
+ .map(String::from),
+ doctype_public_identifier: self
+ .downcast::<DocumentType>()
+ .map(DocumentType::public_id)
+ .cloned()
+ .map(String::from),
+ doctype_system_identifier: self
+ .downcast::<DocumentType>()
+ .map(DocumentType::system_id)
+ .cloned()
+ .map(String::from),
}
}
diff --git a/components/script/dom/shadowroot.rs b/components/script/dom/shadowroot.rs
index 72b074ed6f4..14d9c24b10e 100644
--- a/components/script/dom/shadowroot.rs
+++ b/components/script/dom/shadowroot.rs
@@ -453,6 +453,15 @@ impl ShadowRootMethods<crate::DomTypeHolder> for ShadowRoot {
self.slot_assignment_mode
}
+ /// <https://html.spec.whatwg.org/multipage/#dom-shadowroot-sethtmlunsafe>
+ fn SetHTMLUnsafe(&self, html: DOMString, can_gc: CanGc) {
+ // Step 2. Unsafely set HTMl given this, this's shadow host, and complaintHTML
+ let target = self.upcast::<Node>();
+ let context_element = self.Host();
+
+ Node::unsafely_set_html(target, &context_element, html, can_gc);
+ }
+
// https://dom.spec.whatwg.org/#dom-shadowroot-onslotchange
event_handler!(onslotchange, GetOnslotchange, SetOnslotchange);
}
diff --git a/components/script/dom/webgl2renderingcontext.rs b/components/script/dom/webgl2renderingcontext.rs
index 416454d8719..5e538b53b5f 100644
--- a/components/script/dom/webgl2renderingcontext.rs
+++ b/components/script/dom/webgl2renderingcontext.rs
@@ -22,10 +22,10 @@ use js::jsval::{BooleanValue, DoubleValue, Int32Value, NullValue, ObjectValue, U
use js::rust::{CustomAutoRooterGuard, HandleObject, MutableHandleValue};
use js::typedarray::{ArrayBufferView, CreateWith, Float32, Int32Array, Uint32, Uint32Array};
use script_bindings::interfaces::WebGL2RenderingContextHelpers;
-use script_layout_interface::HTMLCanvasDataSource;
use servo_config::pref;
use snapshot::Snapshot;
use url::Host;
+use webrender_api::ImageKey;
use crate::canvas_context::CanvasContext;
use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::{
@@ -4702,7 +4702,7 @@ impl WebGL2RenderingContextMethods<crate::DomTypeHolder> for WebGL2RenderingCont
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGL2RenderingContext> {
#[allow(unsafe_code)]
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
let this = self.unsafe_get();
unsafe { (*this.base.to_layout().unsafe_get()).layout_handle() }
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 9996a3cf504..98170f9655b 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -31,7 +31,6 @@ use js::typedarray::{
};
use net_traits::image_cache::ImageResponse;
use pixels::{self, PixelFormat};
-use script_layout_interface::HTMLCanvasDataSource;
use serde::{Deserialize, Serialize};
use servo_config::pref;
use snapshot::Snapshot;
@@ -875,9 +874,8 @@ impl WebGLRenderingContext {
receiver.recv().unwrap()
}
- pub(crate) fn layout_handle(&self) -> HTMLCanvasDataSource {
- let image_key = self.webrender_image;
- HTMLCanvasDataSource::WebGL(image_key)
+ pub(crate) fn layout_handle(&self) -> Option<ImageKey> {
+ Some(self.webrender_image)
}
// https://www.khronos.org/registry/webgl/extensions/ANGLE_instanced_arrays/
@@ -4829,7 +4827,7 @@ impl WebGLRenderingContextMethods<crate::DomTypeHolder> for WebGLRenderingContex
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, WebGLRenderingContext> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
(*self.unsafe_get()).layout_handle()
}
}
diff --git a/components/script/dom/webgpu/gpucanvascontext.rs b/components/script/dom/webgpu/gpucanvascontext.rs
index c81f96f651f..359b1b14003 100644
--- a/components/script/dom/webgpu/gpucanvascontext.rs
+++ b/components/script/dom/webgpu/gpucanvascontext.rs
@@ -8,7 +8,6 @@ use std::cell::RefCell;
use arrayvec::ArrayVec;
use dom_struct::dom_struct;
use ipc_channel::ipc::{self};
-use script_layout_interface::HTMLCanvasDataSource;
use snapshot::Snapshot;
use webgpu_traits::{
ContextConfiguration, PRESENTATION_BUFFER_COUNT, WebGPU, WebGPUContextId, WebGPURequest,
@@ -227,11 +226,11 @@ impl GPUCanvasContext {
// Internal helper methods
impl GPUCanvasContext {
- fn layout_handle(&self) -> HTMLCanvasDataSource {
+ fn layout_handle(&self) -> Option<ImageKey> {
if self.drawing_buffer.borrow().cleared {
- HTMLCanvasDataSource::Empty
+ None
} else {
- HTMLCanvasDataSource::WebGPU(self.webrender_image)
+ Some(self.webrender_image)
}
}
@@ -301,7 +300,7 @@ impl CanvasContext for GPUCanvasContext {
}
impl LayoutCanvasRenderingContextHelpers for LayoutDom<'_, GPUCanvasContext> {
- fn canvas_data_source(self) -> HTMLCanvasDataSource {
+ fn canvas_data_source(self) -> Option<ImageKey> {
(*self.unsafe_get()).layout_handle()
}
}
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index a685bbb25f2..90782e217b7 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1246,7 +1246,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let rv = jsval_to_webdriver(cx, &self.globalscope, val, realm, can_gc);
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
- chan.send(rv).unwrap();
+ let _ = chan.send(rv);
}
}
@@ -1255,9 +1255,9 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
if let Ok(rv) = rv {
- chan.send(Err(WebDriverJSError::JSException(rv))).unwrap();
+ let _ = chan.send(Err(WebDriverJSError::JSException(rv)));
} else {
- chan.send(rv).unwrap();
+ let _ = chan.send(rv);
}
}
}
@@ -1265,7 +1265,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
fn WebdriverTimeout(&self) {
let opt_chan = self.webdriver_script_chan.borrow_mut().take();
if let Some(chan) = opt_chan {
- chan.send(Err(WebDriverJSError::Timeout)).unwrap();
+ let _ = chan.send(Err(WebDriverJSError::Timeout));
}
}
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index 4ab0b21cabe..6396e3ced0c 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -579,7 +579,7 @@ DOMInterfaces = {
},
'ShadowRoot': {
- 'canGc': ['ElementFromPoint', 'ElementsFromPoint', 'SetInnerHTML', 'GetHTML', 'InnerHTML'],
+ 'canGc': ['SetHTMLUnsafe', 'ElementFromPoint', 'ElementsFromPoint', 'SetInnerHTML', 'GetHTML', 'InnerHTML'],
},
'StaticRange': {
diff --git a/components/script_bindings/webidls/ShadowRoot.webidl b/components/script_bindings/webidls/ShadowRoot.webidl
index 6e3f2032294..cb0926afc10 100644
--- a/components/script_bindings/webidls/ShadowRoot.webidl
+++ b/components/script_bindings/webidls/ShadowRoot.webidl
@@ -25,7 +25,7 @@ ShadowRoot includes DocumentOrShadowRoot;
// https://html.spec.whatwg.org/multipage/#dom-parsing-and-serialization
partial interface ShadowRoot {
- // [CEReactions] undefined setHTMLUnsafe((TrustedHTML or DOMString) html);
+ [CEReactions] undefined setHTMLUnsafe(DOMString html);
DOMString getHTML(optional GetHTMLOptions options = {});
// [CEReactions] attribute (TrustedHTML or [LegacyNullToEmptyString] DOMString) innerHTML;
diff --git a/components/servo/lib.rs b/components/servo/lib.rs
index 6f39e773e4e..366685e1123 100644
--- a/components/servo/lib.rs
+++ b/components/servo/lib.rs
@@ -120,6 +120,7 @@ pub use {bluetooth, bluetooth_traits};
use crate::proxies::ConstellationProxy;
use crate::responders::ServoErrorChannel;
pub use crate::servo_delegate::{ServoDelegate, ServoError};
+use crate::webrender_api::FrameReadyParams;
pub use crate::webview::{WebView, WebViewBuilder};
pub use crate::webview_delegate::{
AllowOrDenyRequest, AuthenticationRequest, FormControl, NavigationRequest, PermissionRequest,
@@ -233,14 +234,13 @@ impl webrender_api::RenderNotifier for RenderNotifier {
fn new_frame_ready(
&self,
document_id: DocumentId,
- _scrolled: bool,
- composite_needed: bool,
- _frame_publish_id: FramePublishId,
+ _: FramePublishId,
+ frame_ready_params: &FrameReadyParams,
) {
self.compositor_proxy
.send(CompositorMsg::NewWebRenderFrameReady(
document_id,
- composite_needed,
+ frame_ready_params.render,
));
}
}
diff --git a/components/shared/devtools/lib.rs b/components/shared/devtools/lib.rs
index 0cf99d22658..c07f4529073 100644
--- a/components/shared/devtools/lib.rs
+++ b/components/shared/devtools/lib.rs
@@ -144,6 +144,15 @@ pub struct NodeInfo {
pub shadow_root_mode: Option<ShadowRootMode>,
pub is_shadow_host: bool,
pub display: Option<String>,
+
+ /// The `DOCTYPE` name if this is a `DocumentType` node, `None` otherwise
+ pub doctype_name: Option<String>,
+
+ /// The `DOCTYPE` public identifier if this is a `DocumentType` node , `None` otherwise
+ pub doctype_public_identifier: Option<String>,
+
+ /// The `DOCTYPE` system identifier if this is a `DocumentType` node, `None` otherwise
+ pub doctype_system_identifier: Option<String>,
}
pub struct StartedTimelineMarker {
diff --git a/components/shared/script_layout/lib.rs b/components/shared/script_layout/lib.rs
index a40b8c403c1..66baccd5147 100644
--- a/components/shared/script_layout/lib.rs
+++ b/components/shared/script_layout/lib.rs
@@ -117,16 +117,8 @@ pub enum LayoutElementType {
SVGSVGElement,
}
-pub enum HTMLCanvasDataSource {
- WebGL(ImageKey),
- Image(ImageKey),
- WebGPU(ImageKey),
- /// transparent black
- Empty,
-}
-
pub struct HTMLCanvasData {
- pub source: HTMLCanvasDataSource,
+ pub source: Option<ImageKey>,
pub width: u32,
pub height: u32,
}
diff --git a/components/webdriver_server/actions.rs b/components/webdriver_server/actions.rs
index f69a09a2577..fbede5b5887 100644
--- a/components/webdriver_server/actions.rs
+++ b/components/webdriver_server/actions.rs
@@ -76,7 +76,7 @@ fn compute_tick_duration(tick_actions: &ActionSequence) -> u64 {
}
},
ActionsType::Key { actions: _ } => (),
- ActionsType::Wheel { .. } => todo!("Not implemented."),
+ ActionsType::Wheel { .. } => log::error!("not implemented"),
}
duration
}
@@ -176,7 +176,10 @@ impl Handler {
}
}
},
- ActionsType::Wheel { .. } => todo!("Not implemented."),
+ ActionsType::Wheel { .. } => {
+ log::error!("not yet implemented");
+ return Err(ErrorStatus::UnsupportedOperation);
+ },
}
Ok(())
diff --git a/components/webdriver_server/capabilities.rs b/components/webdriver_server/capabilities.rs
index 477a3bfd34c..32596f5275a 100644
--- a/components/webdriver_server/capabilities.rs
+++ b/components/webdriver_server/capabilities.rs
@@ -4,7 +4,7 @@
use serde_json::{Map, Value};
use webdriver::capabilities::{BrowserCapabilities, Capabilities};
-use webdriver::error::{WebDriverError, WebDriverResult};
+use webdriver::error::{ErrorStatus, WebDriverError, WebDriverResult};
pub struct ServoCapabilities {
pub browser_name: String,
@@ -79,42 +79,42 @@ impl BrowserCapabilities for ServoCapabilities {
&mut self,
_: &serde_json::Map<std::string::String, Value>,
) -> Result<bool, WebDriverError> {
- todo!()
+ Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, ""))
}
fn webauthn_virtual_authenticators(
&mut self,
_: &serde_json::Map<std::string::String, Value>,
) -> Result<bool, WebDriverError> {
- todo!()
+ Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, ""))
}
fn webauthn_extension_uvm(
&mut self,
_: &serde_json::Map<std::string::String, Value>,
) -> Result<bool, WebDriverError> {
- todo!()
+ Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, ""))
}
fn webauthn_extension_prf(
&mut self,
_: &serde_json::Map<std::string::String, Value>,
) -> Result<bool, WebDriverError> {
- todo!()
+ Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, ""))
}
fn webauthn_extension_large_blob(
&mut self,
_: &serde_json::Map<std::string::String, Value>,
) -> Result<bool, WebDriverError> {
- todo!()
+ Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, ""))
}
fn webauthn_extension_cred_blob(
&mut self,
_: &serde_json::Map<std::string::String, Value>,
) -> Result<bool, WebDriverError> {
- todo!()
+ Err(WebDriverError::new(ErrorStatus::UnsupportedOperation, ""))
}
}
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index ce83a8f3cc1..d003ebf8adb 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -29,7 +29,7 @@ use embedder_traits::{
use euclid::{Rect, Size2D};
use http::method::Method;
use image::{DynamicImage, ImageFormat, RgbaImage};
-use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use keyboard_types::webdriver::send_keys;
use log::{debug, info};
@@ -678,7 +678,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
self.top_level_script_command(WebDriverScriptCommand::GetUrl(sender))?;
- let url = receiver.recv().unwrap();
+ let url = wait_for_script_response(receiver)?;
Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(url.as_str())?,
@@ -694,7 +694,7 @@ impl Handler {
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
- let window_size = receiver.recv().unwrap();
+ let window_size = wait_for_script_response(receiver)?;
let window_size_response = WindowRectResponse {
x: 0,
y: 0,
@@ -738,7 +738,7 @@ impl Handler {
.unwrap();
});
- let window_size = receiver.recv().unwrap();
+ let window_size = wait_for_script_response(receiver)?;
let window_size_response = WindowRectResponse {
x: 0,
y: 0,
@@ -756,7 +756,7 @@ impl Handler {
sender,
))?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(is_enabled) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(is_enabled)?,
))),
@@ -772,7 +772,7 @@ impl Handler {
sender,
))?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(is_selected) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(is_selected)?,
))),
@@ -812,7 +812,7 @@ impl Handler {
self.top_level_script_command(WebDriverScriptCommand::GetTitle(sender))?;
- let value = receiver.recv().unwrap();
+ let value = wait_for_script_response(receiver)?;
Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
)))
@@ -874,7 +874,7 @@ impl Handler {
},
}
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => {
let value_resp = serde_json::to_value(
value.map(|x| serde_json::to_value(WebElement(x)).unwrap()),
@@ -1005,7 +1005,7 @@ impl Handler {
let cmd = WebDriverScriptCommand::GetBrowsingContextId(frame_id, sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(browsing_context_id) => {
self.session_mut()?.browsing_context_id = browsing_context_id;
Ok(WebDriverResponse::Void)
@@ -1047,7 +1047,7 @@ impl Handler {
},
}
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => {
let resp_value: Vec<Value> = value
.into_iter()
@@ -1103,7 +1103,7 @@ impl Handler {
},
}
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => {
let value_resp = serde_json::to_value(
value.map(|x| serde_json::to_value(WebElement(x)).unwrap()),
@@ -1156,7 +1156,7 @@ impl Handler {
},
}
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => {
let resp_value: Vec<Value> = value
.into_iter()
@@ -1175,7 +1175,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementRect(element.to_string(), sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(rect) => {
let response = ElementRectResponse {
x: rect.origin.x,
@@ -1193,7 +1193,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementText(element.to_string(), sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
))),
@@ -1205,9 +1205,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetActiveElement(sender);
self.browsing_context_script_command(cmd)?;
- let value = receiver
- .recv()
- .unwrap()
+ let value = wait_for_script_response(receiver)?
.map(|x| serde_json::to_value(WebElement(x)).unwrap());
Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
@@ -1218,7 +1216,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetComputedRole(element.to_string(), sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
))),
@@ -1230,7 +1228,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetElementTagName(element.to_string(), sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
))),
@@ -1250,7 +1248,7 @@ impl Handler {
sender,
);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
))),
@@ -1272,7 +1270,7 @@ impl Handler {
);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(SendableWebDriverJSValue(value))?,
))),
@@ -1289,7 +1287,7 @@ impl Handler {
let cmd =
WebDriverScriptCommand::GetElementCSS(element.to_string(), name.to_owned(), sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(value) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(value)?,
))),
@@ -1301,7 +1299,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetCookies(sender);
self.browsing_context_script_command(cmd)?;
- let cookies = receiver.recv().unwrap();
+ let cookies = wait_for_script_response(receiver)?;
let response = cookies
.into_iter()
.map(|cookie| cookie_msg_to_cookie(cookie.into_inner()))
@@ -1313,12 +1311,14 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetCookie(name, sender);
self.browsing_context_script_command(cmd)?;
- let cookies = receiver.recv().unwrap();
- let response = cookies
+ let cookies = wait_for_script_response(receiver)?;
+ let Some(response) = cookies
.into_iter()
.map(|cookie| cookie_msg_to_cookie(cookie.into_inner()))
.next()
- .unwrap();
+ else {
+ return Err(WebDriverError::new(ErrorStatus::NoSuchCookie, ""));
+ };
Ok(WebDriverResponse::Cookie(CookieResponse(response)))
}
@@ -1342,7 +1342,7 @@ impl Handler {
let cmd = WebDriverScriptCommand::AddCookie(cookie_builder.build(), sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(_) => Ok(WebDriverResponse::Void),
Err(response) => match response {
WebDriverCookieError::InvalidDomain => Err(WebDriverError::new(
@@ -1361,7 +1361,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::DeleteCookie(name, sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(_) => Ok(WebDriverResponse::Void),
Err(error) => Err(WebDriverError::new(error, "")),
}
@@ -1371,7 +1371,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::DeleteCookies(sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(_) => Ok(WebDriverResponse::Void),
Err(error) => Err(WebDriverError::new(error, "")),
}
@@ -1426,7 +1426,7 @@ impl Handler {
let cmd = WebDriverScriptCommand::GetPageSource(sender);
self.browsing_context_script_command(cmd)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(source) => Ok(WebDriverResponse::Generic(ValueResponse(
serde_json::to_value(source)?,
))),
@@ -1487,9 +1487,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let command = WebDriverScriptCommand::ExecuteScript(script, sender);
self.browsing_context_script_command(command)?;
- let result = receiver
- .recv()
- .unwrap_or(Err(WebDriverJSError::BrowsingContextNotFound));
+ let result = wait_for_script_response(receiver)?;
self.postprocess_js_result(result)
}
@@ -1533,9 +1531,7 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let command = WebDriverScriptCommand::ExecuteAsyncScript(script, sender);
self.browsing_context_script_command(command)?;
- let result = receiver
- .recv()
- .unwrap_or(Err(WebDriverJSError::BrowsingContextNotFound));
+ let result = wait_for_script_response(receiver)?;
self.postprocess_js_result(result)
}
@@ -1589,10 +1585,7 @@ impl Handler {
.unwrap();
// TODO: distinguish the not found and not focusable cases
- receiver
- .recv()
- .unwrap()
- .map_err(|error| WebDriverError::new(error, ""))?;
+ wait_for_script_response(receiver)?.map_err(|error| WebDriverError::new(error, ""))?;
let input_events = send_keys(&keys.text);
@@ -1615,7 +1608,7 @@ impl Handler {
let command = WebDriverScriptCommand::ElementClick(element.to_string(), sender);
self.browsing_context_script_command(command)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(element_id) => match element_id {
Some(element_id) => {
let id = Uuid::new_v4().to_string();
@@ -1688,7 +1681,7 @@ impl Handler {
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
- if let Some(x) = receiver.recv().unwrap() {
+ if let Some(x) = wait_for_script_response(receiver)? {
img = Some(x);
break;
};
@@ -1739,7 +1732,7 @@ impl Handler {
let command = WebDriverScriptCommand::GetBoundingClientRect(element.to_string(), sender);
self.browsing_context_script_command(command)?;
- match receiver.recv().unwrap() {
+ match wait_for_script_response(receiver)? {
Ok(rect) => {
let encoded = self.take_screenshot(Some(Rect::from_untyped(&rect)))?;
@@ -1944,3 +1937,12 @@ fn webdriver_value_to_js_argument(v: &Value) -> String {
},
}
}
+
+fn wait_for_script_response<T>(receiver: IpcReceiver<T>) -> Result<T, WebDriverError>
+where
+ T: for<'de> Deserialize<'de> + Serialize,
+{
+ receiver
+ .recv()
+ .map_err(|_| WebDriverError::new(ErrorStatus::NoSuchWindow, ""))
+}