diff options
Diffstat (limited to 'components')
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, "")), } } |