Auto merge of #25675 - pylbrecht:draw.image, r=jdm

Add usability checks to CanvasRenderingContext2D.drawImage()

<!-- Please describe your changes on the following line: -->
These changes add the usability checks performed on an image to be drawn to the canvas.

References:
- https://html.spec.whatwg.org/multipage/canvas.html#drawing-images
- https://html.spec.whatwg.org/multipage/canvas.html#check-the-usability-of-the-image-argument

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and repla(e `___` with appropriate data: -->
- [x] `./mach build -d` does not report any errors
- [x] `./mach test-tidy` does not report any errors
- [x] These changes fix part of #25331

<!-- Either: -->
- [x] There are tests for these changes

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
bors-servo 2020-02-10 22:59:37 -05:00 committed by GitHub
commit 8e65787737
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 43 additions and 47 deletions

View file

@ -382,12 +382,30 @@ impl CanvasState {
) -> ErrorResult { ) -> ErrorResult {
let result = match image { let result = match image {
CanvasImageSource::HTMLCanvasElement(ref canvas) => { CanvasImageSource::HTMLCanvasElement(ref canvas) => {
// https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
if !canvas.is_valid() {
return Err(Error::InvalidState);
}
self.draw_html_canvas_element(&canvas, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh) self.draw_html_canvas_element(&canvas, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh)
}, },
CanvasImageSource::OffscreenCanvas(ref canvas) => { CanvasImageSource::OffscreenCanvas(ref canvas) => {
// https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
if !canvas.is_valid() {
return Err(Error::InvalidState);
}
self.draw_offscreen_canvas(&canvas, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh) self.draw_offscreen_canvas(&canvas, htmlcanvas, sx, sy, sw, sh, dx, dy, dw, dh)
}, },
CanvasImageSource::HTMLImageElement(ref image) => { CanvasImageSource::HTMLImageElement(ref image) => {
// https://html.spec.whatwg.org/multipage/#drawing-images
// 2. Let usability be the result of checking the usability of image.
// 3. If usability is bad, then return (without drawing anything).
if !image.is_usable()? {
return Ok(());
}
// TODO(pylbrecht): is it possible for image.get_url() to return None after the usability check?
// https://html.spec.whatwg.org/multipage/#img-error // https://html.spec.whatwg.org/multipage/#img-error
// If the image argument is an HTMLImageElement object that is in the broken state, // If the image argument is an HTMLImageElement object that is in the broken state,
// then throw an InvalidStateError exception // then throw an InvalidStateError exception

View file

@ -13,7 +13,7 @@ use crate::dom::bindings::codegen::Bindings::HTMLImageElementBinding::HTMLImageE
use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods; use crate::dom::bindings::codegen::Bindings::MouseEventBinding::MouseEventMethods;
use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods; use crate::dom::bindings::codegen::Bindings::NodeBinding::NodeBinding::NodeMethods;
use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods; use crate::dom::bindings::codegen::Bindings::WindowBinding::WindowMethods;
use crate::dom::bindings::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;
use crate::dom::bindings::reflector::DomObject; use crate::dom::bindings::reflector::DomObject;
@ -164,6 +164,26 @@ impl HTMLImageElement {
pub fn get_url(&self) -> Option<ServoUrl> { pub fn get_url(&self) -> Option<ServoUrl> {
self.current_request.borrow().parsed_url.clone() self.current_request.borrow().parsed_url.clone()
} }
// https://html.spec.whatwg.org/multipage/#check-the-usability-of-the-image-argument
pub fn is_usable(&self) -> Fallible<bool> {
// If image has an intrinsic width or intrinsic height (or both) equal to zero, then return bad.
match &self.current_request.borrow().image {
Some(image) => {
if image.width == 0 || image.height == 0 {
return Ok(false);
}
},
None => return Ok(false),
}
match self.current_request.borrow().state {
// If image's current request's state is broken, then throw an "InvalidStateError" DOMException.
State::Broken => Err(Error::InvalidState),
State::CompletelyAvailable => Ok(true),
// If image is not fully decodable, then return bad.
State::PartiallyAvailable | State::Unavailable => Ok(false),
}
}
} }
/// The context required for asynchronously loading an external image. /// The context required for asynchronously loading an external image.

View file

@ -138,6 +138,10 @@ impl OffscreenCanvas {
)); ));
Some(context) Some(context)
} }
pub fn is_valid(&self) -> bool {
self.Width() != 0 && self.Height() != 0
}
} }
impl OffscreenCanvasMethods for OffscreenCanvas { impl OffscreenCanvasMethods for OffscreenCanvas {

View file

@ -1,5 +0,0 @@
[2d.drawImage.broken.html]
type: testharness
[Canvas test: 2d.drawImage.broken]
expected: FAIL

View file

@ -1,5 +0,0 @@
[2d.drawImage.incomplete.emptysrc.html]
type: testharness
[Canvas test: 2d.drawImage.incomplete.emptysrc]
expected: FAIL

View file

@ -1,5 +0,0 @@
[2d.drawImage.incomplete.immediate.html]
type: testharness
[Canvas test: 2d.drawImage.incomplete.immediate]
expected: FAIL

View file

@ -1,5 +0,0 @@
[2d.drawImage.incomplete.nosrc.html]
type: testharness
[Canvas test: 2d.drawImage.incomplete.nosrc]
expected: FAIL

View file

@ -1,5 +0,0 @@
[2d.drawImage.incomplete.reload.html]
type: testharness
[Canvas test: 2d.drawImage.incomplete.reload]
expected: FAIL

View file

@ -1,5 +0,0 @@
[2d.drawImage.incomplete.removedsrc.html]
type: testharness
[Canvas test: 2d.drawImage.incomplete.removedsrc]
expected: FAIL

View file

@ -1,5 +0,0 @@
[2d.drawImage.zerocanvas.html]
type: testharness
[Canvas test: 2d.drawImage.zerocanvas]
expected: FAIL

View file

@ -1,8 +1,5 @@
[drawimage_html_image.html] [drawimage_html_image.html]
type: testharness type: testharness
[Draw 100x100 image to 100x100 canvas at 0,0.]
expected: FAIL
[Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 70,99 should be light purple.] [Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 70,99 should be light purple.]
expected: FAIL expected: FAIL

View file

@ -1,4 +0,0 @@
[2d.drawImage.zerocanvas.html]
[OffscreenCanvas test: 2d.drawImage.zerocanvas]
expected: FAIL

View file

@ -1,4 +0,0 @@
[2d.drawImage.zerocanvas.worker.html]
[2d]
expected: FAIL