Decode HTML Image

Signed-off-by: Bentaimia Haddadi <haddadi.taym@gmail.com>
This commit is contained in:
Bentaimia Haddadi 2024-02-29 18:21:25 +01:00
parent 781fda5b6d
commit 5daf5c55e3
3 changed files with 90 additions and 17 deletions

View file

@ -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<CorsSettings>,
) -> Option<Image> {
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) {

View file

@ -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<Promise>) {
let document = document_from_node(self);
let window = document.window();
let elem = self.upcast::<Element>();
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> = 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,
));
}
}
}
/// <https://html.spec.whatwg.org/multipage/#update-the-image-data>
pub fn update_the_image_data(&self) {
let document = document_from_node(self);
@ -1349,6 +1396,11 @@ pub enum ImageElementMicrotask {
elem: DomRoot<HTMLImageElement>,
generation: u32,
},
DecodeTask {
elem: DomRoot<HTMLImageElement>,
#[ignore_malloc_size_of = "promises are hard"]
promise: Rc<Promise>,
},
}
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

View file

@ -119,6 +119,13 @@ pub trait ImageCache: Sync + Send {
use_placeholder: UsePlaceholder,
) -> ImageCacheResult;
fn decode(
&self,
url: ServoUrl,
origin: ImmutableOrigin,
cors_setting: Option<CorsSettings>,
) -> Option<Image>;
/// Add a listener for the provided pending image id, eventually called by
/// ImageCacheStore::complete_load.
/// If only metadata is available, Available(ImageOrMetadataAvailable) will