aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/constellation/constellation.rs31
-rw-r--r--components/net/tests/fetch.rs2
-rw-r--r--components/net/tests/test.css3
-rw-r--r--components/script/canvas_state.rs65
-rw-r--r--components/script/dom/element.rs47
-rw-r--r--components/script/dom/globalscope.rs196
-rw-r--r--components/script/dom/htmlelement.rs2
-rw-r--r--components/script/dom/htmlmediaelement.rs4
-rw-r--r--components/script/dom/htmlvideoelement.rs6
-rw-r--r--components/script/dom/imagebitmap.rs6
-rw-r--r--components/script/dom/imagedata.rs5
-rw-r--r--components/script/dom/node.rs9
-rw-r--r--components/script/dom/offscreencanvas.rs4
-rw-r--r--components/script/dom/raredata.rs7
-rw-r--r--components/script/dom/webglrenderingcontext.rs17
-rw-r--r--components/script/dom/window.rs27
-rw-r--r--components/script/dom/windowproxy.rs37
-rw-r--r--components/script/dom/workerglobalscope.rs27
-rw-r--r--components/script/layout_dom/element.rs30
-rw-r--r--components/script/layout_dom/node.rs8
-rw-r--r--components/script/webdriver_handlers.rs30
-rw-r--r--components/script_bindings/codegen/Bindings.conf4
-rw-r--r--components/script_bindings/webidls/CanvasRenderingContext2D.webidl2
-rw-r--r--components/script_bindings/webidls/Element.webidl5
-rw-r--r--components/script_bindings/webidls/WebGLRenderingContext.webidl3
-rw-r--r--components/script_bindings/webidls/WindowOrWorkerGlobalScope.webidl5
-rw-r--r--components/shared/embedder/webdriver.rs15
-rw-r--r--components/webdriver_server/lib.rs35
28 files changed, 508 insertions, 124 deletions
diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs
index 5b4d244e746..82f55589686 100644
--- a/components/constellation/constellation.rs
+++ b/components/constellation/constellation.rs
@@ -4702,25 +4702,38 @@ where
WebDriverCommandMsg::CloseWebView(webview_id) => {
self.handle_close_top_level_browsing_context(webview_id);
},
- WebDriverCommandMsg::NewWebView(webview_id, sender, load_sender) => {
- let (chan, port) = match ipc::channel() {
+ WebDriverCommandMsg::NewWebView(
+ originating_webview_id,
+ response_sender,
+ load_status_sender,
+ ) => {
+ let (embedder_sender, receiver) = match ipc::channel() {
Ok(result) => result,
Err(error) => return warn!("Failed to create channel: {error:?}"),
};
- self.embedder_proxy
- .send(EmbedderMsg::AllowOpeningWebView(webview_id, chan));
- let (webview_id, viewport_details) = match port.recv() {
- Ok(Some((webview_id, viewport_details))) => (webview_id, viewport_details),
+ self.embedder_proxy.send(EmbedderMsg::AllowOpeningWebView(
+ originating_webview_id,
+ embedder_sender,
+ ));
+ let (new_webview_id, viewport_details) = match receiver.recv() {
+ Ok(Some((new_webview_id, viewport_details))) => {
+ (new_webview_id, viewport_details)
+ },
Ok(None) => return warn!("Embedder refused to allow opening webview"),
Err(error) => return warn!("Failed to receive webview id: {error:?}"),
};
self.handle_new_top_level_browsing_context(
ServoUrl::parse_with_base(None, "about:blank").expect("Infallible parse"),
- webview_id,
+ new_webview_id,
viewport_details,
- Some(load_sender),
+ Some(load_status_sender),
);
- let _ = sender.send(webview_id);
+ if let Err(error) = response_sender.send(new_webview_id) {
+ error!(
+ "WebDriverCommandMsg::NewWebView: IPC error when sending new_webview_id \
+ to webdriver server: {error}"
+ );
+ }
},
WebDriverCommandMsg::FocusWebView(webview_id) => {
self.handle_focus_web_view(webview_id);
diff --git a/components/net/tests/fetch.rs b/components/net/tests/fetch.rs
index e8c5077f12a..0deceab3055 100644
--- a/components/net/tests/fetch.rs
+++ b/components/net/tests/fetch.rs
@@ -225,7 +225,7 @@ fn test_fetch_blob() {
#[test]
fn test_file() {
- let path = Path::new("../../resources/ahem.css")
+ let path = Path::new("../../components/net/tests/test.css")
.canonicalize()
.unwrap();
let url = ServoUrl::from_file_path(path.clone()).unwrap();
diff --git a/components/net/tests/test.css b/components/net/tests/test.css
new file mode 100644
index 00000000000..f7fa63bbaa7
--- /dev/null
+++ b/components/net/tests/test.css
@@ -0,0 +1,3 @@
+html {
+ color: red;
+}
diff --git a/components/script/canvas_state.rs b/components/script/canvas_state.rs
index 139579d2045..7f77daf513b 100644
--- a/components/script/canvas_state.rs
+++ b/components/script/canvas_state.rs
@@ -55,6 +55,7 @@ use crate::dom::element::{Element, cors_setting_for_element};
use crate::dom::globalscope::GlobalScope;
use crate::dom::htmlcanvaselement::HTMLCanvasElement;
use crate::dom::htmlvideoelement::HTMLVideoElement;
+use crate::dom::imagebitmap::ImageBitmap;
use crate::dom::imagedata::ImageData;
use crate::dom::node::{Node, NodeTraits};
use crate::dom::offscreencanvas::OffscreenCanvas;
@@ -319,6 +320,7 @@ impl CanvasState {
},
CanvasImageSource::HTMLVideoElement(video) => video.origin_is_clean(),
CanvasImageSource::HTMLCanvasElement(canvas) => canvas.origin_is_clean(),
+ CanvasImageSource::ImageBitmap(bitmap) => bitmap.origin_is_clean(),
CanvasImageSource::OffscreenCanvas(canvas) => canvas.origin_is_clean(),
CanvasImageSource::CSSStyleValue(_) => true,
}
@@ -459,6 +461,15 @@ impl CanvasState {
self.draw_html_canvas_element(canvas, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh)
},
+ CanvasImageSource::ImageBitmap(ref bitmap) => {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if bitmap.is_detached() {
+ return Err(Error::InvalidState);
+ }
+
+ self.draw_image_bitmap(bitmap, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh);
+ Ok(())
+ },
CanvasImageSource::OffscreenCanvas(ref canvas) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
if canvas.get_size().is_empty() {
@@ -728,6 +739,52 @@ impl CanvasState {
Ok(())
}
+ /// <https://html.spec.whatwg.org/multipage/#dom-context-2d-drawimage>
+ #[allow(clippy::too_many_arguments)]
+ fn draw_image_bitmap(
+ &self,
+ bitmap: &ImageBitmap,
+ canvas: Option<&HTMLCanvasElement>,
+ sx: f64,
+ sy: f64,
+ sw: Option<f64>,
+ sh: Option<f64>,
+ dx: f64,
+ dy: f64,
+ dw: Option<f64>,
+ dh: Option<f64>,
+ ) {
+ let Some(snapshot) = bitmap.bitmap_data().clone() else {
+ return;
+ };
+
+ // Step 4. Establish the source and destination rectangles.
+ let bitmap_size = snapshot.size();
+ let dw = dw.unwrap_or(bitmap_size.width as f64);
+ let dh = dh.unwrap_or(bitmap_size.height as f64);
+ let sw = sw.unwrap_or(bitmap_size.width as f64);
+ let sh = sh.unwrap_or(bitmap_size.height as f64);
+
+ let (source_rect, dest_rect) =
+ self.adjust_source_dest_rects(bitmap_size, sx, sy, sw, sh, dx, dy, dw, dh);
+
+ // Step 5. If one of the sw or sh arguments is zero, then return. Nothing is painted.
+ if !is_rect_valid(source_rect) || !is_rect_valid(dest_rect) {
+ return;
+ }
+
+ let smoothing_enabled = self.state.borrow().image_smoothing_enabled;
+
+ self.send_canvas_2d_msg(Canvas2dMsg::DrawImage(
+ snapshot.as_ipc(),
+ dest_rect,
+ source_rect,
+ smoothing_enabled,
+ ));
+
+ self.mark_as_dirty(canvas);
+ }
+
pub(crate) fn mark_as_dirty(&self, canvas: Option<&HTMLCanvasElement>) {
if let Some(canvas) = canvas {
canvas.mark_as_dirty();
@@ -1063,6 +1120,14 @@ impl CanvasState {
canvas.get_image_data().ok_or(Error::InvalidState)?
},
+ CanvasImageSource::ImageBitmap(ref bitmap) => {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if bitmap.is_detached() {
+ return Err(Error::InvalidState);
+ }
+
+ bitmap.bitmap_data().clone().ok_or(Error::InvalidState)?
+ },
CanvasImageSource::OffscreenCanvas(ref canvas) => {
// <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
if canvas.get_size().is_empty() {
diff --git a/components/script/dom/element.rs b/components/script/dom/element.rs
index 961fb92121d..1fe51407638 100644
--- a/components/script/dom/element.rs
+++ b/components/script/dom/element.rs
@@ -861,8 +861,14 @@ pub(crate) fn get_attr_for_layout<'dom>(
pub(crate) trait LayoutElementHelpers<'dom> {
fn attrs(self) -> &'dom [LayoutDom<'dom, Attr>];
- fn has_class_for_layout(self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool;
+ fn has_class_or_part_for_layout(
+ self,
+ name: &AtomIdent,
+ attr_name: &LocalName,
+ case_sensitivity: CaseSensitivity,
+ ) -> bool;
fn get_classes_for_layout(self) -> Option<&'dom [Atom]>;
+ fn get_parts_for_layout(self) -> Option<&'dom [Atom]>;
fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
where
@@ -905,8 +911,13 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
}
#[inline]
- fn has_class_for_layout(self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
- get_attr_for_layout(self, &ns!(), &local_name!("class")).is_some_and(|attr| {
+ fn has_class_or_part_for_layout(
+ self,
+ name: &AtomIdent,
+ attr_name: &LocalName,
+ case_sensitivity: CaseSensitivity,
+ ) -> bool {
+ get_attr_for_layout(self, &ns!(), attr_name).is_some_and(|attr| {
attr.to_tokens()
.unwrap()
.iter()
@@ -920,6 +931,11 @@ impl<'dom> LayoutElementHelpers<'dom> for LayoutDom<'dom, Element> {
.map(|attr| attr.to_tokens().unwrap())
}
+ fn get_parts_for_layout(self) -> Option<&'dom [Atom]> {
+ get_attr_for_layout(self, &ns!(), &local_name!("part"))
+ .map(|attr| attr.to_tokens().unwrap())
+ }
+
fn synthesize_presentational_hints_for_legacy_attributes<V>(self, hints: &mut V)
where
V: Push<ApplicableDeclarationBlock>,
@@ -1995,6 +2011,16 @@ impl Element {
})
}
+ pub(crate) fn is_part(&self, name: &Atom, case_sensitivity: CaseSensitivity) -> bool {
+ self.get_attribute(&ns!(), &LocalName::from("part"))
+ .is_some_and(|attr| {
+ attr.value()
+ .as_tokens()
+ .iter()
+ .any(|atom| case_sensitivity.eq_atom(name, atom))
+ })
+ }
+
pub(crate) fn set_atomic_attribute(
&self,
local_name: &LocalName,
@@ -4051,6 +4077,13 @@ impl ElementMethods<crate::DomTypeHolder> for Element {
rooted!(in(*cx) let slottable = Slottable(Dom::from_ref(self.upcast::<Node>())));
slottable.find_a_slot(true)
}
+
+ /// <https://drafts.csswg.org/css-shadow-parts/#dom-element-part>
+ fn Part(&self) -> DomRoot<DOMTokenList> {
+ self.ensure_rare_data()
+ .part
+ .or_init(|| DOMTokenList::new(self, &local_name!("part"), None, CanGc::note()))
+ }
}
impl VirtualMethods for Element {
@@ -4190,7 +4223,9 @@ impl VirtualMethods for Element {
match *name {
local_name!("id") => AttrValue::from_atomic(value.into()),
local_name!("name") => AttrValue::from_atomic(value.into()),
- local_name!("class") => AttrValue::from_serialized_tokenlist(value.into()),
+ local_name!("class") | local_name!("part") => {
+ AttrValue::from_serialized_tokenlist(value.into())
+ },
_ => self
.super_type()
.unwrap()
@@ -4564,8 +4599,8 @@ impl SelectorsElement for SelectorWrapper<'_> {
.is_some_and(|atom| case_sensitivity.eq_atom(id, atom))
}
- fn is_part(&self, _name: &AtomIdent) -> bool {
- false
+ fn is_part(&self, name: &AtomIdent) -> bool {
+ Element::is_part(self, name, CaseSensitivity::CaseSensitive)
}
fn imported_part(&self, _: &AtomIdent) -> Option<AtomIdent> {
diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs
index 9bec85afe5b..ade7b86caa8 100644
--- a/components/script/dom/globalscope.rs
+++ b/components/script/dom/globalscope.rs
@@ -29,9 +29,10 @@ use crossbeam_channel::Sender;
use devtools_traits::{PageError, ScriptToDevtoolsControlMsg};
use dom_struct::dom_struct;
use embedder_traits::EmbedderMsg;
+use euclid::default::Size2D;
use http::HeaderMap;
use hyper_serde::Serde;
-use ipc_channel::ipc::{self, IpcSender};
+use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
use ipc_channel::router::ROUTER;
use js::glue::{IsWrapper, UnwrapObjectDynamic};
use js::jsapi::{
@@ -59,9 +60,11 @@ use net_traits::{
CoreResourceMsg, CoreResourceThread, FetchResponseListener, IpcSend, ReferrerPolicy,
ResourceThreads, fetch_async,
};
+use pixels::PixelFormat;
use profile_traits::{ipc as profile_ipc, mem as profile_mem, time as profile_time};
use script_bindings::interfaces::GlobalScopeHelpers;
use servo_url::{ImmutableOrigin, MutableOrigin, ServoUrl};
+use snapshot::Snapshot;
use timers::{TimerEventId, TimerEventRequest, TimerSource};
use url::Origin;
use uuid::Uuid;
@@ -2956,64 +2959,209 @@ impl GlobalScope {
result == CheckResult::Blocked
}
+ /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
+ #[allow(clippy::too_many_arguments)]
pub(crate) fn create_image_bitmap(
&self,
image: ImageBitmapSource,
+ _sx: i32,
+ _sy: i32,
+ sw: Option<i32>,
+ sh: Option<i32>,
options: &ImageBitmapOptions,
can_gc: CanGc,
) -> Rc<Promise> {
let in_realm_proof = AlreadyInRealm::assert::<crate::DomTypeHolder>();
let p = Promise::new_in_current_realm(InRealm::Already(&in_realm_proof), can_gc);
+
+ // Step 1. If either sw or sh is given and is 0, then return a promise rejected with a RangeError.
+ if sw.is_some_and(|w| w == 0) {
+ p.reject_error(
+ Error::Range("'sw' must be a non-zero value".to_owned()),
+ can_gc,
+ );
+ return p;
+ }
+
+ if sh.is_some_and(|h| h == 0) {
+ p.reject_error(
+ Error::Range("'sh' must be a non-zero value".to_owned()),
+ can_gc,
+ );
+ return p;
+ }
+
+ // Step 2. If either options's resizeWidth or options's resizeHeight is present and is 0,
+ // then return a promise rejected with an "InvalidStateError" DOMException.
if options.resizeWidth.is_some_and(|w| w == 0) {
p.reject_error(Error::InvalidState, can_gc);
return p;
}
- if options.resizeHeight.is_some_and(|w| w == 0) {
+ if options.resizeHeight.is_some_and(|h| h == 0) {
p.reject_error(Error::InvalidState, can_gc);
return p;
}
+ // Step 3. Check the usability of the image argument. If this throws an exception or returns bad,
+ // then return a promise rejected with an "InvalidStateError" DOMException.
+ // Step 6. Switch on image:
match image {
- ImageBitmapSource::HTMLCanvasElement(ref canvas) => {
- // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
- if !canvas.is_valid() {
+ ImageBitmapSource::HTMLImageElement(ref image) => {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if !image.is_usable().is_ok_and(|u| u) {
p.reject_error(Error::InvalidState, can_gc);
return p;
}
- match canvas.get_image_data() {
- Some(snapshot) => {
- let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
- image_bitmap.set_origin_clean(canvas.origin_is_clean());
- p.resolve_native(&(image_bitmap), can_gc);
+ // If no ImageBitmap object can be constructed, then the promise is rejected instead.
+ let Some(img) = image.image_data() else {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ };
+
+ let Some(img) = img.as_raster_image() else {
+ // Vector HTMLImageElement are not yet supported.
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ };
+
+ let size = Size2D::new(img.metadata.width, img.metadata.height);
+ let format = match img.format {
+ PixelFormat::BGRA8 => snapshot::PixelFormat::BGRA,
+ PixelFormat::RGBA8 => snapshot::PixelFormat::RGBA,
+ pixel_format => {
+ unimplemented!("unsupported pixel format ({:?})", pixel_format)
},
- None => p.reject_error(Error::InvalidState, can_gc),
+ };
+ let alpha_mode = snapshot::AlphaMode::Transparent {
+ premultiplied: false,
+ };
+
+ let snapshot = Snapshot::from_shared_memory(
+ size.cast(),
+ format,
+ alpha_mode,
+ IpcSharedMemory::from_bytes(img.first_frame().bytes),
+ );
+
+ let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
+ image_bitmap.set_origin_clean(image.same_origin(GlobalScope::entry().origin()));
+
+ p.resolve_native(&image_bitmap, can_gc);
+ },
+ ImageBitmapSource::HTMLVideoElement(ref video) => {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if !video.is_usable() {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ }
+
+ if video.is_network_state_empty() {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ }
+
+ // If no ImageBitmap object can be constructed, then the promise is rejected instead.
+ let Some(snapshot) = video.get_current_frame_data() else {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ };
+
+ let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
+ image_bitmap.set_origin_clean(video.origin_is_clean());
+
+ p.resolve_native(&image_bitmap, can_gc);
+ },
+ ImageBitmapSource::HTMLCanvasElement(ref canvas) => {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if canvas.get_size().is_empty() {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
}
- p
+
+ // If no ImageBitmap object can be constructed, then the promise is rejected instead.
+ let Some(snapshot) = canvas.get_image_data() else {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ };
+
+ let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
+ image_bitmap.set_origin_clean(canvas.origin_is_clean());
+
+ p.resolve_native(&image_bitmap, can_gc);
+ },
+ ImageBitmapSource::ImageBitmap(ref bitmap) => {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if bitmap.is_detached() {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ }
+
+ // If no ImageBitmap object can be constructed, then the promise is rejected instead.
+ let Some(snapshot) = bitmap.bitmap_data().clone() else {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ };
+
+ let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
+ image_bitmap.set_origin_clean(bitmap.origin_is_clean());
+
+ p.resolve_native(&image_bitmap, can_gc);
},
ImageBitmapSource::OffscreenCanvas(ref canvas) => {
- // https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
- if !canvas.is_valid() {
+ // <https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument>
+ if canvas.get_size().is_empty() {
p.reject_error(Error::InvalidState, can_gc);
return p;
}
- match canvas.get_image_data() {
- Some(snapshot) => {
- let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
- image_bitmap.set_origin_clean(canvas.origin_is_clean());
- p.resolve_native(&(image_bitmap), can_gc);
- },
- None => p.reject_error(Error::InvalidState, can_gc),
+ // If no ImageBitmap object can be constructed, then the promise is rejected instead.
+ let Some(snapshot) = canvas.get_image_data() else {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
+ };
+
+ let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
+ image_bitmap.set_origin_clean(canvas.origin_is_clean());
+
+ p.resolve_native(&image_bitmap, can_gc);
+ },
+ ImageBitmapSource::Blob(_) => {
+ // TODO: implement support of Blob object as ImageBitmapSource
+ p.reject_error(Error::InvalidState, can_gc);
+ },
+ ImageBitmapSource::ImageData(ref image_data) => {
+ // <https://html.spec.whatwg.org/multipage/#the-imagebitmap-interface:imagedata-4>
+ if image_data.is_detached() {
+ p.reject_error(Error::InvalidState, can_gc);
+ return p;
}
- p
+
+ let alpha_mode = snapshot::AlphaMode::Transparent {
+ premultiplied: false,
+ };
+
+ let snapshot = Snapshot::from_shared_memory(
+ image_data.get_size().cast(),
+ snapshot::PixelFormat::RGBA,
+ alpha_mode,
+ image_data.to_shared_memory(),
+ );
+
+ let image_bitmap = ImageBitmap::new(self, snapshot, can_gc);
+
+ p.resolve_native(&image_bitmap, can_gc);
},
- _ => {
+ ImageBitmapSource::CSSStyleValue(_) => {
+ // TODO: CSSStyleValue is not part of ImageBitmapSource
+ // <https://html.spec.whatwg.org/multipage/#imagebitmapsource>
p.reject_error(Error::NotSupported, can_gc);
- p
},
}
+
+ // Step 7. Return promise.
+ p
}
pub(crate) fn fire_timer(&self, handle: TimerEventId, can_gc: CanGc) {
diff --git a/components/script/dom/htmlelement.rs b/components/script/dom/htmlelement.rs
index f41370386e9..f47a40d3cdb 100644
--- a/components/script/dom/htmlelement.rs
+++ b/components/script/dom/htmlelement.rs
@@ -437,7 +437,7 @@ impl HTMLElementMethods<crate::DomTypeHolder> for HTMLElement {
document.request_focus(None, FocusInitiator::Local, can_gc);
}
- // https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent
+ /// <https://drafts.csswg.org/cssom-view/#dom-htmlelement-offsetparent>
fn GetOffsetParent(&self, can_gc: CanGc) -> Option<DomRoot<Element>> {
if self.is::<HTMLBodyElement>() || self.is::<HTMLHtmlElement>() {
return None;
diff --git a/components/script/dom/htmlmediaelement.rs b/components/script/dom/htmlmediaelement.rs
index 0d54d188e59..e483504cceb 100644
--- a/components/script/dom/htmlmediaelement.rs
+++ b/components/script/dom/htmlmediaelement.rs
@@ -520,6 +520,10 @@ impl HTMLMediaElement {
}
}
+ pub(crate) fn network_state(&self) -> NetworkState {
+ self.network_state.get()
+ }
+
pub(crate) fn get_ready_state(&self) -> ReadyState {
self.ready_state.get()
}
diff --git a/components/script/dom/htmlvideoelement.rs b/components/script/dom/htmlvideoelement.rs
index c5699014ee2..622e5079ee9 100644
--- a/components/script/dom/htmlvideoelement.rs
+++ b/components/script/dom/htmlvideoelement.rs
@@ -37,7 +37,7 @@ use crate::dom::bindings::str::DOMString;
use crate::dom::document::Document;
use crate::dom::element::{AttributeMutation, Element, LayoutElementHelpers};
use crate::dom::globalscope::GlobalScope;
-use crate::dom::htmlmediaelement::{HTMLMediaElement, ReadyState};
+use crate::dom::htmlmediaelement::{HTMLMediaElement, NetworkState, ReadyState};
use crate::dom::node::{Node, NodeTraits};
use crate::dom::performanceresourcetiming::InitiatorType;
use crate::dom::virtualmethods::VirtualMethods;
@@ -294,6 +294,10 @@ impl HTMLVideoElement {
pub(crate) fn origin_is_clean(&self) -> bool {
self.htmlmediaelement.origin_is_clean()
}
+
+ pub(crate) fn is_network_state_empty(&self) -> bool {
+ self.htmlmediaelement.network_state() == NetworkState::Empty
+ }
}
impl HTMLVideoElementMethods<crate::DomTypeHolder> for HTMLVideoElement {
diff --git a/components/script/dom/imagebitmap.rs b/components/script/dom/imagebitmap.rs
index cddd8cf1188..0a43bf4f176 100644
--- a/components/script/dom/imagebitmap.rs
+++ b/components/script/dom/imagebitmap.rs
@@ -68,7 +68,7 @@ impl ImageBitmap {
/// Return the value of the [`[[Detached]]`](https://html.spec.whatwg.org/multipage/#detached)
/// internal slot
- fn is_detached(&self) -> bool {
+ pub(crate) fn is_detached(&self) -> bool {
self.bitmap_data.borrow().is_none()
}
}
@@ -109,9 +109,9 @@ impl Serializable for ImageBitmap {
}
fn serialized_storage<'a>(
- reader: StructuredData<'a, '_>,
+ data: StructuredData<'a, '_>,
) -> &'a mut Option<HashMap<ImageBitmapId, Self::Data>> {
- match reader {
+ match data {
StructuredData::Reader(r) => &mut r.image_bitmaps,
StructuredData::Writer(w) => &mut w.image_bitmaps,
}
diff --git a/components/script/dom/imagedata.rs b/components/script/dom/imagedata.rs
index a834abdae78..907561cdda4 100644
--- a/components/script/dom/imagedata.rs
+++ b/components/script/dom/imagedata.rs
@@ -148,6 +148,11 @@ impl ImageData {
imagedata, global, proto, can_gc,
))
}
+
+ pub(crate) fn is_detached(&self) -> bool {
+ self.data.is_detached_buffer(GlobalScope::get_cx())
+ }
+
#[allow(unsafe_code)]
pub(crate) fn to_shared_memory(&self) -> IpcSharedMemory {
IpcSharedMemory::from_bytes(unsafe { self.as_slice() })
diff --git a/components/script/dom/node.rs b/components/script/dom/node.rs
index bf36242572f..6d4a0d2529e 100644
--- a/components/script/dom/node.rs
+++ b/components/script/dom/node.rs
@@ -1583,6 +1583,7 @@ pub(crate) unsafe fn from_untrusted_node_address(candidate: UntrustedNodeAddress
pub(crate) trait LayoutNodeHelpers<'dom> {
fn type_id_for_layout(self) -> NodeTypeId;
+ fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>>;
fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>>;
fn first_child_ref(self) -> Option<LayoutDom<'dom, Node>>;
fn last_child_ref(self) -> Option<LayoutDom<'dom, Node>>;
@@ -1645,7 +1646,7 @@ pub(crate) trait LayoutNodeHelpers<'dom> {
impl<'dom> LayoutDom<'dom, Node> {
#[inline]
#[allow(unsafe_code)]
- fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
+ pub(crate) fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
}
}
@@ -1662,6 +1663,12 @@ impl<'dom> LayoutNodeHelpers<'dom> for LayoutDom<'dom, Node> {
}
#[inline]
+ #[allow(unsafe_code)]
+ fn parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
+ unsafe { self.unsafe_get().parent_node.get_inner_as_layout() }
+ }
+
+ #[inline]
fn composed_parent_node_ref(self) -> Option<LayoutDom<'dom, Node>> {
let parent = self.parent_node_ref();
if let Some(parent) = parent {
diff --git a/components/script/dom/offscreencanvas.rs b/components/script/dom/offscreencanvas.rs
index cbcffb40e3e..391c83f3a84 100644
--- a/components/script/dom/offscreencanvas.rs
+++ b/components/script/dom/offscreencanvas.rs
@@ -126,10 +126,6 @@ impl OffscreenCanvas {
Some(context)
}
- pub(crate) fn is_valid(&self) -> bool {
- self.Width() != 0 && self.Height() != 0
- }
-
pub(crate) fn placeholder(&self) -> Option<&HTMLCanvasElement> {
self.placeholder.as_deref()
}
diff --git a/components/script/dom/raredata.rs b/components/script/dom/raredata.rs
index 0c048956217..2c303d6874f 100644
--- a/components/script/dom/raredata.rs
+++ b/components/script/dom/raredata.rs
@@ -11,6 +11,7 @@ use crate::dom::bindings::root::{Dom, MutNullableDom};
use crate::dom::customelementregistry::{
CustomElementDefinition, CustomElementReaction, CustomElementState,
};
+use crate::dom::domtokenlist::DOMTokenList;
use crate::dom::elementinternals::ElementInternals;
use crate::dom::htmlslotelement::SlottableData;
use crate::dom::intersectionobserver::IntersectionObserverRegistration;
@@ -76,4 +77,10 @@ pub(crate) struct ElementRareData {
/// > which is initialized to an empty list. This list holds IntersectionObserverRegistration records, which have:
pub(crate) registered_intersection_observers: Vec<IntersectionObserverRegistration>,
pub(crate) cryptographic_nonce: String,
+
+ /// <https://drafts.csswg.org/css-shadow-parts/#element-forwarded-part-name-list>
+ pub(crate) forwarded_part_names: Vec<(String, String)>,
+
+ /// <https://drafts.csswg.org/css-shadow-parts/#dom-element-part>
+ pub(crate) part: MutNullableDom<DOMTokenList>,
}
diff --git a/components/script/dom/webglrenderingcontext.rs b/components/script/dom/webglrenderingcontext.rs
index 9b8ee461979..aee785b0e12 100644
--- a/components/script/dom/webglrenderingcontext.rs
+++ b/components/script/dom/webglrenderingcontext.rs
@@ -575,6 +575,23 @@ impl WebGLRenderingContext {
pub(crate) fn get_image_pixels(&self, source: TexImageSource) -> Fallible<Option<TexPixels>> {
Ok(Some(match source {
+ TexImageSource::ImageBitmap(bitmap) => {
+ if !bitmap.origin_is_clean() {
+ return Err(Error::Security);
+ }
+ let Some(snapshot) = bitmap.bitmap_data().clone() else {
+ return Ok(None);
+ };
+
+ let snapshot = snapshot.as_ipc();
+ let size = snapshot.size().cast();
+ let format = match snapshot.format() {
+ snapshot::PixelFormat::RGBA => PixelFormat::RGBA8,
+ snapshot::PixelFormat::BGRA => PixelFormat::BGRA8,
+ };
+ let premultiply = snapshot.alpha_mode().is_premultiplied();
+ TexPixels::new(snapshot.to_ipc_shared_memory(), size, format, premultiply)
+ },
TexImageSource::ImageData(image_data) => TexPixels::new(
image_data.to_shared_memory(),
image_data.get_size(),
diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs
index dcaa025c778..fca40987898 100644
--- a/components/script/dom/window.rs
+++ b/components/script/dom/window.rs
@@ -1214,7 +1214,7 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
self.as_global_scope().queue_function_as_microtask(callback);
}
- // https://html.spec.whatwg.org/multipage/#dom-createimagebitmap
+ /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
fn CreateImageBitmap(
&self,
image: ImageBitmapSource,
@@ -1223,7 +1223,30 @@ impl WindowMethods<crate::DomTypeHolder> for Window {
) -> Rc<Promise> {
let p = self
.as_global_scope()
- .create_image_bitmap(image, options, can_gc);
+ .create_image_bitmap(image, 0, 0, None, None, options, can_gc);
+ p
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
+ fn CreateImageBitmap_(
+ &self,
+ image: ImageBitmapSource,
+ sx: i32,
+ sy: i32,
+ sw: i32,
+ sh: i32,
+ options: &ImageBitmapOptions,
+ can_gc: CanGc,
+ ) -> Rc<Promise> {
+ let p = self.as_global_scope().create_image_bitmap(
+ image,
+ sx,
+ sy,
+ Some(sw),
+ Some(sh),
+ options,
+ can_gc,
+ );
p
}
diff --git a/components/script/dom/windowproxy.rs b/components/script/dom/windowproxy.rs
index a8decee24ed..648146ac2e9 100644
--- a/components/script/dom/windowproxy.rs
+++ b/components/script/dom/windowproxy.rs
@@ -466,26 +466,40 @@ impl WindowProxy {
features: DOMString,
can_gc: CanGc,
) -> Fallible<Option<DomRoot<WindowProxy>>> {
- // Step 4.
+ // Step 5. If target is the empty string, then set target to "_blank".
let non_empty_target = match target.as_ref() {
"" => DOMString::from("_blank"),
_ => target,
};
- // Step 5
+ // Step 6. Let tokenizedFeatures be the result of tokenizing features.
let tokenized_features = tokenize_open_features(features);
- // Step 7-9
+ // Step 7 - 8.
+ // If tokenizedFeatures["noreferrer"] exists, then set noreferrer to
+ // the result of parsing tokenizedFeatures["noreferrer"] as a boolean feature.
let noreferrer = parse_open_feature_boolean(&tokenized_features, "noreferrer");
+
+ // Step 9. Let noopener be the result of getting noopener for window
+ // open with sourceDocument, tokenizedFeatures, and urlRecord.
let noopener = if noreferrer {
true
} else {
parse_open_feature_boolean(&tokenized_features, "noopener")
};
- // Step 10, 11
+ // (TODO) Step 10. Remove tokenizedFeatures["noopener"] and tokenizedFeatures["noreferrer"].
+
+ // (TODO) Step 11. Let referrerPolicy be the empty string.
+ // (TODO) Step 12. If noreferrer is true, then set referrerPolicy to "no-referrer".
+
+ // Step 13 - 14
+ // Let targetNavigable and windowType be the result of applying the rules for
+ // choosing a navigable given target, sourceDocument's node navigable, and noopener.
+ // If targetNavigable is null, then return null.
let (chosen, new) = match self.choose_browsing_context(non_empty_target, noopener) {
(Some(chosen), new) => (chosen, new),
(None, _) => return Ok(None),
};
- // TODO Step 12, set up browsing context features.
+ // TODO Step 15.2, Set up browsing context features for targetNavigable's
+ // active browsing context given tokenizedFeatures.
let target_document = match chosen.document() {
Some(target_document) => target_document,
None => return Ok(None),
@@ -496,7 +510,7 @@ impl WindowProxy {
false
};
let target_window = target_document.window();
- // Step 13, and 14.4, will have happened elsewhere,
+ // Step 15.3 and 15.4 will have happened elsewhere,
// since we've created a new browsing context and loaded it with about:blank.
if !url.is_empty() {
let existing_document = self
@@ -504,18 +518,18 @@ impl WindowProxy {
.get()
.and_then(ScriptThread::find_document)
.unwrap();
- // Step 14.1
let url = match existing_document.url().join(&url) {
Ok(url) => url,
Err(_) => return Err(Error::Syntax),
};
- // Step 14.3
let referrer = if noreferrer {
Referrer::NoReferrer
} else {
target_window.as_global_scope().get_referrer()
};
- // Step 14.5
+ // Step 15.5 Otherwise, navigate targetNavigable to urlRecord using sourceDocument,
+ // with referrerPolicy set to referrerPolicy and exceptionsEnabled set to true.
+ // FIXME: referrerPolicy may not be used properly here. exceptionsEnabled not used.
let referrer_policy = target_document.get_referrer_policy();
let pipeline_id = target_window.pipeline_id();
let secure = target_window.as_global_scope().is_secure_context();
@@ -534,14 +548,13 @@ impl WindowProxy {
} else {
NavigationHistoryBehavior::Push
};
-
target_window.load_url(history_handling, false, load_data, can_gc);
}
+ // Step 17 (Dis-owning has been done in create_auxiliary_browsing_context).
if noopener {
- // Step 15 (Dis-owning has been done in create_auxiliary_browsing_context).
return Ok(None);
}
- // Step 17.
+ // Step 18
Ok(target_document.browsing_context())
}
diff --git a/components/script/dom/workerglobalscope.rs b/components/script/dom/workerglobalscope.rs
index fa94dcc1d04..7912e90cdcf 100644
--- a/components/script/dom/workerglobalscope.rs
+++ b/components/script/dom/workerglobalscope.rs
@@ -446,7 +446,7 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
.queue_function_as_microtask(callback);
}
- // https://html.spec.whatwg.org/multipage/#dom-createimagebitmap
+ /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
fn CreateImageBitmap(
&self,
image: ImageBitmapSource,
@@ -455,7 +455,30 @@ impl WorkerGlobalScopeMethods<crate::DomTypeHolder> for WorkerGlobalScope {
) -> Rc<Promise> {
let p = self
.upcast::<GlobalScope>()
- .create_image_bitmap(image, options, can_gc);
+ .create_image_bitmap(image, 0, 0, None, None, options, can_gc);
+ p
+ }
+
+ /// <https://html.spec.whatwg.org/multipage/#dom-createimagebitmap>
+ fn CreateImageBitmap_(
+ &self,
+ image: ImageBitmapSource,
+ sx: i32,
+ sy: i32,
+ sw: i32,
+ sh: i32,
+ options: &ImageBitmapOptions,
+ can_gc: CanGc,
+ ) -> Rc<Promise> {
+ let p = self.upcast::<GlobalScope>().create_image_bitmap(
+ image,
+ sx,
+ sy,
+ Some(sw),
+ Some(sh),
+ options,
+ can_gc,
+ );
p
}
diff --git a/components/script/layout_dom/element.rs b/components/script/layout_dom/element.rs
index 9b50c9f3a2b..fd34d591f0c 100644
--- a/components/script/layout_dom/element.rs
+++ b/components/script/layout_dom/element.rs
@@ -216,11 +216,15 @@ impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
}
fn has_part_attr(&self) -> bool {
- false
+ self.element
+ .get_attr_for_layout(&ns!(), &local_name!("part"))
+ .is_some()
}
fn exports_any_part(&self) -> bool {
- false
+ self.element
+ .get_attr_for_layout(&ns!(), &local_name!("exportparts"))
+ .is_some()
}
fn style_attribute(&self) -> Option<ArcBorrow<StyleLocked<PropertyDeclarationBlock>>> {
@@ -292,6 +296,17 @@ impl<'dom> style::dom::TElement for ServoLayoutElement<'dom> {
}
}
+ fn each_part<F>(&self, mut callback: F)
+ where
+ F: FnMut(&AtomIdent),
+ {
+ if let Some(parts) = self.element.get_parts_for_layout() {
+ for part in parts {
+ callback(AtomIdent::cast(part))
+ }
+ }
+ }
+
fn has_dirty_descendants(&self) -> bool {
unsafe {
self.as_node()
@@ -728,8 +743,12 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
}
#[inline]
- fn is_part(&self, _name: &AtomIdent) -> bool {
- false
+ fn is_part(&self, name: &AtomIdent) -> bool {
+ self.element.has_class_or_part_for_layout(
+ name,
+ &local_name!("part"),
+ CaseSensitivity::CaseSensitive,
+ )
}
fn imported_part(&self, _: &AtomIdent) -> Option<AtomIdent> {
@@ -738,7 +757,8 @@ impl<'dom> ::selectors::Element for ServoLayoutElement<'dom> {
#[inline]
fn has_class(&self, name: &AtomIdent, case_sensitivity: CaseSensitivity) -> bool {
- self.element.has_class_for_layout(name, case_sensitivity)
+ self.element
+ .has_class_or_part_for_layout(name, &local_name!("class"), case_sensitivity)
}
fn is_html_slot_element(&self) -> bool {
diff --git a/components/script/layout_dom/node.rs b/components/script/layout_dom/node.rs
index dfb921b1ded..85b75f0b15f 100644
--- a/components/script/layout_dom/node.rs
+++ b/components/script/layout_dom/node.rs
@@ -119,9 +119,7 @@ impl<'dom> style::dom::TNode for ServoLayoutNode<'dom> {
type ConcreteShadowRoot = ServoShadowRoot<'dom>;
fn parent_node(&self) -> Option<Self> {
- self.node
- .composed_parent_node_ref()
- .map(Self::from_layout_js)
+ self.node.parent_node_ref().map(Self::from_layout_js)
}
fn first_child(&self) -> Option<Self> {
@@ -302,8 +300,8 @@ impl<'dom> ThreadSafeLayoutNode<'dom> for ServoThreadSafeLayoutNode<'dom> {
}
fn parent_style(&self) -> Arc<ComputedValues> {
- let parent = self.node.parent_node().unwrap().as_element().unwrap();
- let parent_data = parent.borrow_data().unwrap();
+ let parent_element = self.node.traversal_parent().unwrap();
+ let parent_data = parent_element.borrow_data().unwrap();
parent_data.styles.primary().clone()
}
diff --git a/components/script/webdriver_handlers.rs b/components/script/webdriver_handlers.rs
index 322839aa078..1bde6f314f2 100644
--- a/components/script/webdriver_handlers.rs
+++ b/components/script/webdriver_handlers.rs
@@ -9,9 +9,7 @@ use std::ptr::NonNull;
use base::id::{BrowsingContextId, PipelineId};
use cookie::Cookie;
-use embedder_traits::{
- WebDriverCookieError, WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue,
-};
+use embedder_traits::{WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue};
use euclid::default::{Point2D, Rect, Size2D};
use hyper_serde::Serde;
use ipc_channel::ipc::{self, IpcSender};
@@ -81,6 +79,8 @@ fn find_node_by_unique_id(
match documents.find_document(pipeline) {
Some(doc) => find_node_by_unique_id_in_document(&doc, node_id),
None => {
+ // FIXME: This is unreacheable!! Because we already early return in Constellation
+ // To be Fixed soon
if ScriptThread::has_node_id(pipeline, &node_id) {
Err(ErrorStatus::StaleElementReference)
} else {
@@ -994,7 +994,7 @@ pub(crate) fn handle_get_page_source(
pub(crate) fn handle_get_cookies(
documents: &DocumentCollection,
pipeline: PipelineId,
- reply: IpcSender<Vec<Serde<Cookie<'static>>>>,
+ reply: IpcSender<Result<Vec<Serde<Cookie<'static>>>, ErrorStatus>>,
) {
reply
.send(
@@ -1008,9 +1008,9 @@ pub(crate) fn handle_get_cookies(
.as_global_scope()
.resource_threads()
.send(GetCookiesDataForUrl(url, sender, NonHTTP));
- receiver.recv().unwrap()
+ Ok(receiver.recv().unwrap())
},
- None => Vec::new(),
+ None => Ok(Vec::new()),
},
)
.unwrap();
@@ -1021,7 +1021,7 @@ pub(crate) fn handle_get_cookie(
documents: &DocumentCollection,
pipeline: PipelineId,
name: String,
- reply: IpcSender<Vec<Serde<Cookie<'static>>>>,
+ reply: IpcSender<Result<Vec<Serde<Cookie<'static>>>, ErrorStatus>>,
) {
reply
.send(
@@ -1036,12 +1036,12 @@ pub(crate) fn handle_get_cookie(
.resource_threads()
.send(GetCookiesDataForUrl(url, sender, NonHTTP));
let cookies = receiver.recv().unwrap();
- cookies
+ Ok(cookies
.into_iter()
.filter(|cookie| cookie.name() == &*name)
- .collect()
+ .collect())
},
- None => Vec::new(),
+ None => Ok(Vec::new()),
},
)
.unwrap();
@@ -1052,15 +1052,13 @@ pub(crate) fn handle_add_cookie(
documents: &DocumentCollection,
pipeline: PipelineId,
cookie: Cookie<'static>,
- reply: IpcSender<Result<(), WebDriverCookieError>>,
+ reply: IpcSender<Result<(), ErrorStatus>>,
) {
// TODO: Return a different error if the pipeline doesn't exist
let document = match documents.find_document(pipeline) {
Some(document) => document,
None => {
- return reply
- .send(Err(WebDriverCookieError::UnableToSetCookie))
- .unwrap();
+ return reply.send(Err(ErrorStatus::UnableToSetCookie)).unwrap();
},
};
let url = document.url();
@@ -1073,7 +1071,7 @@ pub(crate) fn handle_add_cookie(
let domain = cookie.domain().map(ToOwned::to_owned);
reply
.send(match (document.is_cookie_averse(), domain) {
- (true, _) => Err(WebDriverCookieError::InvalidDomain),
+ (true, _) => Err(ErrorStatus::InvalidCookieDomain),
(false, Some(ref domain)) if url.host_str().map(|x| x == domain).unwrap_or(false) => {
let _ = document
.window()
@@ -1090,7 +1088,7 @@ pub(crate) fn handle_add_cookie(
.send(SetCookieForUrl(url, Serde(cookie), method));
Ok(())
},
- (_, _) => Err(WebDriverCookieError::UnableToSetCookie),
+ (_, _) => Err(ErrorStatus::UnableToSetCookie),
})
.unwrap();
}
diff --git a/components/script_bindings/codegen/Bindings.conf b/components/script_bindings/codegen/Bindings.conf
index dd034654974..edc099a823f 100644
--- a/components/script_bindings/codegen/Bindings.conf
+++ b/components/script_bindings/codegen/Bindings.conf
@@ -646,7 +646,7 @@ DOMInterfaces = {
},
'Window': {
- 'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'],
+ 'canGc': ['Stop', 'Fetch', 'Scroll', 'Scroll_','ScrollBy', 'ScrollBy_', 'Stop', 'Fetch', 'Open', 'CreateImageBitmap', 'CreateImageBitmap_', 'TrustedTypes', 'WebdriverCallback', 'WebdriverException'],
'inRealms': ['Fetch', 'GetOpener', 'WebdriverCallback', 'WebdriverException'],
'additionalTraits': ['crate::interfaces::WindowHelpers'],
},
@@ -658,7 +658,7 @@ DOMInterfaces = {
'WorkerGlobalScope': {
'inRealms': ['Fetch'],
- 'canGc': ['Fetch', 'CreateImageBitmap', 'ImportScripts', 'TrustedTypes'],
+ 'canGc': ['Fetch', 'CreateImageBitmap', 'CreateImageBitmap_', 'ImportScripts', 'TrustedTypes'],
},
'Worklet': {
diff --git a/components/script_bindings/webidls/CanvasRenderingContext2D.webidl b/components/script_bindings/webidls/CanvasRenderingContext2D.webidl
index 47612a29937..b277ec2df41 100644
--- a/components/script_bindings/webidls/CanvasRenderingContext2D.webidl
+++ b/components/script_bindings/webidls/CanvasRenderingContext2D.webidl
@@ -11,7 +11,7 @@ typedef HTMLImageElement HTMLOrSVGImageElement;
typedef (HTMLOrSVGImageElement or
HTMLVideoElement or
HTMLCanvasElement or
- /*ImageBitmap or*/
+ ImageBitmap or
OffscreenCanvas or
/*VideoFrame or*/
/*CSSImageValue*/ CSSStyleValue) CanvasImageSource;
diff --git a/components/script_bindings/webidls/Element.webidl b/components/script_bindings/webidls/Element.webidl
index 4545b18d058..e0073f856ca 100644
--- a/components/script_bindings/webidls/Element.webidl
+++ b/components/script_bindings/webidls/Element.webidl
@@ -144,3 +144,8 @@ Element includes NonDocumentTypeChildNode;
Element includes ParentNode;
Element includes ActivatableElement;
Element includes ARIAMixin;
+
+// https://drafts.csswg.org/css-shadow-parts/#idl
+partial interface Element {
+ [SameObject, PutForwards=value] readonly attribute DOMTokenList part;
+};
diff --git a/components/script_bindings/webidls/WebGLRenderingContext.webidl b/components/script_bindings/webidls/WebGLRenderingContext.webidl
index 6938e547cce..645eef0c23f 100644
--- a/components/script_bindings/webidls/WebGLRenderingContext.webidl
+++ b/components/script_bindings/webidls/WebGLRenderingContext.webidl
@@ -24,7 +24,8 @@ typedef unsigned long GLuint;
typedef unrestricted float GLfloat;
typedef unrestricted float GLclampf;
-typedef (ImageData or
+typedef (ImageBitmap or
+ ImageData or
HTMLImageElement or
HTMLCanvasElement or
HTMLVideoElement) TexImageSource;
diff --git a/components/script_bindings/webidls/WindowOrWorkerGlobalScope.webidl b/components/script_bindings/webidls/WindowOrWorkerGlobalScope.webidl
index deb3d5e2947..e329048b1fb 100644
--- a/components/script_bindings/webidls/WindowOrWorkerGlobalScope.webidl
+++ b/components/script_bindings/webidls/WindowOrWorkerGlobalScope.webidl
@@ -26,8 +26,9 @@ interface mixin WindowOrWorkerGlobalScope {
// ImageBitmap
[Pref="dom_imagebitmap_enabled"]
Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, optional ImageBitmapOptions options = {});
- // Promise<ImageBitmap> createImageBitmap(
- // ImageBitmapSource image, long sx, long sy, long sw, long sh, optional ImageBitmapOptions options);
+ [Pref="dom_imagebitmap_enabled"]
+ Promise<ImageBitmap> createImageBitmap(ImageBitmapSource image, long sx, long sy, long sw, long sh,
+ optional ImageBitmapOptions options = {});
// structured cloning
[Throws]
diff --git a/components/shared/embedder/webdriver.rs b/components/shared/embedder/webdriver.rs
index d28bb6fc6c3..4f58c10fb6f 100644
--- a/components/shared/embedder/webdriver.rs
+++ b/components/shared/embedder/webdriver.rs
@@ -94,7 +94,7 @@ pub enum WebDriverScriptCommand {
serialize_with = "::hyper_serde::serialize"
)]
Cookie<'static>,
- IpcSender<Result<(), WebDriverCookieError>>,
+ IpcSender<Result<(), ErrorStatus>>,
),
DeleteCookies(IpcSender<Result<(), ErrorStatus>>),
DeleteCookie(String, IpcSender<Result<(), ErrorStatus>>),
@@ -134,8 +134,11 @@ pub enum WebDriverScriptCommand {
ElementClick(String, IpcSender<Result<Option<String>, ErrorStatus>>),
GetActiveElement(IpcSender<Option<String>>),
GetComputedRole(String, IpcSender<Result<Option<String>, ErrorStatus>>),
- GetCookie(String, IpcSender<Vec<Serde<Cookie<'static>>>>),
- GetCookies(IpcSender<Vec<Serde<Cookie<'static>>>>),
+ GetCookie(
+ String,
+ IpcSender<Result<Vec<Serde<Cookie<'static>>>, ErrorStatus>>,
+ ),
+ GetCookies(IpcSender<Result<Vec<Serde<Cookie<'static>>>, ErrorStatus>>),
GetElementAttribute(
String,
String,
@@ -165,12 +168,6 @@ pub enum WebDriverScriptCommand {
WillSendKeys(String, String, bool, IpcSender<Result<bool, ErrorStatus>>),
}
-#[derive(Debug, Deserialize, Serialize)]
-pub enum WebDriverCookieError {
- InvalidDomain,
- UnableToSetCookie,
-}
-
#[derive(Clone, Debug, Deserialize, Serialize)]
pub enum WebDriverJSValue {
Undefined,
diff --git a/components/webdriver_server/lib.rs b/components/webdriver_server/lib.rs
index 5d5159f7232..f2638764df6 100644
--- a/components/webdriver_server/lib.rs
+++ b/components/webdriver_server/lib.rs
@@ -24,9 +24,9 @@ use constellation_traits::{EmbedderToConstellationMessage, TraversalDirection};
use cookie::{CookieBuilder, Expiration};
use crossbeam_channel::{Receiver, Sender, after, select, unbounded};
use embedder_traits::{
- MouseButton, WebDriverCommandMsg, WebDriverCommandResponse, WebDriverCookieError,
- WebDriverFrameId, WebDriverJSError, WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus,
- WebDriverMessageId, WebDriverScriptCommand,
+ MouseButton, WebDriverCommandMsg, WebDriverCommandResponse, WebDriverFrameId, WebDriverJSError,
+ WebDriverJSResult, WebDriverJSValue, WebDriverLoadStatus, WebDriverMessageId,
+ WebDriverScriptCommand,
};
use euclid::{Rect, Size2D};
use http::method::Method;
@@ -949,6 +949,7 @@ impl Handler {
)))
}
+ /// <https://w3c.github.io/webdriver/#new-window>
fn handle_new_window(
&mut self,
_parameters: &NewWindowParameters,
@@ -956,11 +957,16 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let session = self.session().unwrap();
+ // Step 2. (TODO) If session's current top-level browsing context is no longer open,
+ // return error with error code no such window.
+
let cmd_msg = WebDriverCommandMsg::NewWebView(
session.webview_id,
sender,
self.load_status_sender.clone(),
);
+ // Step 5. Create a new top-level browsing context by running the window open steps.
+ // This MUST be done without invoking the focusing steps.
self.constellation_chan
.send(EmbedderToConstellationMessage::WebDriverCommand(cmd_msg))
.unwrap();
@@ -968,8 +974,6 @@ impl Handler {
let mut handle = self.session.as_ref().unwrap().id.to_string();
if let Ok(new_webview_id) = receiver.recv() {
let session = self.session_mut().unwrap();
- session.webview_id = new_webview_id;
- session.browsing_context_id = BrowsingContextId::from(new_webview_id);
let new_handle = Uuid::new_v4().to_string();
handle = new_handle.clone();
session.window_handles.insert(new_webview_id, new_handle);
@@ -1365,7 +1369,10 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetCookies(sender);
self.browsing_context_script_command(cmd)?;
- let cookies = wait_for_script_response(receiver)?;
+ let cookies = match wait_for_script_response(receiver)? {
+ Ok(cookies) => cookies,
+ Err(error) => return Err(WebDriverError::new(error, "")),
+ };
let response = cookies
.into_iter()
.map(|cookie| cookie_msg_to_cookie(cookie.into_inner()))
@@ -1377,7 +1384,10 @@ impl Handler {
let (sender, receiver) = ipc::channel().unwrap();
let cmd = WebDriverScriptCommand::GetCookie(name, sender);
self.browsing_context_script_command(cmd)?;
- let cookies = wait_for_script_response(receiver)?;
+ let cookies = match wait_for_script_response(receiver)? {
+ Ok(cookies) => cookies,
+ Err(error) => return Err(WebDriverError::new(error, "")),
+ };
let Some(response) = cookies
.into_iter()
.map(|cookie| cookie_msg_to_cookie(cookie.into_inner()))
@@ -1410,16 +1420,7 @@ impl Handler {
self.browsing_context_script_command(cmd)?;
match wait_for_script_response(receiver)? {
Ok(_) => Ok(WebDriverResponse::Void),
- Err(response) => match response {
- WebDriverCookieError::InvalidDomain => Err(WebDriverError::new(
- ErrorStatus::InvalidCookieDomain,
- "Invalid cookie domain",
- )),
- WebDriverCookieError::UnableToSetCookie => Err(WebDriverError::new(
- ErrorStatus::UnableToSetCookie,
- "Unable to set cookie",
- )),
- },
+ Err(error) => Err(WebDriverError::new(error, "")),
}
}