aboutsummaryrefslogtreecommitdiffstats
path: root/components/script
diff options
context:
space:
mode:
authorSimon Wülker <simon.wuelker@arcor.de>2025-04-26 21:44:12 +0200
committerGitHub <noreply@github.com>2025-04-26 19:44:12 +0000
commit902d2ad8f40d62ac131d104877df0e9861f90ba4 (patch)
treec4e823a1d53f23197e807acda6133074db71f952 /components/script
parent18d6981d84e42a949cd10bf2c05b89828567be7d (diff)
downloadservo-902d2ad8f40d62ac131d104877df0e9861f90ba4.tar.gz
servo-902d2ad8f40d62ac131d104877df0e9861f90ba4.zip
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>
Diffstat (limited to 'components/script')
-rw-r--r--components/script/dom/htmlcanvaselement.rs30
1 files changed, 19 insertions, 11 deletions
diff --git a/components/script/dom/htmlcanvaselement.rs b/components/script/dom/htmlcanvaselement.rs
index 303c781c8b3..bb27d28cea8 100644
--- a/components/script/dom/htmlcanvaselement.rs
+++ b/components/script/dom/htmlcanvaselement.rs
@@ -407,15 +407,23 @@ impl HTMLCanvasElement {
&self,
image_type: &EncodedImageType,
quality: Option<f64>,
- bytes: &[u8],
+ snapshot: &Snapshot,
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 {
EncodedImageType::Png => {
// FIXME(nox): https://github.com/image-rs/image-png/issues/86
// FIXME(nox): https://github.com/image-rs/image-png/issues/87
PngEncoder::new(encoder)
- .write_image(bytes, self.Width(), self.Height(), ColorType::Rgba8)
+ .write_image(canvas_data, width, height, ColorType::Rgba8)
.unwrap();
},
EncodedImageType::Jpeg => {
@@ -435,14 +443,14 @@ impl HTMLCanvasElement {
};
jpeg_encoder
- .write_image(bytes, self.Width(), self.Height(), ColorType::Rgba8)
+ .write_image(canvas_data, width, height, ColorType::Rgba8)
.unwrap();
},
EncodedImageType::Webp => {
// No quality support because of https://github.com/image-rs/image/issues/1984
WebPEncoder::new_lossless(encoder)
- .write_image(bytes, self.Width(), self.Height(), ColorType::Rgba8)
+ .write_image(canvas_data, width, height, ColorType::Rgba8)
.unwrap();
},
}
@@ -567,7 +575,7 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
self.encode_for_mime_type(
&image_type,
Self::maybe_quality(quality),
- snapshot.data(),
+ &snapshot,
&mut encoder,
);
encoder.into_inner();
@@ -589,8 +597,8 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
return Err(Error::Security);
}
- // Step 2. and 3.
- // If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension
+ // Step 2. Let result be null.
+ // Step 3. If this canvas element's bitmap has pixels (i.e., neither its horizontal dimension
// nor its vertical dimension is zero),
// then set result to a copy of this canvas element's bitmap.
let result = if self.Width() == 0 || self.Height() == 0 {
@@ -627,12 +635,12 @@ impl HTMLCanvasElementMethods<crate::DomTypeHolder> for HTMLCanvasElement {
// type and quality if given.
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());
- // Step 4.2.1 & 4.2.2
- // Set result to a new Blob object, created in the relevant realm of this canvas element
- // Invoke callback with « result » and "report".
+ // Step 4.2.1 Set result to a new Blob object, created in the relevant realm of this canvas element
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());
} else {
let _ = callback.Call__(None, ExceptionHandling::Report, CanGc::note());