mirror of
https://github.com/servo/servo.git
synced 2025-07-19 05:13:55 +01:00
htmlimageelement: Reject decode promises on the current request mutation (#37828)
Follow the HTML specification and reject the pending image decode promises on any current request mutation. https://html.spec.whatwg.org/multipage/#updating-the-image-data (step 18) https://html.spec.whatwg.org/multipage/#dom-img-decode (step 3) Fulfill and reject image decode promises by queueing a global tasks on the DOM manipulation task source. Testing: Improvements in the following tests - html/semantics/embedded-content/the-img-element/decode/* Signed-off-by: Andrei Volykhin <andrei.volykhin@gmail.com>
This commit is contained in:
parent
45fb0bac82
commit
4cbadde144
5 changed files with 58 additions and 48 deletions
|
@ -97,6 +97,7 @@ pub(crate) fn throw_dom_exception(
|
||||||
Error::NotReadable => DOMErrorName::NotReadableError,
|
Error::NotReadable => DOMErrorName::NotReadableError,
|
||||||
Error::Operation => DOMErrorName::OperationError,
|
Error::Operation => DOMErrorName::OperationError,
|
||||||
Error::NotAllowed => DOMErrorName::NotAllowedError,
|
Error::NotAllowed => DOMErrorName::NotAllowedError,
|
||||||
|
Error::Encoding => DOMErrorName::EncodingError,
|
||||||
Error::Type(message) => unsafe {
|
Error::Type(message) => unsafe {
|
||||||
assert!(!JS_IsExceptionPending(*cx));
|
assert!(!JS_IsExceptionPending(*cx));
|
||||||
throw_type_error(*cx, &message);
|
throw_type_error(*cx, &message);
|
||||||
|
|
|
@ -43,8 +43,6 @@ use style::values::specified::source_size_list::SourceSizeList;
|
||||||
use style_traits::ParsingMode;
|
use style_traits::ParsingMode;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
use super::domexception::DOMErrorName;
|
|
||||||
use super::types::DOMException;
|
|
||||||
use crate::document_loader::{LoadBlocker, LoadType};
|
use crate::document_loader::{LoadBlocker, LoadType};
|
||||||
use crate::dom::activation::Activatable;
|
use crate::dom::activation::Activatable;
|
||||||
use crate::dom::attr::Attr;
|
use crate::dom::attr::Attr;
|
||||||
|
@ -57,7 +55,7 @@ use crate::dom::bindings::codegen::Bindings::NodeBinding::Node_Binding::NodeMeth
|
||||||
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
|
||||||
use crate::dom::bindings::error::{Error, Fallible};
|
use crate::dom::bindings::error::{Error, Fallible};
|
||||||
use crate::dom::bindings::inheritance::Castable;
|
use crate::dom::bindings::inheritance::Castable;
|
||||||
use crate::dom::bindings::refcounted::Trusted;
|
use crate::dom::bindings::refcounted::{Trusted, TrustedPromise};
|
||||||
use crate::dom::bindings::reflector::DomGlobal;
|
use crate::dom::bindings::reflector::DomGlobal;
|
||||||
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
use crate::dom::bindings::root::{DomRoot, LayoutDom, MutNullableDom};
|
||||||
use crate::dom::bindings::str::{DOMString, USVString};
|
use crate::dom::bindings::str::{DOMString, USVString};
|
||||||
|
@ -486,7 +484,7 @@ impl HTMLImageElement {
|
||||||
LoadBlocker::terminate(&self.current_request.borrow().blocker, can_gc);
|
LoadBlocker::terminate(&self.current_request.borrow().blocker, can_gc);
|
||||||
// Mark the node dirty
|
// Mark the node dirty
|
||||||
self.upcast::<Node>().dirty(NodeDamage::Other);
|
self.upcast::<Node>().dirty(NodeDamage::Other);
|
||||||
self.resolve_image_decode_promises(can_gc);
|
self.resolve_image_decode_promises();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Step 24 of <https://html.spec.whatwg.org/multipage/#update-the-image-data>
|
/// Step 24 of <https://html.spec.whatwg.org/multipage/#update-the-image-data>
|
||||||
|
@ -597,9 +595,9 @@ impl HTMLImageElement {
|
||||||
request.metadata = None;
|
request.metadata = None;
|
||||||
|
|
||||||
if matches!(state, State::Broken) {
|
if matches!(state, State::Broken) {
|
||||||
self.reject_image_decode_promises(can_gc);
|
self.reject_image_decode_promises();
|
||||||
} else if matches!(state, State::CompletelyAvailable) {
|
} else if matches!(state, State::CompletelyAvailable) {
|
||||||
self.resolve_image_decode_promises(can_gc);
|
self.resolve_image_decode_promises();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -894,6 +892,7 @@ impl HTMLImageElement {
|
||||||
// Step 17
|
// Step 17
|
||||||
current_request.current_pixel_density = Some(selected_pixel_density);
|
current_request.current_pixel_density = Some(selected_pixel_density);
|
||||||
self.init_image_request(&mut current_request, url, src, can_gc);
|
self.init_image_request(&mut current_request, url, src, can_gc);
|
||||||
|
self.reject_image_decode_promises();
|
||||||
},
|
},
|
||||||
(_, _) => {
|
(_, _) => {
|
||||||
// step 17
|
// step 17
|
||||||
|
@ -1186,10 +1185,7 @@ impl HTMLImageElement {
|
||||||
if !document.is_fully_active() ||
|
if !document.is_fully_active() ||
|
||||||
matches!(self.current_request.borrow().state, State::Broken)
|
matches!(self.current_request.borrow().state, State::Broken)
|
||||||
{
|
{
|
||||||
promise.reject_native(
|
promise.reject_error(Error::Encoding, can_gc);
|
||||||
&DOMException::new(&document.global(), DOMErrorName::EncodingError, can_gc),
|
|
||||||
can_gc,
|
|
||||||
);
|
|
||||||
} else if matches!(
|
} else if matches!(
|
||||||
self.current_request.borrow().state,
|
self.current_request.borrow().state,
|
||||||
State::CompletelyAvailable
|
State::CompletelyAvailable
|
||||||
|
@ -1203,22 +1199,59 @@ impl HTMLImageElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_image_decode_promises(&self, can_gc: CanGc) {
|
/// <https://html.spec.whatwg.org/multipage/#dom-img-decode>
|
||||||
for promise in self.image_decode_promises.borrow().iter() {
|
fn resolve_image_decode_promises(&self) {
|
||||||
promise.resolve_native(&(), can_gc);
|
if self.image_decode_promises.borrow().is_empty() {
|
||||||
}
|
return;
|
||||||
self.image_decode_promises.borrow_mut().clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reject_image_decode_promises(&self, can_gc: CanGc) {
|
// Step 3. If the decoding process completes successfully, then queue a
|
||||||
let document = self.owner_document();
|
// global task on the DOM manipulation task source with global to
|
||||||
for promise in self.image_decode_promises.borrow().iter() {
|
// resolve promise with undefined.
|
||||||
promise.reject_native(
|
let trusted_image_decode_promises: Vec<TrustedPromise> = self
|
||||||
&DOMException::new(&document.global(), DOMErrorName::EncodingError, can_gc),
|
.image_decode_promises
|
||||||
can_gc,
|
.borrow()
|
||||||
);
|
.iter()
|
||||||
}
|
.map(|promise| TrustedPromise::new(promise.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
self.image_decode_promises.borrow_mut().clear();
|
self.image_decode_promises.borrow_mut().clear();
|
||||||
|
|
||||||
|
self.owner_global()
|
||||||
|
.task_manager()
|
||||||
|
.dom_manipulation_task_source()
|
||||||
|
.queue(task!(fulfill_image_decode_promises: move || {
|
||||||
|
for trusted_promise in trusted_image_decode_promises {
|
||||||
|
trusted_promise.root().resolve_native(&(), CanGc::note());
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <https://html.spec.whatwg.org/multipage/#dom-img-decode>
|
||||||
|
fn reject_image_decode_promises(&self) {
|
||||||
|
if self.image_decode_promises.borrow().is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step 3. Queue a global task on the DOM manipulation task source with
|
||||||
|
// global to reject promise with an "EncodingError" DOMException.
|
||||||
|
let trusted_image_decode_promises: Vec<TrustedPromise> = self
|
||||||
|
.image_decode_promises
|
||||||
|
.borrow()
|
||||||
|
.iter()
|
||||||
|
.map(|promise| TrustedPromise::new(promise.clone()))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
self.image_decode_promises.borrow_mut().clear();
|
||||||
|
|
||||||
|
self.owner_global()
|
||||||
|
.task_manager()
|
||||||
|
.dom_manipulation_task_source()
|
||||||
|
.queue(task!(reject_image_decode_promises: move || {
|
||||||
|
for trusted_promise in trusted_image_decode_promises {
|
||||||
|
trusted_promise.root().reject_error(Error::Encoding, CanGc::note());
|
||||||
|
}
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Step 15 for <https://html.spec.whatwg.org/multipage/#img-environment-changes>
|
/// Step 15 for <https://html.spec.whatwg.org/multipage/#img-environment-changes>
|
||||||
|
|
|
@ -9,6 +9,7 @@ use crate::codegen::PrototypeList::proto_id_to_name;
|
||||||
use crate::script_runtime::JSContext as SafeJSContext;
|
use crate::script_runtime::JSContext as SafeJSContext;
|
||||||
|
|
||||||
/// DOM exceptions that can be thrown by a native DOM method.
|
/// DOM exceptions that can be thrown by a native DOM method.
|
||||||
|
/// <https://webidl.spec.whatwg.org/#dfn-error-names-table>
|
||||||
#[derive(Clone, Debug, MallocSizeOf)]
|
#[derive(Clone, Debug, MallocSizeOf)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// IndexSizeError DOMException
|
/// IndexSizeError DOMException
|
||||||
|
@ -67,6 +68,8 @@ pub enum Error {
|
||||||
Operation,
|
Operation,
|
||||||
/// NotAllowedError DOMException
|
/// NotAllowedError DOMException
|
||||||
NotAllowed,
|
NotAllowed,
|
||||||
|
/// EncodingError DOMException
|
||||||
|
Encoding,
|
||||||
|
|
||||||
/// TypeError JavaScript Error
|
/// TypeError JavaScript Error
|
||||||
Type(String),
|
Type(String),
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
[image-decode-path-changes.html]
|
|
||||||
[HTMLImageElement.prototype.decode(), src/srcset mutation tests. src changes fail decode; following good png decode succeeds.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), src/srcset mutation tests. src changes fail decode; following good svg decode succeeds.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), src/srcset mutation tests. srcset changes fail decode; following good decode succeeds.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), src/srcset mutation tests. src changes fail decode.]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), src/srcset mutation tests. srcset changes fail decode.]
|
|
||||||
expected: FAIL
|
|
|
@ -1,15 +1,3 @@
|
||||||
[image-decode-with-quick-attach.html]
|
[image-decode-with-quick-attach.html]
|
||||||
[HTMLImageElement.prototype.decode(), attach to DOM before promise resolves.: src in empty picture not cached]
|
[HTMLImageElement.prototype.decode(), attach to DOM before promise resolves.: src in empty picture cached]
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), attach to DOM before promise resolves.: srcset in empty picture]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), attach to DOM before promise resolves.: src in picture with source not cached]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), attach to DOM before promise resolves.: src in picture with source cached]
|
|
||||||
expected: FAIL
|
|
||||||
|
|
||||||
[HTMLImageElement.prototype.decode(), attach to DOM before promise resolves.: srcset in picture with source]
|
|
||||||
expected: FAIL
|
expected: FAIL
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue