diff options
Diffstat (limited to 'components/script/dom')
-rw-r--r-- | components/script/dom/bindings/structuredclone.rs | 27 | ||||
-rw-r--r-- | components/script/dom/globalscope.rs | 6 | ||||
-rw-r--r-- | components/script/dom/htmlareaelement.rs | 26 | ||||
-rw-r--r-- | components/script/dom/imagebitmap.rs | 133 | ||||
-rw-r--r-- | components/script/dom/urlpattern.rs | 182 |
5 files changed, 321 insertions, 53 deletions
diff --git a/components/script/dom/bindings/structuredclone.rs b/components/script/dom/bindings/structuredclone.rs index c23156817cb..73974abe714 100644 --- a/components/script/dom/bindings/structuredclone.rs +++ b/components/script/dom/bindings/structuredclone.rs @@ -10,11 +10,13 @@ use std::os::raw; use std::ptr; use base::id::{ - BlobId, DomExceptionId, DomPointId, Index, MessagePortId, NamespaceIndex, PipelineNamespaceId, + BlobId, DomExceptionId, DomPointId, ImageBitmapId, Index, MessagePortId, NamespaceIndex, + PipelineNamespaceId, }; use constellation_traits::{ BlobImpl, DomException, DomPoint, MessagePortImpl, Serializable as SerializableInterface, - StructuredSerializedData, Transferrable as TransferrableInterface, TransformStreamData, + SerializableImageBitmap, StructuredSerializedData, Transferrable as TransferrableInterface, + TransformStreamData, }; use js::gc::RootedVec; use js::glue::{ @@ -42,6 +44,7 @@ use crate::dom::blob::Blob; use crate::dom::dompoint::DOMPoint; use crate::dom::dompointreadonly::DOMPointReadOnly; use crate::dom::globalscope::GlobalScope; +use crate::dom::imagebitmap::ImageBitmap; use crate::dom::messageport::MessagePort; use crate::dom::readablestream::ReadableStream; use crate::dom::types::{DOMException, TransformStream}; @@ -66,6 +69,7 @@ pub(super) enum StructuredCloneTags { DomException = 0xFFFF8007, WritableStream = 0xFFFF8008, TransformStream = 0xFFFF8009, + ImageBitmap = 0xFFFF800A, Max = 0xFFFFFFFF, } @@ -76,6 +80,7 @@ impl From<SerializableInterface> for StructuredCloneTags { SerializableInterface::DomPointReadOnly => StructuredCloneTags::DomPointReadOnly, SerializableInterface::DomPoint => StructuredCloneTags::DomPoint, SerializableInterface::DomException => StructuredCloneTags::DomException, + SerializableInterface::ImageBitmap => StructuredCloneTags::ImageBitmap, } } } @@ -83,6 +88,7 @@ impl From<SerializableInterface> for StructuredCloneTags { impl From<TransferrableInterface> for StructuredCloneTags { fn from(v: TransferrableInterface) -> Self { match v { + TransferrableInterface::ImageBitmap => StructuredCloneTags::ImageBitmap, TransferrableInterface::MessagePort => StructuredCloneTags::MessagePort, TransferrableInterface::ReadableStream => StructuredCloneTags::ReadableStream, TransferrableInterface::WritableStream => StructuredCloneTags::WritableStream, @@ -104,6 +110,7 @@ fn reader_for_type( SerializableInterface::DomPointReadOnly => read_object::<DOMPointReadOnly>, SerializableInterface::DomPoint => read_object::<DOMPoint>, SerializableInterface::DomException => read_object::<DOMException>, + SerializableInterface::ImageBitmap => read_object::<ImageBitmap>, } } @@ -237,6 +244,7 @@ fn serialize_for_type(val: SerializableInterface) -> SerializeOperation { SerializableInterface::DomPointReadOnly => try_serialize::<DOMPointReadOnly>, SerializableInterface::DomPoint => try_serialize::<DOMPoint>, SerializableInterface::DomException => try_serialize::<DOMException>, + SerializableInterface::ImageBitmap => try_serialize::<ImageBitmap>, } } @@ -264,6 +272,7 @@ fn receiver_for_type( ) -> fn(&GlobalScope, &mut StructuredDataReader<'_>, u64, RawMutableHandleObject) -> Result<(), ()> { match val { + TransferrableInterface::ImageBitmap => receive_object::<ImageBitmap>, TransferrableInterface::MessagePort => receive_object::<MessagePort>, TransferrableInterface::ReadableStream => receive_object::<ReadableStream>, TransferrableInterface::WritableStream => receive_object::<WritableStream>, @@ -390,6 +399,7 @@ type TransferOperation = unsafe fn( fn transfer_for_type(val: TransferrableInterface) -> TransferOperation { match val { + TransferrableInterface::ImageBitmap => try_transfer::<ImageBitmap>, TransferrableInterface::MessagePort => try_transfer::<MessagePort>, TransferrableInterface::ReadableStream => try_transfer::<ReadableStream>, TransferrableInterface::WritableStream => try_transfer::<WritableStream>, @@ -439,6 +449,7 @@ unsafe fn can_transfer_for_type( root_from_object::<T>(*obj, cx).map(|o| Transferable::can_transfer(&*o)) } match transferable { + TransferrableInterface::ImageBitmap => can_transfer::<ImageBitmap>(obj, cx), TransferrableInterface::MessagePort => can_transfer::<MessagePort>(obj, cx), TransferrableInterface::ReadableStream => can_transfer::<ReadableStream>(obj, cx), TransferrableInterface::WritableStream => can_transfer::<WritableStream>(obj, cx), @@ -527,6 +538,10 @@ pub(crate) struct StructuredDataReader<'a> { pub(crate) points: Option<HashMap<DomPointId, DomPoint>>, /// A map of serialized exceptions. pub(crate) exceptions: Option<HashMap<DomExceptionId, DomException>>, + // A map of serialized image bitmaps. + pub(crate) image_bitmaps: Option<HashMap<ImageBitmapId, SerializableImageBitmap>>, + /// A map of transferred image bitmaps. + pub(crate) transferred_image_bitmaps: Option<HashMap<ImageBitmapId, SerializableImageBitmap>>, } /// A data holder for transferred and serialized objects. @@ -545,6 +560,10 @@ pub(crate) struct StructuredDataWriter { pub(crate) exceptions: Option<HashMap<DomExceptionId, DomException>>, /// Serialized blobs. pub(crate) blobs: Option<HashMap<BlobId, BlobImpl>>, + /// Serialized image bitmaps. + pub(crate) image_bitmaps: Option<HashMap<ImageBitmapId, SerializableImageBitmap>>, + /// Transferred image bitmaps. + pub(crate) transferred_image_bitmaps: Option<HashMap<ImageBitmapId, SerializableImageBitmap>>, } /// Writes a structured clone. Returns a `DataClone` error if that fails. @@ -599,6 +618,8 @@ pub(crate) fn write( points: sc_writer.points.take(), exceptions: sc_writer.exceptions.take(), blobs: sc_writer.blobs.take(), + image_bitmaps: sc_writer.image_bitmaps.take(), + transferred_image_bitmaps: sc_writer.transferred_image_bitmaps.take(), }; Ok(data) @@ -623,6 +644,8 @@ pub(crate) fn read( points: data.points.take(), exceptions: data.exceptions.take(), errors: DOMErrorRecord { message: None }, + image_bitmaps: data.image_bitmaps.take(), + transferred_image_bitmaps: data.transferred_image_bitmaps.take(), }; let sc_reader_ptr = &mut sc_reader as *mut _; unsafe { diff --git a/components/script/dom/globalscope.rs b/components/script/dom/globalscope.rs index 55db2e4d248..ec2ed70dd15 100644 --- a/components/script/dom/globalscope.rs +++ b/components/script/dom/globalscope.rs @@ -2992,8 +2992,7 @@ impl GlobalScope { if let Some(snapshot) = canvas.get_image_data() { let size = snapshot.size().cast(); - let image_bitmap = - ImageBitmap::new(self, size.width, size.height, can_gc).unwrap(); + let image_bitmap = ImageBitmap::new(self, size.width, size.height, can_gc); image_bitmap.set_bitmap_data(snapshot.to_vec()); image_bitmap.set_origin_clean(canvas.origin_is_clean()); p.resolve_native(&(image_bitmap), can_gc); @@ -3009,8 +3008,7 @@ impl GlobalScope { if let Some(snapshot) = canvas.get_image_data() { let size = snapshot.size().cast(); - let image_bitmap = - ImageBitmap::new(self, size.width, size.height, can_gc).unwrap(); + let image_bitmap = ImageBitmap::new(self, size.width, size.height, can_gc); image_bitmap.set_bitmap_data(snapshot.to_vec()); image_bitmap.set_origin_clean(canvas.origin_is_clean()); p.resolve_native(&(image_bitmap), can_gc); diff --git a/components/script/dom/htmlareaelement.rs b/components/script/dom/htmlareaelement.rs index a9d94cbd7b2..535d296a29f 100644 --- a/components/script/dom/htmlareaelement.rs +++ b/components/script/dom/htmlareaelement.rs @@ -46,6 +46,8 @@ pub enum Area { bottom_right: (f32, f32), }, Polygon { + /// Stored as a flat array of coordinates + /// e.g. [x1, y1, x2, y2, x3, y3] for a triangle points: Vec<f32>, }, } @@ -203,8 +205,28 @@ impl Area { p.y >= top_left.1 }, - //TODO polygon hit_test - _ => false, + Area::Polygon { ref points } => { + // Ray-casting algorithm to determine if point is inside polygon + // https://en.wikipedia.org/wiki/Point_in_polygon#Ray_casting_algorithm + let mut inside = false; + + debug_assert!(points.len() % 2 == 0); + let vertices = points.len() / 2; + + for i in 0..vertices { + let next_i = if i + 1 == vertices { 0 } else { i + 1 }; + + let xi = points[2 * i]; + let yi = points[2 * i + 1]; + let xj = points[2 * next_i]; + let yj = points[2 * next_i + 1]; + + if (yi > p.y) != (yj > p.y) && p.x < (xj - xi) * (p.y - yi) / (yj - yi) + xi { + inside = !inside; + } + } + inside + }, } } diff --git a/components/script/dom/imagebitmap.rs b/components/script/dom/imagebitmap.rs index ef6538e7451..97a1a54bba7 100644 --- a/components/script/dom/imagebitmap.rs +++ b/components/script/dom/imagebitmap.rs @@ -3,15 +3,20 @@ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ use std::cell::Cell; +use std::collections::HashMap; use std::vec::Vec; +use base::id::{ImageBitmapId, ImageBitmapIndex}; +use constellation_traits::SerializableImageBitmap; use dom_struct::dom_struct; use crate::dom::bindings::cell::DomRefCell; use crate::dom::bindings::codegen::Bindings::ImageBitmapBinding::ImageBitmapMethods; -use crate::dom::bindings::error::Fallible; use crate::dom::bindings::reflector::{Reflector, reflect_dom_object}; use crate::dom::bindings::root::DomRoot; +use crate::dom::bindings::serializable::Serializable; +use crate::dom::bindings::structuredclone::StructuredData; +use crate::dom::bindings::transferable::Transferable; use crate::dom::globalscope::GlobalScope; use crate::script_runtime::CanGc; @@ -29,33 +34,36 @@ pub(crate) struct ImageBitmap { } impl ImageBitmap { - fn new_inherited(width_arg: u32, height_arg: u32) -> ImageBitmap { + fn new_inherited(width: u32, height: u32) -> ImageBitmap { ImageBitmap { reflector_: Reflector::new(), - width: width_arg, - height: height_arg, + width, + height, bitmap_data: DomRefCell::new(Some(vec![])), origin_clean: Cell::new(true), } } - #[allow(dead_code)] pub(crate) fn new( global: &GlobalScope, width: u32, height: u32, can_gc: CanGc, - ) -> Fallible<DomRoot<ImageBitmap>> { + ) -> DomRoot<ImageBitmap> { //assigning to a variable the return object of new_inherited let imagebitmap = Box::new(ImageBitmap::new_inherited(width, height)); - Ok(reflect_dom_object(imagebitmap, global, can_gc)) + reflect_dom_object(imagebitmap, global, can_gc) } pub(crate) fn set_bitmap_data(&self, data: Vec<u8>) { *self.bitmap_data.borrow_mut() = Some(data); } + pub(crate) fn origin_is_clean(&self) -> bool { + self.origin_clean.get() + } + pub(crate) fn set_origin_clean(&self, origin_is_clean: bool) { self.origin_clean.set(origin_is_clean); } @@ -67,6 +75,117 @@ impl ImageBitmap { } } +impl Serializable for ImageBitmap { + type Index = ImageBitmapIndex; + type Data = SerializableImageBitmap; + + /// <https://html.spec.whatwg.org/multipage/#the-imagebitmap-interface:serialization-steps> + fn serialize(&self) -> Result<(ImageBitmapId, Self::Data), ()> { + // Step 1. If value's origin-clean flag is not set, then throw a "DataCloneError" DOMException. + if !self.origin_is_clean() { + return Err(()); + } + + // If value has a [[Detached]] internal slot whose value is true, + // then throw a "DataCloneError" DOMException. + if self.is_detached() { + return Err(()); + } + + // Step 2. Set serialized.[[BitmapData]] to a copy of value's bitmap data. + let serialized = SerializableImageBitmap { + width: self.width, + height: self.height, + bitmap_data: self.bitmap_data.borrow().clone().unwrap(), + }; + + Ok((ImageBitmapId::new(), serialized)) + } + + /// <https://html.spec.whatwg.org/multipage/#the-imagebitmap-interface:deserialization-steps> + fn deserialize( + owner: &GlobalScope, + serialized: Self::Data, + can_gc: CanGc, + ) -> Result<DomRoot<Self>, ()> { + let image_bitmap = ImageBitmap::new(owner, serialized.width, serialized.height, can_gc); + + // Step 1. Set value's bitmap data to serialized.[[BitmapData]]. + image_bitmap.set_bitmap_data(serialized.bitmap_data); + + Ok(image_bitmap) + } + + fn serialized_storage<'a>( + reader: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<ImageBitmapId, Self::Data>> { + match reader { + StructuredData::Reader(r) => &mut r.image_bitmaps, + StructuredData::Writer(w) => &mut w.image_bitmaps, + } + } +} + +impl Transferable for ImageBitmap { + type Index = ImageBitmapIndex; + type Data = SerializableImageBitmap; + + fn can_transfer(&self) -> bool { + if !self.origin_is_clean() || self.is_detached() { + return false; + } + true + } + + /// <https://html.spec.whatwg.org/multipage/#the-imagebitmap-interface:transfer-steps> + fn transfer(&self) -> Result<(ImageBitmapId, SerializableImageBitmap), ()> { + // Step 1. If value's origin-clean flag is not set, then throw a "DataCloneError" DOMException. + if !self.origin_is_clean() { + return Err(()); + } + + // If value has a [[Detached]] internal slot whose value is true, + // then throw a "DataCloneError" DOMException. + if self.is_detached() { + return Err(()); + } + + // Step 2. Set dataHolder.[[BitmapData]] to value's bitmap data. + // Step 3. Unset value's bitmap data. + let serialized = SerializableImageBitmap { + width: self.width, + height: self.height, + bitmap_data: self.bitmap_data.borrow_mut().take().unwrap(), + }; + + Ok((ImageBitmapId::new(), serialized)) + } + + /// <https://html.spec.whatwg.org/multipage/#the-imagebitmap-interface:transfer-receiving-steps> + fn transfer_receive( + owner: &GlobalScope, + _: ImageBitmapId, + serialized: SerializableImageBitmap, + ) -> Result<DomRoot<Self>, ()> { + let image_bitmap = + ImageBitmap::new(owner, serialized.width, serialized.height, CanGc::note()); + + // Step 1. Set value's bitmap data to serialized.[[BitmapData]]. + image_bitmap.set_bitmap_data(serialized.bitmap_data); + + Ok(image_bitmap) + } + + fn serialized_storage<'a>( + data: StructuredData<'a, '_>, + ) -> &'a mut Option<HashMap<ImageBitmapId, Self::Data>> { + match data { + StructuredData::Reader(r) => &mut r.transferred_image_bitmaps, + StructuredData::Writer(w) => &mut w.transferred_image_bitmaps, + } + } +} + impl ImageBitmapMethods<crate::DomTypeHolder> for ImageBitmap { /// <https://html.spec.whatwg.org/multipage/#dom-imagebitmap-height> fn Height(&self) -> u32 { diff --git a/components/script/dom/urlpattern.rs b/components/script/dom/urlpattern.rs index c811d3a9a70..63665f6df0b 100644 --- a/components/script/dom/urlpattern.rs +++ b/components/script/dom/urlpattern.rs @@ -4,6 +4,7 @@ use dom_struct::dom_struct; use js::rust::HandleObject; +use script_bindings::codegen::GenericBindings::URLPatternBinding::URLPatternResult; use script_bindings::codegen::GenericUnionTypes::USVStringOrURLPatternInit; use script_bindings::error::{Error, Fallible}; use script_bindings::reflector::Reflector; @@ -46,7 +47,7 @@ impl URLPattern { ) -> Fallible<DomRoot<URLPattern>> { // The section below converts from servos types to the types used in the urlpattern crate let base_url = base_url.map(|usv_string| usv_string.0); - let input = bindings_to_third_party::map_urlpattern_input(input, base_url.clone()); + let input = bindings_to_third_party::map_urlpattern_input(input); let options = urlpattern::UrlPatternOptions { ignore_case: options.ignoreCase, }; @@ -94,6 +95,50 @@ impl URLPatternMethods<crate::DomTypeHolder> for URLPattern { URLPattern::initialize(global, proto, input, None, options, can_gc) } + /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-test> + fn Test( + &self, + input: USVStringOrURLPatternInit, + base_url: Option<USVString>, + ) -> Fallible<bool> { + let input = bindings_to_third_party::map_urlpattern_input(input); + let inputs = urlpattern::quirks::process_match_input(input, base_url.as_deref()) + .map_err(|error| Error::Type(format!("{error}")))?; + let Some((match_input, _)) = inputs else { + return Ok(false); + }; + + self.associated_url_pattern + .test(match_input) + .map_err(|error| Error::Type(format!("{error}"))) + } + + /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-exec> + fn Exec( + &self, + input: USVStringOrURLPatternInit, + base_url: Option<USVString>, + ) -> Fallible<Option<URLPatternResult>> { + let input = bindings_to_third_party::map_urlpattern_input(input); + let inputs = urlpattern::quirks::process_match_input(input, base_url.as_deref()) + .map_err(|error| Error::Type(format!("{error}")))?; + let Some((match_input, inputs)) = inputs else { + return Ok(None); + }; + + let result = self + .associated_url_pattern + .exec(match_input) + .map_err(|error| Error::Type(format!("{error}")))?; + let Some(result) = result else { + return Ok(None); + }; + + Ok(Some(third_party_to_bindings::map_urlpattern_result( + result, inputs, + ))) + } + /// <https://urlpattern.spec.whatwg.org/#dom-urlpattern-protocol> fn Protocol(&self) -> USVString { // Step 1. Return this’s associated URL pattern’s protocol component’s pattern string. @@ -151,54 +196,115 @@ impl URLPatternMethods<crate::DomTypeHolder> for URLPattern { } mod bindings_to_third_party { + use script_bindings::codegen::GenericBindings::URLPatternBinding::URLPatternInit; + use crate::dom::urlpattern::USVStringOrURLPatternInit; + fn map_urlpatterninit(pattern_init: URLPatternInit) -> urlpattern::quirks::UrlPatternInit { + urlpattern::quirks::UrlPatternInit { + protocol: pattern_init.protocol.map(|protocol| protocol.0), + username: pattern_init.username.map(|username| username.0), + password: pattern_init.password.map(|password| password.0), + hostname: pattern_init.hostname.map(|hostname| hostname.0), + port: pattern_init.port.map(|hash| hash.0), + pathname: pattern_init + .pathname + .as_ref() + .map(|usv_string| usv_string.to_string()), + search: pattern_init.search.map(|search| search.0), + hash: pattern_init.hash.map(|hash| hash.0), + base_url: pattern_init.baseURL.map(|base_url| base_url.0), + } + } + pub(super) fn map_urlpattern_input( input: USVStringOrURLPatternInit, - base_url: Option<String>, ) -> urlpattern::quirks::StringOrInit { match input { USVStringOrURLPatternInit::USVString(usv_string) => { urlpattern::quirks::StringOrInit::String(usv_string.0) }, USVStringOrURLPatternInit::URLPatternInit(pattern_init) => { - let pattern_init = urlpattern::quirks::UrlPatternInit { - protocol: pattern_init - .protocol - .as_ref() - .map(|usv_string| usv_string.to_string()), - username: pattern_init - .username - .as_ref() - .map(|usv_string| usv_string.to_string()), - password: pattern_init - .password - .as_ref() - .map(|usv_string| usv_string.to_string()), - hostname: pattern_init - .hostname - .as_ref() - .map(|usv_string| usv_string.to_string()), - port: pattern_init - .port - .as_ref() - .map(|usv_string| usv_string.to_string()), - pathname: pattern_init - .pathname - .as_ref() - .map(|usv_string| usv_string.to_string()), - search: pattern_init - .search - .as_ref() - .map(|usv_string| usv_string.to_string()), - hash: pattern_init - .hash - .as_ref() - .map(|usv_string| usv_string.to_string()), - base_url, - }; - urlpattern::quirks::StringOrInit::Init(pattern_init) + urlpattern::quirks::StringOrInit::Init(map_urlpatterninit(pattern_init)) + }, + } + } +} + +mod third_party_to_bindings { + use script_bindings::codegen::GenericBindings::URLPatternBinding::{ + URLPatternComponentResult, URLPatternInit, URLPatternResult, + }; + use script_bindings::codegen::GenericUnionTypes::USVStringOrUndefined; + use script_bindings::record::Record; + use script_bindings::str::USVString; + + use crate::dom::bindings::codegen::UnionTypes::USVStringOrURLPatternInit; + + // FIXME: For some reason codegen puts a lot of options into these types that don't make sense + + fn map_component_result( + component_result: urlpattern::UrlPatternComponentResult, + ) -> URLPatternComponentResult { + let mut groups = Record::new(); + for (key, value) in component_result.groups.iter() { + let value = match value { + Some(value) => USVStringOrUndefined::USVString(USVString(value.to_owned())), + None => USVStringOrUndefined::Undefined(()), + }; + + groups.insert(USVString(key.to_owned()), value); + } + + URLPatternComponentResult { + input: Some(component_result.input.into()), + groups: Some(groups), + } + } + + fn map_urlpatterninit(pattern_init: urlpattern::quirks::UrlPatternInit) -> URLPatternInit { + URLPatternInit { + baseURL: pattern_init.base_url.map(USVString), + protocol: pattern_init.protocol.map(USVString), + username: pattern_init.username.map(USVString), + password: pattern_init.password.map(USVString), + hostname: pattern_init.hostname.map(USVString), + port: pattern_init.port.map(USVString), + pathname: pattern_init.pathname.map(USVString), + search: pattern_init.search.map(USVString), + hash: pattern_init.hash.map(USVString), + } + } + + pub(super) fn map_urlpattern_result( + result: urlpattern::UrlPatternResult, + (string_or_init, base_url): urlpattern::quirks::Inputs, + ) -> URLPatternResult { + let string_or_init = match string_or_init { + urlpattern::quirks::StringOrInit::String(string) => { + USVStringOrURLPatternInit::USVString(USVString(string)) + }, + urlpattern::quirks::StringOrInit::Init(pattern_init) => { + USVStringOrURLPatternInit::URLPatternInit(map_urlpatterninit(pattern_init)) }, + }; + + let mut inputs = vec![string_or_init]; + + if let Some(base_url) = base_url { + inputs.push(USVStringOrURLPatternInit::USVString(USVString(base_url))); + } + + URLPatternResult { + inputs: Some(inputs), + protocol: Some(map_component_result(result.protocol)), + username: Some(map_component_result(result.username)), + password: Some(map_component_result(result.password)), + hostname: Some(map_component_result(result.hostname)), + port: Some(map_component_result(result.port)), + pathname: Some(map_component_result(result.pathname)), + search: Some(map_component_result(result.search)), + hash: Some(map_component_result(result.hash)), } } } |