mirror of
https://github.com/servo/servo.git
synced 2025-07-24 15:50:21 +01:00
Use snapshot size instead of canvas size when converting canvas to blob (#36705)
The blob data is encoded asynchronously, therefore the canvas size may have changed since it's data was saved to a snapshot. Using the canvas size confuses the encoder, because the provided data does not match the expected size anymore. Testing: This change includes a new web platform test Fixes https://github.com/servo/servo/issues/36702 --------- Signed-off-by: Simon Wülker <simon.wuelker@arcor.de>
This commit is contained in:
parent
18d6981d84
commit
902d2ad8f4
3 changed files with 36 additions and 11 deletions
|
@ -407,15 +407,23 @@ impl HTMLCanvasElement {
|
||||||
&self,
|
&self,
|
||||||
image_type: &EncodedImageType,
|
image_type: &EncodedImageType,
|
||||||
quality: Option<f64>,
|
quality: Option<f64>,
|
||||||
bytes: &[u8],
|
snapshot: &Snapshot,
|
||||||
encoder: &mut W,
|
encoder: &mut W,
|
||||||
) {
|
) {
|
||||||
|
// We can't use self.Width() or self.Height() here, since the size of the canvas
|
||||||
|
// may have changed since the snapshot was created. Truncating the dimensions to a
|
||||||
|
// u32 can't panic, since the data comes from a canvas which is always smaller than
|
||||||
|
// u32::MAX.
|
||||||
|
let canvas_data = snapshot.data();
|
||||||
|
let width = snapshot.size().width as u32;
|
||||||
|
let height = snapshot.size().height as u32;
|
||||||
|
|
||||||
match image_type {
|
match image_type {
|
||||||
EncodedImageType::Png => {
|
EncodedImageType::Png => {
|
||||||
// FIXME(nox): https://github.com/image-rs/image-png/issues/86
|
// FIXME(nox): https://github.com/image-rs/image-png/issues/86
|
||||||
// FIXME(nox): https://github.com/image-rs/image-png/issues/87
|
// FIXME(nox): https://github.com/image-rs/image-png/issues/87
|
||||||
PngEncoder::new(encoder)
|
PngEncoder::new(encoder)
|
||||||
.write_image(bytes, self.Width(), self.Height(), ColorType::Rgba8)
|
.write_image(canvas_data, width, height, ColorType::Rgba8)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
EncodedImageType::Jpeg => {
|
EncodedImageType::Jpeg => {
|
||||||
|
@ -435,14 +443,14 @@ impl HTMLCanvasElement {
|
||||||
};
|
};
|
||||||
|
|
||||||
jpeg_encoder
|
jpeg_encoder
|
||||||
.write_image(bytes, self.Width(), self.Height(), ColorType::Rgba8)
|
.write_image(canvas_data, width, height, ColorType::Rgba8)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
|
|
||||||
EncodedImageType::Webp => {
|
EncodedImageType::Webp => {
|
||||||
// No quality support because of https://github.com/image-rs/image/issues/1984
|
// No quality support because of https://github.com/image-rs/image/issues/1984
|
||||||
WebPEncoder::new_lossless(encoder)
|
WebPEncoder::new_lossless(encoder)
|
||||||
.write_image(bytes, self.Width(), self.Height(), ColorType::Rgba8)
|
.write_image(canvas_data, width, height, ColorType::Rgba8)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -567,7 +575,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
|
||||||
self.encode_for_mime_type(
|
self.encode_for_mime_type(
|
||||||
&image_type,
|
&image_type,
|
||||||
Self::maybe_quality(quality),
|
Self::maybe_quality(quality),
|
||||||
snapshot.data(),
|
&snapshot,
|
||||||
&mut encoder,
|
&mut encoder,
|
||||||
);
|
);
|
||||||
encoder.into_inner();
|
encoder.into_inner();
|
||||||
|
@ -589,8 +597,8 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
|
||||||
return Err(Error::Security);
|
return Err(Error::Security);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 2. and 3.
|
// Step 2. Let result be null.
|
||||||
// If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension
|
// Step 3. If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension
|
||||||
// nor its vertical dimension is zero),
|
// nor its vertical dimension is zero),
|
||||||
// then set result to a copy of this canvas element's bitmap.
|
// then set result to a copy of this canvas element's bitmap.
|
||||||
let result = if self.Width() == 0 || self.Height() == 0 {
|
let result = if self.Width() == 0 || self.Height() == 0 {
|
||||||
|
@ -627,12 +635,12 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
|
||||||
// type and quality if given.
|
// type and quality if given.
|
||||||
let mut encoded: Vec<u8> = vec![];
|
let mut encoded: Vec<u8> = vec![];
|
||||||
|
|
||||||
this.encode_for_mime_type(&image_type, quality, snapshot.data(), &mut encoded);
|
this.encode_for_mime_type(&image_type, quality, &snapshot, &mut encoded);
|
||||||
let blob_impl = BlobImpl::new_from_bytes(encoded, image_type.as_mime_type());
|
let blob_impl = BlobImpl::new_from_bytes(encoded, image_type.as_mime_type());
|
||||||
// Step 4.2.1 & 4.2.2
|
// Step 4.2.1 Set result to a new Blob object, created in the relevant realm of this canvas element
|
||||||
// Set result to a new Blob object, created in the relevant realm of this canvas element
|
|
||||||
// Invoke callback with « result » and "report".
|
|
||||||
let blob = Blob::new(&this.global(), blob_impl, CanGc::note());
|
let blob = Blob::new(&this.global(), blob_impl, CanGc::note());
|
||||||
|
|
||||||
|
// Step 4.2.2 Invoke callback with « result » and "report".
|
||||||
let _ = callback.Call__(Some(&blob), ExceptionHandling::Report, CanGc::note());
|
let _ = callback.Call__(Some(&blob), ExceptionHandling::Report, CanGc::note());
|
||||||
} else {
|
} else {
|
||||||
let _ = callback.Call__(None, ExceptionHandling::Report, CanGc::note());
|
let _ = callback.Call__(None, ExceptionHandling::Report, CanGc::note());
|
||||||
|
|
9
tests/wpt/mozilla/meta/MANIFEST.json
vendored
9
tests/wpt/mozilla/meta/MANIFEST.json
vendored
|
@ -9,6 +9,15 @@
|
||||||
{}
|
{}
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
"canvas": {
|
||||||
|
"toblob-then-change-size-crash.html": [
|
||||||
|
"355474b4832dde985a73baad925702bbb0cbc73f",
|
||||||
|
[
|
||||||
|
null,
|
||||||
|
{}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
"datatransferitem-crash.html": [
|
"datatransferitem-crash.html": [
|
||||||
"d11355ab38c1e99e0ba3e10d7dfed18bf26af60b",
|
"d11355ab38c1e99e0ba3e10d7dfed18bf26af60b",
|
||||||
[
|
[
|
||||||
|
|
8
tests/wpt/mozilla/tests/mozilla/canvas/toblob-then-change-size-crash.html
vendored
Normal file
8
tests/wpt/mozilla/tests/mozilla/canvas/toblob-then-change-size-crash.html
vendored
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<!-- https://github.com/servo/servo/issues/36702 -->
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<script>
|
||||||
|
canvas.toBlob(() => {});
|
||||||
|
canvas.width = 0;
|
||||||
|
</script>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue