[GTK] Fix the image size cache never hitting at zoom != 100 - #3512
[GTK] Fix the image size cache never hitting at zoom != 100#3512vogella wants to merge 2 commits into
Conversation
Test Results 211 files + 35 211 suites +35 26m 53s ⏱️ + 1m 52s For more details on these errors, see this check. Results for commit ba401ef. ± Comparison against base commit 3e3b24b. This pull request removes 57 and adds 2 tests. Note that renamed tests count towards both.♻️ This comment has been updated with latest results. |
The internal drawImage that every public overload funnels into read the source dimensions from srcImage.getImageData(), which is getImageData(100). At currentDeviceZoom != 100 that misses the zoom == currentDeviceZoom fast path and loads new ImageData(fileName): a full open and full decode, for SVG a full re-parse and re-rasterize, to obtain two integers the Image already knows. The result was used for nothing else, the drawing itself goes through srcImage.surface. An ImageGcDrawer image paid the same way, by running the drawer callback once per draw. Take the dimensions from the Image, falling back to ImageData for images wrapped around a native handle by Image.gtk_new, which carry none. Those have no provider, so the fallback reads the cairo surface and never a file. Cocoa already takes its dimensions from NSImage.size() and win32 from getBounds(), so this brings GTK in line with both. Opens per draw over 100 draws of one Image at zoom 200, strace on Linux/GTK: 9 arg overload, PNG 1.00 -> 0.00 5 arg overload, PNG 2.00 -> 1.00 The open left on the 5 arg overload is the CachedImageAtSize path of issue 3505. Rendering is unchanged wherever the Image dimensions agree with the decoded ones, verified as identical SHA-256 of the drawn ImageData over both overloads, three files and zoom 100, 150 and 200, and again for an ImageFileNameProvider returning one path at every zoom. Two cases change, both where getBounds() and getImageData() already disagreed. For an asset set that is not exactly proportional, 16 pixels at 100% and 33 at 200%, the width field is round(33/2) = 17 while getImageData(100) gives 16, so at zoom 200 the unscaled draw now paints the last point row and column that were previously clipped. For a provider handing out the same file at every zoom, a 16 pixel file at zoom 200 gives bounds 8 and getImageData 16, so passing getImageData() dimensions as the source rectangle now raises ERROR_INVALID_ARGUMENT where it previously drew. In both cases the new value is the one that agrees with getBounds(). Fixes eclipse-platform#3507
CachedImageAtSize.refresh converted the requested draw size to pixels with DPIUtil.pointToPixel and handed that to isReusable, which compared it against the cached image's width and height. Those are points: the cached image is built with new Image(device, imageData, getDeviceZoom()) and Image.init(ImageData, zoom) divides by the scale factor. At zoom 200 the comparison is scaledWidth/2 == scaledWidth, never true, so the cache never hit and every scaled draw reloaded the image. Remember the requested size in pixels alongside the cached image and compare against that, as the win32 HandleAtSize already does. Opens per draw over 100 draws of one Image at a stable draw size through the 5 argument overload, SVG, strace on Linux/GTK: zoom 100 0.02 -> 0.02 zoom 200 2.00 -> 0.02 Rendering is unchanged, verified as identical SHA-256 of the drawn ImageData over both overloads, three files and zoom 100, 150 and 200. Cocoa has the same comparison but is not affected: its cached image is built with new Image(device, imageData), which passes zoom 100 to init and so keeps the value in pixels. Fixes eclipse-platform#3511
ee4ddac to
ba401ef
Compare
There was a problem hiding this comment.
Pull request overview
Fixes GTK’s scaled-image cache at non-default zoom by using consistent cache-key units.
Changes:
- Tracks requested pixel dimensions and device zoom in
CachedImageAtSize. - Adds a regression test verifying repeated scaled draws reuse the cached SVG.
Review scope: The GC changes belong to stacked PR #3510 and were excluded as requested.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
Image.java (GTK) |
Corrects scaled-image cache matching. |
Test_org_eclipse_swt_graphics_Image.java |
Tests cache reuse at 200% zoom. |
GC.java (GTK) |
Stacked #3510 prerequisite. |
Test_org_eclipse_swt_graphics_GC.java |
Stacked #3510 regression coverage. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Stacked on #3510. This branch contains that commit as well, so review only the second one,
[GTK] Fix the image size cache never hitting at zoom != 100. Draft until #3510 merges, then I will rebase and mark it ready.CachedImageAtSize.refreshconverted the requested draw size to pixels withDPIUtil.pointToPixeland handed that toisReusable, which compared it against the cached image'swidthandheight.Those are points: the cached image is built with
new Image(device, imageData, getDeviceZoom())andImage.init(ImageData, zoom)divides by the scale factor.At zoom 200 the comparison is
scaledWidth/2 == scaledWidth, never true, so the single-entry size cache never hit and every scaled draw reloaded the image.This remembers the requested size in pixels alongside the cached image and compares against that, as the win32
HandleAtSizealready does.Opens per draw over 100 draws of one
Imageat a stable draw size through the 5 argument overload, SVG,strace -f -e trace=openaton Linux/GTK:Zoom 100 is unchanged and zoom 200 drops to the same one-miss-then-hits behaviour.
Rendering is identical, verified as matching SHA-256 of the drawn
ImageDataacross both overloads, three files and zoom 100, 150 and 200.Cocoa has a textually identical
isReusablebut is not affected: its cached image is built withnew Image(device, imageData), which passes zoom 100 toinitand so keeps the value in pixels.The new test needs #3510, since without it the
getImageDatadecode re-reads the deleted file at zoom 200 and the test would fail for an unrelated reason.Fixes #3511