From 5daf5c55e3afe609b40224b40a7b4bf68c1b69ec Mon Sep 17 00:00:00 2001 From: Bentaimia Haddadi Date: Thu, 29 Feb 2024 18:21:25 +0100 Subject: [PATCH] Decode HTML Image Signed-off-by: Bentaimia Haddadi --- components/net/image_cache.rs | 20 +++++- components/script/dom/htmlimageelement.rs | 80 ++++++++++++++++++----- components/shared/net/image_cache.rs | 7 ++ 3 files changed, 90 insertions(+), 17 deletions(-) diff --git a/components/net/image_cache.rs b/components/net/image_cache.rs index d7dc1e171d6..0446f957114 100644 --- a/components/net/image_cache.rs +++ b/components/net/image_cache.rs @@ -41,7 +41,6 @@ use crate::resource_thread::CoreResourceThreadPool; // ====================================================================== fn decode_bytes_sync(key: LoadKey, bytes: &[u8], cors: CorsStatus) -> DecoderMsg { - // decode let image = load_from_memory(bytes, cors); DecoderMsg { key, image } } @@ -571,6 +570,25 @@ impl ImageCache for ImageCacheImpl { cache_result } + fn decode( + &self, + url: ServoUrl, + origin: ImmutableOrigin, + cors_setting: Option, + ) -> Option { + let mut store: std::sync::MutexGuard<'_, ImageCacheStore> = self.store.lock().unwrap(); + + let result = store + .pending_loads + .get_cached(url.clone(), origin.clone(), cors_setting); + match result { + CacheResult::Hit(key, pl) => { + return decode_bytes_sync(key, &pl.bytes.as_slice(), pl.cors_status).image + }, + CacheResult::Miss(_) => return None, + } + } + /// Add a new listener for the given pending image id. If the image is already present, /// the responder will still receive the expected response. fn add_listener(&self, id: PendingImageId, listener: ImageResponder) { diff --git a/components/script/dom/htmlimageelement.rs b/components/script/dom/htmlimageelement.rs index 79c8fffc411..eddd777ef46 100644 --- a/components/script/dom/htmlimageelement.rs +++ b/components/script/dom/htmlimageelement.rs @@ -920,6 +920,53 @@ impl HTMLImageElement { } } + /// Step 2-2.2 of https://html.spec.whatwg.org/multipage/embedded-content.html#dom-img-decode + fn decode_image_data_sync(&self, promise: &Rc) { + let document = document_from_node(self); + let window = document.window(); + let elem = self.upcast::(); + let src = elem.get_url_attribute(&local_name!("src")); + let base_url = document.base_url(); + + let image_cache = window.image_cache(); + + if let Ok(img_url) = base_url.join(&src) { + // Step 2.1 + let available = match self.current_request.borrow().state { + State::Unavailable => false, + State::PartiallyAvailable => false, + State::CompletelyAvailable => true, + State::Broken => false, + }; + + // Step 2.2 + if document.is_fully_active() || !available { + let decode_result: Option = image_cache.decode( + img_url.clone(), + window.origin().immutable().clone(), + cors_setting_for_element(self.upcast()), + ); + + match decode_result { + Some(_) => { + promise.resolve_native(&()); + }, + None => { + promise.reject_native(&DOMException::new( + &self.global(), + DOMErrorName::EncodingError, + )); + }, + } + } else { + promise.reject_native(&DOMException::new( + &self.global(), + DOMErrorName::EncodingError, + )); + } + } + } + /// pub fn update_the_image_data(&self) { let document = document_from_node(self); @@ -1349,6 +1396,11 @@ pub enum ImageElementMicrotask { elem: DomRoot, generation: u32, }, + DecodeTask { + elem: DomRoot, + #[ignore_malloc_size_of = "promises are hard"] + promise: Rc, + }, } impl MicrotaskRunnable for ImageElementMicrotask { @@ -1370,13 +1422,20 @@ impl MicrotaskRunnable for ImageElementMicrotask { } => { elem.react_to_environment_changes_sync_steps(*generation); }, + &ImageElementMicrotask::DecodeTask { + ref elem, + ref promise, + } => { + elem.decode_image_data_sync(promise); + }, } } fn enter_realm(&self) -> JSAutoRealm { match self { &ImageElementMicrotask::StableStateUpdateImageDataTask { ref elem, .. } | - &ImageElementMicrotask::EnvironmentChangesTask { ref elem, .. } => enter_realm(&**elem), + &ImageElementMicrotask::EnvironmentChangesTask { ref elem, .. } | + &ImageElementMicrotask::DecodeTask { ref elem, .. } => enter_realm(&**elem), } } } @@ -1615,22 +1674,11 @@ impl HTMLImageElementMethods for HTMLImageElement { let promise = Promise::new(&self.global()); // Step 2 - let document = document_from_node(self); - let ready = match self.current_request.borrow().state { - State::Unavailable => false, - State::PartiallyAvailable => false, - State::CompletelyAvailable => true, - State::Broken => false, + let task = ImageElementMicrotask::DecodeTask { + elem: DomRoot::from_ref(self), + promise: promise.clone(), }; - - if document.is_fully_active() && ready && self.current_request.borrow().image.is_some() { - promise.reject_native(&DOMException::new( - &self.global(), - DOMErrorName::EncodingError, - )); - } else { - promise.resolve_native(&()); - } + ScriptThread::await_stable_state(Microtask::ImageElement(task)); // Step 3 promise diff --git a/components/shared/net/image_cache.rs b/components/shared/net/image_cache.rs index 317fd1b66ef..bf72360f725 100644 --- a/components/shared/net/image_cache.rs +++ b/components/shared/net/image_cache.rs @@ -119,6 +119,13 @@ pub trait ImageCache: Sync + Send { use_placeholder: UsePlaceholder, ) -> ImageCacheResult; + fn decode( + &self, + url: ServoUrl, + origin: ImmutableOrigin, + cors_setting: Option, + ) -> Option; + /// Add a listener for the provided pending image id, eventually called by /// ImageCacheStore::complete_load. /// If only metadata is available, Available(ImageOrMetadataAvailable) will