Skip to content

Apply EXIF orientation to decoded images; render image documents in iframes - #829

Open
nicoburns wants to merge 1 commit into
mainfrom
devin/1788306004-image-orientation
Open

nicoburns wants to merge 1 commit into
mainfrom
devin/1788306004-image-orientation

Conversation

@nicoburns

@nicoburns nicoburns commented Sep 1, 2026

Copy link
Copy Markdown
Member

Summary

Two small changes in blitz-dom/src/net.rs that take css/css-images/image-orientation WPT from 14/34 to 21/34 passing.

EXIF orientation (image-orientation: from-image, the initial value). ImageHandler::parse previously used ImageReader::decode(), which discards the decoder's orientation metadata, so JPEGs/PNGs with EXIF rotation/flip rendered un-rotated. Now:

let mut decoder = ImageReader::new(..).with_guessed_format()?.into_decoder()?;
let orientation = decoder.orientation().unwrap_or(Orientation::NoTransforms);
let mut image = DynamicImage::from_decoder(decoder)?;
image.apply_orientation(orientation);

The transform is baked in at decode time (width/height in Resource::Image are post-rotation), so everything downstream (<img>, background-image, border-image, list-style-image, mask-image, content:) picks it up for free.

Image documents in <iframe>. DocumentSrcHandler treated every response as HTML, so an iframe whose src is a JPEG rendered the raw bytes as text. If image::guess_format recognises the bytes, we now synthesise a minimal <img src="{url}"> document instead (the image is then fetched via the normal image path, so it gets EXIF handling too).

Remaining failures (13) — not addressed here

  • 10 need image-orientation: none: background-image, none, none-content-images, *-dynamic2, *-computed-style, none-cross-origin*. Stylo declares image-orientation with engine = "gecko" in properties/longhands.toml, so the property isn't generated for the Servo build and can't be parsed by Blitz at all. Supporting it needs an upstream Stylo change plus keeping the un-oriented pixels around (or applying the orientation as a paint-time transform instead of at decode). The cross-origin variants additionally need multi-origin serving and <canvas>.
  • exif-png.html: EXIF stored in a legacy compressed zTXt "Raw profile type exif" chunk. No browser passes this on wpt.fyi either.
  • background-properties(-border-radius): renders visually identical, but JPEG decode noise between the EXIF file and the pre-rotated reference file gives 406 differing pixels (max diff 2) vs the fuzzy budget of 313/331. Chrome/Edge also fail one or both of these.

Side finding: new URL(img.src) throws "relative URL without a base" in the cross-origin tests — the HTMLImageElement.src getter returns the raw attribute rather than the resolved absolute URL.

Link to Devin session: https://dioxus.staging.devinenterprise.com/sessions/67f3ef53d8b744548190d4a3dfa8f9dc
Open in Devin Desktop: https://dioxus.staging.devinenterprise.com/desktop/session/67f3ef53d8b744548190d4a3dfa8f9dc?variant=devin-insiders
Requested by: @nicoburns

WPT results

11 newly passing, 4 newly failing (net +7).

Full diff (15 changed tests)
+ Fail => Pass css/css-images/image-orientation/image-orientation-background-position.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-default.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-exif-png-2.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-exif-png-3.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-from-image-composited-dynamic1.html
- Pass => Fail css/css-images/image-orientation/image-orientation-from-image-composited-dynamic2.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-from-image-composited.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-from-image-content-images.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-from-image-dynamic1.html
- Pass => Fail css/css-images/image-orientation/image-orientation-from-image-dynamic2.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-from-image-embedded-content.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-from-image.html
- Pass => Fail css/css-images/image-orientation/image-orientation-none-content-images.html
+ Fail => Pass css/css-images/image-orientation/image-orientation-none-image-document.html
- Pass => Fail css/css-images/image-orientation/image-orientation-none.html

Generated by the WPT workflow.

…n iframes

Fixes 7 css/css-images/image-orientation WPT tests (14/34 -> 21/34).
@staging-devin-ai-integration

Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR that start with 'DevinAI' or '@devin'.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment, CI, and merge conflict monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant