Skip to content

Screenshot test for clip under scale+translate (#4907)#4917

Open
shai-almog wants to merge 2 commits into
masterfrom
clip-under-scale-translate-test
Open

Screenshot test for clip under scale+translate (#4907)#4917
shai-almog wants to merge 2 commits into
masterfrom
clip-under-scale-translate-test

Conversation

@shai-almog
Copy link
Copy Markdown
Collaborator

Summary

  • Adds ClipUnderScaleTranslate screenshot test that reproduces the magnifier-style render path from issue glitchy metal drawing #4907 (set a small clip, then g.scale(2,2) + g.translate(-ax,-ay), then a fillRect covering the whole post-transform cell).
  • A navy outline of the expected clip rect anchors the diff; a corner green sentinel after popClip catches broken pop/transform-reset.
  • Uses the standard AbstractGraphicsScreenshotTest 2×2 grid so the form-graphics path and the mutable-image path are captured separately, narrowing the suspect target if only one cell fails.

This is purely a test addition -- no framework code is touched. We're letting CI render the test on each platform to see whether iOS Metal currently clips correctly or leaks outside the rect.

Test plan

  • JavaSE simulator cells render gray cell, navy outline, centred red square, small green corner dot.
  • Android renders the same.
  • iOS legacy renderer renders the same.
  • iOS Metal renderer: check whether red leaks outside the navy outline -- if so, glitchy metal drawing #4907 is reproduced and the failing cell (form-graphics vs mutable-image) localises the bug.

🤖 Generated with Claude Code

Repro for issue #4907 (glitchy metal drawing). The issue reports that a
magnifier-style render path -- set a small clip rect, then apply
g.scale(scale, scale) + g.translate(-ax, -ay) and draw a much larger
surface -- correctly clips on the legacy iOS pipeline / JavaSE / Android
but leaks outside the clip rect under iOS Metal.

The new ClipUnderScaleTranslate test runs the AbstractGraphicsScreenshotTest
2x2 (AA off/on, form-graphics vs mutable-image) and renders the exact
sequence from ddyer0's snippet:

  g.pushClip();
  g.clipRect(centred small rect);
  g.scale(2.0f, 2.0f);
  g.translate(-ax, -ay);
  g.fillRect(<covers entire post-transform cell>);   // should clip to rect
  g.translate(ax, ay);
  g.scale(0.5f, 0.5f);
  g.popClip();

A navy outline of the expected clip rect is drawn before the clipped
fill so the screenshot diff has a stable anchor; a tiny green sentinel
is drawn after popClip so a broken pop/transform-reset is also caught.
On a working pipeline the cell shows a centred red square inside the
navy outline; on the buggy pipeline the red leaks outside (worst case:
the entire cell is red). Splitting the form-graphics path from the
mutable-image path lets the diff narrow the suspect target without
extra instrumentation.

Wired into Cn1ssDeviceRunner after Clip and into the HTML5 skip list to
match the other graphics screenshot tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 11, 2026

JavaScript port screenshot updates

Compared 16 screenshots: 15 matched, 1 missing reference.

  • graphics-clip-under-scale-translate — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/javascript/screenshots/graphics-clip-under-scale-translate.png.

    graphics-clip-under-scale-translate
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as graphics-clip-under-scale-translate.png in workflow artifacts.

…4907)

The previous version drew a solid red fillRect covering the entire
post-transform area, with a navy outline of the expected clip rect.
When the clip is honoured the red square sits exactly on the navy
outline, so a small bleed at the edges is hard to distinguish from
normal antialiasing -- on the JavaSE simulator the result looked
correct but it was hard to tell whether the test would catch a
subtle leak.

Switch to a 5-patch pattern sized in source (pre-scale) coordinates:

  - Central red patch sized 1/scale * clipW by 1/scale * clipH so
    that, under the 2x scale, it exactly fills the clip rect.
  - Four side patches (green N, blue S, orange W, magenta E) placed
    one patch-width / height away from the centre. With the 2x scale
    they end up one full clipW / clipH off-centre, entirely outside
    the clip rect under a correct clip and invisible.

A correct render shows only a red square inside a black clip-rect
outline (drawn last, on top of the fill so its position is stable).
A bleed shows a coloured patch outside the outline, and the colour
identifies which post-transform direction leaked. The clip rect is
now 1/5 of the cell (was 1/3) so there is plenty of gray buffer
around it to make even a thin bleed visible.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 11, 2026

Android screenshot updates

Compared 106 screenshots: 105 matched, 1 missing reference.

  • graphics-clip-under-scale-translate — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/graphics-clip-under-scale-translate.png.

    graphics-clip-under-scale-translate
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as graphics-clip-under-scale-translate.png in workflow artifacts.

Native Android coverage

  • 📊 Line coverage: 11.25% (6213/55246 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 8.94% (30766/344236), branch 3.78% (1237/32726), complexity 4.92% (1544/31377), method 8.65% (1269/14679), class 14.56% (289/1985)
    • Lowest covered classes
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysKt – 0.00% (0/6327 lines covered)
      • kotlin.collections.unsigned.kotlin.collections.unsigned.UArraysKt___UArraysKt – 0.00% (0/2384 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.ClassReader – 0.00% (0/1519 lines covered)
      • kotlin.collections.kotlin.collections.CollectionsKt___CollectionsKt – 0.00% (0/1148 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.MethodWriter – 0.00% (0/923 lines covered)
      • kotlin.sequences.kotlin.sequences.SequencesKt___SequencesKt – 0.00% (0/730 lines covered)
      • kotlin.text.kotlin.text.StringsKt___StringsKt – 0.00% (0/623 lines covered)
      • org.jacoco.agent.rt.internal_b6258fc.asm.org.jacoco.agent.rt.internal_b6258fc.asm.Frame – 0.00% (0/564 lines covered)
      • kotlin.collections.kotlin.collections.ArraysKt___ArraysJvmKt – 0.00% (0/495 lines covered)
      • kotlinx.coroutines.kotlinx.coroutines.JobSupport – 0.00% (0/423 lines covered)

Benchmark Results

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 799.000 ms
Base64 CN1 encode 215.000 ms
Base64 encode ratio (CN1/native) 0.269x (73.1% faster)
Base64 native decode 746.000 ms
Base64 CN1 decode 263.000 ms
Base64 decode ratio (CN1/native) 0.353x (64.7% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 11, 2026

iOS Metal screenshot updates

Compared 106 screenshots: 105 matched, 1 missing reference.

  • graphics-clip-under-scale-translate — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots-metal/graphics-clip-under-scale-translate.png.

    graphics-clip-under-scale-translate
    Preview info: JPEG preview quality 60; JPEG preview quality 60; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-clip-under-scale-translate.png in workflow artifacts.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 344 seconds

Build and Run Timing

Metric Duration
Simulator Boot 86000 ms
Simulator Boot (Run) 1000 ms
App Install 19000 ms
App Launch 10000 ms
Test Execution 289000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 2335.000 ms
Base64 CN1 encode 2266.000 ms
Base64 encode ratio (CN1/native) 0.970x (3.0% faster)
Base64 native decode 1365.000 ms
Base64 CN1 decode 1731.000 ms
Base64 decode ratio (CN1/native) 1.268x (26.8% slower)
Base64 SIMD encode 707.000 ms
Base64 encode ratio (SIMD/native) 0.303x (69.7% faster)
Base64 encode ratio (SIMD/CN1) 0.312x (68.8% faster)
Base64 SIMD decode 680.000 ms
Base64 decode ratio (SIMD/native) 0.498x (50.2% faster)
Base64 decode ratio (SIMD/CN1) 0.393x (60.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 82.000 ms
Image createMask (SIMD on) 9.000 ms
Image createMask ratio (SIMD on/off) 0.110x (89.0% faster)
Image applyMask (SIMD off) 273.000 ms
Image applyMask (SIMD on) 66.000 ms
Image applyMask ratio (SIMD on/off) 0.242x (75.8% faster)
Image modifyAlpha (SIMD off) 147.000 ms
Image modifyAlpha (SIMD on) 77.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.524x (47.6% faster)
Image modifyAlpha removeColor (SIMD off) 233.000 ms
Image modifyAlpha removeColor (SIMD on) 94.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.403x (59.7% faster)
Image PNG encode (SIMD off) 1676.000 ms
Image PNG encode (SIMD on) 4198.000 ms
Image PNG encode ratio (SIMD on/off) 2.505x (150.5% slower)
Image JPEG encode 901.000 ms

@shai-almog
Copy link
Copy Markdown
Collaborator Author

shai-almog commented May 11, 2026

iOS screenshot updates

Compared 106 screenshots: 105 matched, 1 missing reference.

  • graphics-clip-under-scale-translate — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/graphics-clip-under-scale-translate.png.

    graphics-clip-under-scale-translate
    Preview info: JPEG preview quality 50; JPEG preview quality 50; downscaled to 825x1789.
    Full-resolution PNG saved as graphics-clip-under-scale-translate.png in workflow artifacts.

Benchmark Results

  • VM Translation Time: 0 seconds
  • Compilation Time: 269 seconds

Build and Run Timing

Metric Duration
Simulator Boot 86000 ms
Simulator Boot (Run) 1000 ms
App Install 17000 ms
App Launch 8000 ms
Test Execution 316000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 1953.000 ms
Base64 CN1 encode 2058.000 ms
Base64 encode ratio (CN1/native) 1.054x (5.4% slower)
Base64 native decode 1142.000 ms
Base64 CN1 decode 1360.000 ms
Base64 decode ratio (CN1/native) 1.191x (19.1% slower)
Base64 SIMD encode 532.000 ms
Base64 encode ratio (SIMD/native) 0.272x (72.8% faster)
Base64 encode ratio (SIMD/CN1) 0.259x (74.1% faster)
Base64 SIMD decode 616.000 ms
Base64 decode ratio (SIMD/native) 0.539x (46.1% faster)
Base64 decode ratio (SIMD/CN1) 0.453x (54.7% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 92.000 ms
Image createMask (SIMD on) 25.000 ms
Image createMask ratio (SIMD on/off) 0.272x (72.8% faster)
Image applyMask (SIMD off) 181.000 ms
Image applyMask (SIMD on) 103.000 ms
Image applyMask ratio (SIMD on/off) 0.569x (43.1% faster)
Image modifyAlpha (SIMD off) 158.000 ms
Image modifyAlpha (SIMD on) 81.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.513x (48.7% faster)
Image modifyAlpha removeColor (SIMD off) 257.000 ms
Image modifyAlpha removeColor (SIMD on) 117.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.455x (54.5% faster)
Image PNG encode (SIMD off) 1422.000 ms
Image PNG encode (SIMD on) 1645.000 ms
Image PNG encode ratio (SIMD on/off) 1.157x (15.7% slower)
Image JPEG encode 1241.000 ms

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