Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
171 commits
Select commit Hold shift + click to select a range
ed0da53
iOS Metal port: Phase 0 scaffolding
shai-almog Apr 23, 2026
c0bfe58
iOS Metal port: fix Phase 0 compile/link under -Dios.metal=true
shai-almog Apr 23, 2026
e566564
iOS Metal port: make setFramebuffer idempotent
shai-almog Apr 23, 2026
2bca0bf
iOS Metal port: Phase 1 infrastructure
shai-almog Apr 23, 2026
d2c1b33
iOS Metal port: port MVP ExecutableOps to Metal
shai-almog Apr 23, 2026
814a2e3
iOS Metal port: update status doc for Phase 0 completion + Phase 1
shai-almog Apr 23, 2026
611a3ef
iOS Metal port: fix header include order; MSL address spaces
shai-almog Apr 23, 2026
e7552ed
iOS Metal port: mark Phase 1 MVP complete; document visual validation
shai-almog Apr 23, 2026
1f01cdc
iOS Metal port: fix CI build for .metal path and ClipRect imports
shai-almog Apr 23, 2026
55e2249
iOS Metal port: Phase 2 coord fixes, persistent render target, more ops
shai-almog Apr 23, 2026
e115665
iOS Metal port: update status for Phase 2 progress
shai-almog Apr 23, 2026
4d8e654
CI: validate Metal rendering backend in scripts-ios workflow
shai-almog Apr 23, 2026
dd4c180
CI: point MetalToolchain download at Xcode 26 explicitly
shai-almog Apr 24, 2026
2f70d65
CI: surface Metal screenshot comparison in the workflow summary
shai-almog Apr 24, 2026
80f8953
CI: give the Metal pipeline its own golden-image directory
shai-almog Apr 24, 2026
b1d996d
CI: fix broken YAML in scripts-ios.yml (Python heredoc ate the block …
shai-almog Apr 24, 2026
e31a539
iOS Metal port: re-enable ClipRect; tear down in-flight encoder on re…
shai-almog Apr 24, 2026
47be76e
iOS Metal port: Phase 2 DrawString (whole-string texture, parity level)
shai-almog Apr 24, 2026
940457e
iOS Metal port: update status for Phase 2 progress (ClipRect + DrawSt…
shai-almog Apr 24, 2026
cee97d7
iOS Metal port: refresh screenshots-metal/ baselines from CI run
shai-almog Apr 24, 2026
368b9c0
iOS Metal port: refresh 3 drifted/corrupt screenshots-metal baselines
shai-almog Apr 24, 2026
4a1f9b0
iOS Metal port: document landscape + fill-round-rect as test-level fl…
shai-almog Apr 24, 2026
5b427c6
iOS Metal port: correct screenshot-validation framing
shai-almog Apr 24, 2026
fad7b1b
iOS Metal port: fix mutable-image Y-flip in DrawImage path
shai-almog Apr 25, 2026
c5cc8e2
iOS Metal port: port DrawGradient (linear + radial)
shai-almog Apr 25, 2026
0d262c3
iOS Metal port: port TileImage
shai-almog Apr 25, 2026
af8c635
iOS Metal port: cache MTLTexture on GLUIImage
shai-almog Apr 25, 2026
5e461a4
iOS Metal port: update status doc with Phase 2 progress
shai-almog Apr 25, 2026
0e13c79
ProcessScreenshots: handle malformed PNGs with a clear error
shai-almog Apr 25, 2026
a22ef25
iOS Metal port: port DrawTextureAlphaMask (path-based shape draws)
shai-almog Apr 25, 2026
f261085
iOS Metal port: status doc updates for end-of-Phase-2 session
shai-almog Apr 25, 2026
f8fc76a
iOS Metal port: pixel-perfect projection (fix separator-line artifact)
shai-almog Apr 25, 2026
961cc32
iOS Metal port: Phase 3 scaffolding for unified mutable-image rendering
shai-almog Apr 25, 2026
ff9f838
iOS Metal port: status doc -- Phase 2 -> complete, Phase 3 in progress
shai-almog Apr 25, 2026
b0e3cc0
iOS Metal port: revert pixel-perfect projection offset (it didn't work)
shai-almog Apr 25, 2026
b1aef94
iOS Metal port: Phase 3 activation -- mutable images render via Metal
shai-almog Apr 25, 2026
8f880a6
iOS Metal port: fix duplicate-variable redefinitions in mutable JNI
shai-almog Apr 25, 2026
8270e4d
Revert "iOS Metal port: fix duplicate-variable redefinitions in mutab…
shai-almog Apr 25, 2026
36e9e29
Revert "iOS Metal port: Phase 3 activation -- mutable images render v…
shai-almog Apr 25, 2026
6482810
iOS Metal port: status doc -- Phase 3 activation attempt + revert
shai-almog Apr 25, 2026
41aa325
iOS Metal port: thread-local rendering state via __thread
shai-almog Apr 25, 2026
bd405c8
Reapply "iOS Metal port: Phase 3 activation -- mutable images render …
shai-almog Apr 25, 2026
ac9acd6
Reapply "iOS Metal port: fix duplicate-variable redefinitions in muta…
shai-almog Apr 25, 2026
a22aca7
iOS Metal port: status doc -- Phase 3 second activation attempt
shai-almog Apr 25, 2026
e40be9e
iOS Metal port: switch thread-local state from __thread to pthread_key
shai-almog Apr 25, 2026
c0375dd
iOS Metal port: rename `I` -- C99 imaginary-unit macro collision
shai-almog Apr 25, 2026
a754802
iOS Metal port: switch Phase 3 mutable rendering to sync-on-finish
shai-almog Apr 25, 2026
cfc5b7f
iOS Metal port: cache device + commandQueue, no UIKit access from EDT
shai-almog Apr 25, 2026
08cfe99
iOS Metal port: diagnostic logging for Phase 3 mutable empty-output bug
shai-almog Apr 25, 2026
7472f44
iOS Metal port: rename DIAG prefix so log predicate captures it
shai-almog Apr 25, 2026
5e48b21
iOS Metal port: Phase 3 v6 -- per-call scope, encoder-on-image
shai-almog Apr 26, 2026
5eb1387
iOS Metal port: more diagnostic logging for Phase 3 v6 empty-mutable
shai-almog Apr 26, 2026
173abf1
iOS Metal port: log JNI mutable entry to find why Enter scope not called
shai-almog Apr 26, 2026
35b5221
iOS Metal port: trace dispatch chain to find missing JNI mutable calls
shai-almog Apr 26, 2026
fbd6a49
iOS Metal port: ifdef setNativeClippingMutableImpl + Shape variant
shai-almog Apr 26, 2026
138e3bd
Don't track .claude/ directory
shai-almog Apr 26, 2026
cc1604a
iOS Metal port: Java-side trace in drawLine to find dispatch break
shai-almog Apr 26, 2026
73b5221
iOS Metal port: broaden Java drawLine/fillRect trace
shai-almog Apr 26, 2026
1dbce58
iOS Metal port: revert Phase 3 mutable rendering -- restore CG path
shai-almog Apr 26, 2026
06608fa
iOS UI tests: fail loudly when fewer than CN1SS_MIN_SCREENSHOTS captured
shai-almog Apr 26, 2026
7fd4b23
iOS Metal port: Phase 3 v2 -- async-dispatched mutable rendering
shai-almog Apr 26, 2026
ef1a34b
iOS Metal port: ExecutableOp.h import CN1ES2compat for CN1_USE_METAL
shai-almog Apr 26, 2026
8412add
iOS Metal port: Phase 3 v2 step 6 -- readback flush + Metal pixel read
shai-almog Apr 26, 2026
8053359
iOS Metal port: status doc -- Phase 3 v2 complete
shai-almog Apr 26, 2026
8b58202
iOS Metal port: respect mutable image fill colour + bump CI timeout
shai-almog Apr 27, 2026
af160fd
iOS Metal port: bump per-test timeout 10s -> 30s
shai-almog Apr 27, 2026
9b2aaf1
iOS Metal port: disable step-6 readback (suspected hang in DrawImage)
shai-almog Apr 27, 2026
cf17636
iOS Metal port: route mutable tileImage through TileImage op
shai-almog Apr 27, 2026
d271385
iOS Metal port: add isMetalRendering ___R_boolean wrapper
shai-almog Apr 27, 2026
c295a3e
iOS Metal port: status doc -- Phase 3 v2 green at 65 screenshots
shai-almog Apr 27, 2026
640b50d
iOS Metal port: instrument fillRect/drawLine for line-artifact diagnosis
shai-almog Apr 27, 2026
7fc89bf
iOS Metal port: refine line-artifact diagnostic filters
shai-almog Apr 27, 2026
686ee1e
iOS Metal port: instrument DrawImage / DrawAlphaMask for line artifact
shai-almog Apr 27, 2026
b8daa95
iOS Metal port: fix 246-247 line artifact at title-bar top edge
shai-almog Apr 27, 2026
bc19e84
iOS Metal port: refresh metal screenshots after line-artifact fix
shai-almog Apr 27, 2026
24e6fa2
iOS Metal port: update status doc -- line artifact fixed
shai-almog Apr 27, 2026
f15baba
iOS Metal port: Phase 4 -- CoreText glyph atlas
shai-almog Apr 28, 2026
5d381f6
iOS Metal port: import CN1ES2compat.h in CN1MetalGlyphAtlas to see CN…
shai-almog Apr 28, 2026
2febc0f
Revert "iOS Metal port: import CN1ES2compat.h in CN1MetalGlyphAtlas t…
shai-almog Apr 28, 2026
3fd1fc0
Revert "iOS Metal port: Phase 4 -- CoreText glyph atlas"
shai-almog Apr 28, 2026
d9dc4c0
iOS Metal port: document Phase 4 attempt + retry plan
shai-almog Apr 28, 2026
c6c01f6
iOS Metal port: Phase 4 -- CoreText glyph atlas (with whole-string fa…
shai-almog Apr 28, 2026
8c13683
iOS Metal port: instrument Phase 4 hang on CI
shai-almog Apr 28, 2026
2189d97
iOS Metal port: bump Phase 4 hang diagnostic limits
shai-almog Apr 28, 2026
02e8531
iOS Metal port: granular DrawString step logging for CI hang chase
shai-almog Apr 28, 2026
330fcdc
iOS Metal port: log every step inside atlasForFont
shai-almog Apr 28, 2026
b9c5add
iOS Metal port: fix Phase 4 atlas-cache lifetime under MRR
shai-almog Apr 29, 2026
3ceaa1a
iOS Metal port: re-add minimal DrawString entry log
shai-almog Apr 29, 2026
a4f064e
iOS Metal port: bump DrawString diag cap to 50
shai-almog Apr 29, 2026
c4156fd
iOS Metal port: log post-atlas DrawString steps + drawQuad
shai-almog Apr 29, 2026
4de8cb0
iOS Metal port: Phase 4 -- fix _slots dictionary autorelease, drop di…
shai-almog Apr 29, 2026
fe5972c
iOS Metal port: refresh goldens after Phase 4 lands
shai-almog Apr 29, 2026
8b8bcac
iOS Metal port: status doc -- Phase 4 complete
shai-almog Apr 29, 2026
e132cde
iOS Metal port: Phase 5 hardening — colorspace, drawable cap, memory …
shai-almog Apr 29, 2026
80c2e4f
iOS Metal port: status doc -- Phase 5 complete
shai-almog Apr 29, 2026
0fa7b31
iOS Metal port: refresh 5 goldens after Phase 5 sRGB colorspace change
shai-almog Apr 29, 2026
4cddd1c
iOS Metal port: route mutable gradient natives through ExecutableOp q…
shai-almog Apr 29, 2026
d2fec54
iOS Metal port: build atlas CTFont from UIFontDescriptor, not fontName
shai-almog Apr 30, 2026
da365a2
iOS Metal port: mutable shape rendering + radial-gradient on mutable …
shai-almog Apr 30, 2026
af662ec
iOS Metal port: Phase 5+ radial-gradient on alpha-mask
shai-almog Apr 30, 2026
6b5456d
iOS Metal port: chunk CN1MetalFillPolygon for >170-triangle polygons
shai-almog Apr 30, 2026
e548d1a
iOS Metal port: plug Metal-resource leaks under MRR
shai-almog Apr 30, 2026
faa0b4b
Revert "iOS Metal port: Phase 5+ radial-gradient on alpha-mask"
shai-almog Apr 30, 2026
494a38b
Revert "iOS Metal port: mutable shape rendering + radial-gradient on …
shai-almog Apr 30, 2026
4fe239f
iOS Metal port: re-enable Phase 3 v2 mutable-image readback
shai-almog Apr 30, 2026
cdf3608
iOS Metal port: route createImageFile through Metal readback
shai-almog Apr 30, 2026
230ef04
Reapply "iOS Metal port: Phase 5+ radial-gradient on alpha-mask"
shai-almog Apr 30, 2026
103f16d
Reapply "iOS Metal port: mutable shape rendering + radial-gradient on…
shai-almog Apr 30, 2026
1a65646
iOS Metal port: pass UIFont directly to CTLine attributes
shai-almog Apr 30, 2026
b114b83
trigger CI re-run for UIFont text fix
shai-almog Apr 30, 2026
0d39d8e
Merge remote-tracking branch 'origin/master' into metal-ios-backend
shai-almog Apr 30, 2026
a5845df
iOS Metal port: temporarily diag-log CN1MetalDrawString font + position
shai-almog Apr 30, 2026
f4cd47a
iOS Metal port: filter DSD diag to decorated-test strings
shai-almog Apr 30, 2026
493c91f
graphics test: re-sync NativeGraphics font with Java current at panel…
shai-almog Apr 30, 2026
764c9f6
Merge remote-tracking branch 'origin/master' into metal-ios-backend
shai-almog May 1, 2026
af853ce
CI: route build-ios-metal through the shared iOS port cache (#4837 fo…
shai-almog May 1, 2026
7358c67
iOS Metal port: pin alpha-mask MTLTexture lifetime to queued op
shai-almog May 1, 2026
a192af5
iOS Metal port: refresh 20 graphics goldens to match GL baseline
shai-almog May 1, 2026
df71d17
hellocodenameone: bump round-rect ready-callback to 3s
shai-almog May 1, 2026
52b64ff
hellocodenameone: bump round-rect ready-callback to 5s
shai-almog May 1, 2026
9065247
Revert round-rect ready-callback overrides
shai-almog May 1, 2026
4482453
hellocodenameone: skip transition for round-rect tests on Metal
shai-almog May 1, 2026
ced1fa5
iOS Metal port: refresh graphics-scale and graphics-affine-scale goldens
shai-almog May 1, 2026
cb9e665
iOS Metal port: refresh perspective/camera goldens (title bar only diff)
shai-almog May 1, 2026
9206110
iOS Metal port: refresh draw-round-rect golden post-transition-skip
shai-almog May 1, 2026
98e67c6
hellocodenameone: also skip outgoing transition for round-rect tests
shai-almog May 1, 2026
8100f51
Revert round-rect transition workaround — debug-only, must not ship
shai-almog May 1, 2026
ff1d22c
Fix slide-and-fade-title transition's title-area accumulation
shai-almog May 1, 2026
3ce6f60
Fix slide-and-fade transition: paint dest form on final frame
shai-almog May 1, 2026
fde9309
iOS Metal port: refresh draw-round-rect golden post-transition-fix
shai-almog May 1, 2026
ee31352
CommonTransitions: replace em-dash with ASCII -- to fix Android build
shai-almog May 1, 2026
d11f7dc
iOS Metal port: premultiply mutable texture clear color
shai-almog May 1, 2026
c60a6b8
trigger CI
shai-almog May 1, 2026
a0737b9
CI: share cn1-built cache key from build-port to dependent jobs
shai-almog May 1, 2026
1677316
iOS Metal port: refresh draw-image-rect golden post premult-alpha fix
shai-almog May 1, 2026
fca82b0
iOS Metal port: plug three MRR leaks at +1-retain boundaries
shai-almog May 2, 2026
c3cc48f
iOS: pin ng.font to Java current at drawString -- not in test
shai-almog May 2, 2026
5c48d15
iOS Metal port: route mutable shape/arc/round-rect through alpha-mask…
shai-almog May 2, 2026
86347f5
iOS Metal port: delete whole-string LRU text cache (Phase 4 mandate)
shai-almog May 2, 2026
1ea2543
iOS Metal port: pure-GPU linear/radial gradient shaders (Phase 1 mand…
shai-almog May 2, 2026
e3c1a4d
iOS Metal port: remove dead CG-rasterise-then-DrawImage paths
shai-almog May 2, 2026
f46ff92
Revert 'dead-code removal' to bisect mutable-rendering regression
shai-almog May 2, 2026
1e2f6a2
iOS Metal port: make metalRendering gate static
shai-almog May 2, 2026
43da8f7
iOS Metal port: snapshot radial paint on alpha-mask op for mutable ta…
shai-almog May 2, 2026
af346f2
iOS Metal port: refresh 7 graphics goldens to match alpha-mask Metal …
shai-almog May 2, 2026
b415338
iOS Metal port: remove dead CG-rasterise-then-DrawImage paths
shai-almog May 2, 2026
58408f6
iOS Metal port: refresh draw-image-rect golden (alpha-mask now active)
shai-almog May 2, 2026
ef2392a
hellocodenameone: add mutable-image readback regression test
shai-almog May 2, 2026
85164b6
iOS Metal port: convert ifdef-return-endif to ifdef-else-endif
shai-almog May 3, 2026
aba3b9a
iOS Metal port: LRU-evict + bump glyph-atlas cache to 64 entries
shai-almog May 3, 2026
fc042d5
iOS Metal port: refresh 40 goldens after glyph-atlas LRU fix
shai-almog May 3, 2026
d857083
iOS Metal port: fix fillArc full-circle pacman; revert broken Switch …
shai-almog May 3, 2026
5fb3f6a
iOS Metal port: fix roundRectPath disconnected sub-paths (Switch pill)
shai-almog May 3, 2026
7533857
iOS Metal port: gausianBlurImage reads back mtlMutableTexture pixels
shai-almog May 3, 2026
be18fcd
iOS Metal port: fix gausianBlurImage compile -- C callback for CGData…
shai-almog May 3, 2026
b45c555
iOS Metal port: drain queued ops before gausianBlurImage readback
shai-almog May 3, 2026
15e1d9f
iOS Metal port: skip zero-length edges in roundRectPath for pills
shai-almog May 3, 2026
49b563a
iOS Metal port: pill path uses single 180-deg arc per side
shai-almog May 3, 2026
9f03c11
iOS Metal port: seed mutable texture from existing UIImage on first draw
shai-almog May 3, 2026
4aa8158
iOS Metal port: revert pill-as-180-arc; my pill arc angles were wrong
shai-almog May 3, 2026
70ecde3
iOS Metal port: seed mutable texture via render pass not blit
shai-almog May 3, 2026
512aae3
iOS Metal port: V-flip seed texcoords; ensurePipelineCache before ren…
shai-almog May 3, 2026
b8db2d7
iOS Metal port: revert mutable texture seeding from UIImage
shai-almog May 3, 2026
015b004
iOS Metal port: refresh 6 goldens after roundRectPath / fillArc fixes
shai-almog May 4, 2026
7f1bd51
iOS Metal port: refresh landscape golden (sub-pixel text diff)
shai-almog May 4, 2026
19d0fa7
iOS Metal port: restore kotlin golden to pre-switch-bug version
shai-almog May 4, 2026
c764fd4
iOS port: collapse metalRendering branches; alpha-mask everywhere
shai-almog May 4, 2026
4eb13d8
iOS Metal port: trim status doc to architectural choices + open issues
shai-almog May 4, 2026
5d45d03
iOS Metal port: restore landscape + SwitchTheme goldens to pre-bug state
shai-almog May 4, 2026
8790b21
iOS Metal port: use GL goldens for SwitchTheme/kotlin/landscape
shai-almog May 4, 2026
905c2b2
iOS Metal port: seed mutable texture from UIImage in same command buffer
shai-almog May 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion .github/workflows/_build-ios-port.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@ name: _Build iOS port (reusable)

on:
workflow_call:
outputs:
cn1_built_cache_key:
description: "Cache key the build job used for the cn1-built artifact bundle. Dependent jobs should reuse this exact key to avoid recomputing the hash and getting a spurious cache miss."
value: ${{ jobs.build.outputs.cn1_built_cache_key }}

jobs:
build:
runs-on: macos-15
timeout-minutes: 60
outputs:
cn1_built_cache_key: ${{ steps.cn1_built_key.outputs.key }}
concurrency:
group: mac-ios-port-${{ github.workflow }}-${{ github.ref_name }}
cancel-in-progress: true
Expand Down Expand Up @@ -105,6 +111,18 @@ jobs:
# Built CN1 + iOS port artifacts. Restored after the m2 cache so it
# overwrites any stale com/codenameone subtree pulled in by the broader
# m2 cache (whose key is keyed on POMs, not source).
- name: Compute cn1-built cache key
id: cn1_built_key
# Single source of truth for the cache key, exposed as a job output
# so dependent jobs (build-ios, build-ios-metal in scripts-ios.yml,
# the iOS-native and packaging workflows) restore the EXACT key this
# job saved against. Computing the same hash again on each consumer
# job has been observed to produce a different value on some runners
# (suspected: the find -type f traversal picks up runner-specific
# filesystem metadata that survives between jobs). Sharing the key
# via an output sidesteps that.
run: echo "key=cn1-built-${{ runner.os }}-${{ steps.src_hash.outputs.hash }}" >> "$GITHUB_OUTPUT"

- name: Cache built CN1 + iOS port artifacts
id: cn1_built
uses: actions/cache@v4
Expand All @@ -113,7 +131,7 @@ jobs:
~/.m2/repository/com/codenameone
Themes
Ports/iOSPort/nativeSources
key: cn1-built-${{ runner.os }}-${{ steps.src_hash.outputs.hash }}
key: ${{ steps.cn1_built_key.outputs.key }}

- name: Setup workspace
if: steps.cn1_built.outputs.cache-hit != 'true'
Expand Down
243 changes: 243 additions & 0 deletions .github/workflows/scripts-ios.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ on:
- 'scripts/hellocodenameone/**'
- 'scripts/ios/tests/**'
- 'scripts/ios/screenshots/**'
- 'scripts/ios/screenshots-metal/**'
- 'scripts/templates/**'
- '!scripts/templates/**/*.md'
- 'CodenameOne/src/**'
Expand Down Expand Up @@ -45,6 +46,7 @@ on:
- 'scripts/hellocodenameone/**'
- 'scripts/ios/tests/**'
- 'scripts/ios/screenshots/**'
- 'scripts/ios/screenshots-metal/**'
- 'scripts/templates/**'
- '!scripts/templates/**/*.md'
- 'CodenameOne/src/**'
Expand Down Expand Up @@ -197,3 +199,244 @@ jobs:
path: artifacts
if-no-files-found: warn
retention-days: 14

build-ios-metal:
# Mirrors build-ios but enables the Metal rendering backend via the
# codename1.arg.ios.metal=true build hint. Keeps the GL path untouched
# so a regression on either path is isolated in its own job. Part of
# the iOS Metal port migration -- see Ports/iOSPort/METAL_PORT_STATUS.md.
#
# continue-on-error while the Metal port is still in progress:
# screenshot comparisons will differ from golden images until DrawString
# is ported and ClipRect is re-enabled (Phase 2 follow-ups tracked in
# METAL_PORT_STATUS.md). The Metal job still runs on every PR that
# touches the paths below so we can watch for new regressions and
# download artifacts for comparison, but a failure here won't block
# the PR. Flip this to false (or remove the line) once the Metal
# variant matches the GL variant's screenshot set.
continue-on-error: true
needs: build-port
permissions:
contents: read
pull-requests: write
issues: write
runs-on: macos-15
timeout-minutes: 45
concurrency:
group: mac-ci-${{ github.workflow }}-metal-${{ github.ref_name }}
cancel-in-progress: true

env:
GITHUB_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}
GH_TOKEN: ${{ secrets.CN1SS_GH_TOKEN }}

steps:
- uses: actions/checkout@v4

- name: Cache CocoaPods and user gems
uses: actions/cache@v4
with:
path: |
~/.gem
~/Library/Caches/CocoaPods
~/.cocoapods/repos
key: ${{ runner.os }}-pods-v1-${{ hashFiles('scripts/setup-workspace.sh') }}
restore-keys: |
${{ runner.os }}-pods-v1-

- name: Ensure CocoaPods tooling
run: |
mkdir -p ~/.codenameone
cp maven/UpdateCodenameOne.jar ~/.codenameone/
set -euo pipefail
if ! command -v ruby >/dev/null; then
echo "ruby not found"; exit 1
fi
GEM_USER_DIR="$(ruby -e 'print Gem.user_dir')"
export PATH="$GEM_USER_DIR/bin:$PATH"
if ! command -v pod >/dev/null 2>&1; then
gem install cocoapods xcodeproj --no-document --user-install
fi
pod --version

- name: Compute setup-workspace hash
id: setup_hash
run: |
set -euo pipefail
echo "hash=$(shasum -a 256 scripts/setup-workspace.sh | awk '{print $1}')" >> "$GITHUB_OUTPUT"

- name: Compute CN1 source hash
id: src_hash
run: |
set -euo pipefail
SRC_HASH=$(find CodenameOne/src Ports/iOSPort vm/JavaAPI vm/ByteCodeTranslator Themes \
-type f \( -name '*.java' -o -name '*.m' -o -name '*.h' -o -name '*.xml' -o -name '*.properties' -o -name '*.css' \) 2>/dev/null \
| sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
POM_HASH=$(find . -name 'pom.xml' -not -path './scripts/*' 2>/dev/null \
| sort | xargs shasum -a 256 | shasum -a 256 | awk '{print $1}')
SCRIPT_HASH=$(shasum -a 256 \
scripts/setup-workspace.sh \
scripts/build-ios-port.sh \
scripts/build-native-themes.sh \
.github/workflows/_build-ios-port.yml \
| shasum -a 256 | awk '{print $1}')
echo "hash=${SRC_HASH:0:16}-${POM_HASH:0:16}-${SCRIPT_HASH:0:16}" >> "$GITHUB_OUTPUT"

- name: Set TMPDIR
run: echo "TMPDIR=${{ runner.temp }}" >> $GITHUB_ENV

- name: Cache codenameone-tools
uses: actions/cache@v4
with:
path: ${{ runner.temp }}/codenameone-tools
key: ${{ runner.os }}-cn1-tools-${{ steps.setup_hash.outputs.hash }}
restore-keys: |
${{ runner.os }}-cn1-tools-

- name: Cache Maven repository
uses: actions/cache@v4
with:
path: ~/.m2/repository
key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
restore-keys: |
${{ runner.os }}-m2-

- name: Restore cn1-binaries cache
uses: actions/cache@v4
with:
path: ../cn1-binaries
key: cn1-binaries-${{ runner.os }}-${{ steps.setup_hash.outputs.hash }}
restore-keys: |
cn1-binaries-${{ runner.os }}-

- name: Restore built CN1 + iOS port artifacts
# build-port (the reusable workflow at .github/workflows/_build-ios-port.yml)
# populates this cache with the iOS port artifact + native themes + cn1
# Use the exact key the build-port job saved against. Recomputing
# the hash on this runner has been observed to produce a different
# value than build-port on the same SHA (suspected: find traversal
# picks up runner-specific filesystem metadata), causing a spurious
# cache miss. Reusing the published key sidesteps that.
uses: actions/cache/restore@v4
with:
path: |
~/.m2/repository/com/codenameone
Themes
Ports/iOSPort/nativeSources
key: ${{ needs.build-port.outputs.cn1_built_cache_key }}
fail-on-cache-miss: true

- name: Install Metal Toolchain
# Xcode 26+ requires the Metal Toolchain component to be downloaded
# explicitly before .metal files can compile. The runner's default
# xcodebuild is often an older Xcode whose -downloadComponent flag
# doesn't exist, so we point DEVELOPER_DIR at Xcode 26 first (same
# selection logic build-ios-app.sh uses). If the component is
# already cached on the runner image, xcodebuild exits quickly
# without re-downloading.
run: |
set -euo pipefail
XCODE_APP="$(ls -d /Applications/Xcode_26*.app 2>/dev/null | sort -V | tail -n 1 || true)"
if [ ! -x "$XCODE_APP/Contents/Developer/usr/bin/xcodebuild" ]; then
echo "Xcode 26 not found under /Applications. Cannot install Metal Toolchain." >&2
exit 1
fi
echo "Using $XCODE_APP"
export DEVELOPER_DIR="$XCODE_APP/Contents/Developer"
"$DEVELOPER_DIR/usr/bin/xcodebuild" -downloadComponent MetalToolchain
timeout-minutes: 10

- name: Enable Metal backend for hellocodenameone
# -Dcodename1.arg.* on the mvnw CLI doesn't flow into the Codename
# One Maven plugin's BuildRequest -- the plugin reads build args
# from the codenameone_settings.properties file on disk. Inject the
# Metal flag there so IPhoneBuilder's useMetal path activates.
run: |
set -euo pipefail
SETTINGS=scripts/hellocodenameone/common/codenameone_settings.properties
if grep -q '^codename1\.arg\.ios\.metal=' "$SETTINGS"; then
sed -i '' 's|^codename1.arg.ios.metal=.*|codename1.arg.ios.metal=true|' "$SETTINGS"
else
# Insert next to the other ios.* keys (after applicationQueriesSchemes).
awk '
/^codename1\.arg\.ios\.applicationQueriesSchemes=/ {
print
print "codename1.arg.ios.metal=true"
next
}
{ print }
' "$SETTINGS" > "$SETTINGS.tmp" && mv "$SETTINGS.tmp" "$SETTINGS"
fi
echo "--- codenameone_settings.properties (ios.* keys after patch) ---"
grep -n 'codename1\.arg\.ios' "$SETTINGS" || true

- name: Build sample iOS app and compile workspace (Metal)
id: build-ios-app
run: ./scripts/build-ios-app.sh -q -DskipTests
timeout-minutes: 30

- name: Run iOS UI screenshot tests (Metal)
env:
ARTIFACTS_DIR: ${{ github.workspace }}/artifacts/ios-ui-tests-metal
# Compare Metal output against the Metal-specific golden set.
# See scripts/ios/screenshots-metal/README.md for the rationale:
# the Metal backend will not be pixel-identical to the GL
# baselines (especially once CoreText glyph rendering lands).
SCREENSHOT_REF_DIR: ${{ github.workspace }}/scripts/ios/screenshots-metal
run: |
set -euo pipefail
mkdir -p "${ARTIFACTS_DIR}"

echo "workspace='${{ steps.build-ios-app.outputs.workspace }}'"
echo "scheme='${{ steps.build-ios-app.outputs.scheme }}'"
echo "reference dir='${SCREENSHOT_REF_DIR}'"

./scripts/run-ios-ui-tests.sh \
"${{ steps.build-ios-app.outputs.workspace }}" \
"" \
"${{ steps.build-ios-app.outputs.scheme }}"
timeout-minutes: 30

- name: Publish Metal screenshot summary
# Surfaces run-ios-ui-tests.sh's comparison result in the job's
# GitHub Actions summary page so the Metal port status is visible
# at a glance without digging into the artifact zip. Always runs
# so a failed or cancelled tests step still reports whatever got
# captured. The Python helper lives in scripts/ci/ because
# embedding Python heredocs inside a YAML "run: |" block is
# fragile -- unindented Python breaks the block scalar.
if: always()
env:
COMPARE_JSON: ${{ github.workspace }}/artifacts/ios-ui-tests-metal/screenshot-compare.json
COMMENT_MD: ${{ github.workspace }}/artifacts/ios-ui-tests-metal/screenshot-comment.md
run: |
set -eu
{
echo "## iOS Metal screenshot comparison"
echo
echo "Ran against \`scripts/hellocodenameone\` on the iOS simulator with \`codename1.arg.ios.metal=true\`."
echo "Golden images: \`scripts/ios/screenshots-metal/\` (Metal-specific baseline; see the README there for why it is separate from the GL set)."
echo
if [ -s "$COMPARE_JSON" ]; then
python3 scripts/ci/metal-screenshot-summary.py --markdown "$COMPARE_JSON"
elif [ -s "$COMMENT_MD" ]; then
cat "$COMMENT_MD"
else
echo "_No screenshot comparison artifact was produced. See the upload step output for details._"
fi
} >> "$GITHUB_STEP_SUMMARY"
if [ -s "$COMPARE_JSON" ]; then
NOTICE="$(python3 scripts/ci/metal-screenshot-summary.py --headline "$COMPARE_JSON" || true)"
if [ -n "$NOTICE" ]; then
echo "::notice title=Metal screenshot comparison::${NOTICE}"
fi
fi

- name: Upload iOS Metal artifacts
if: always()
uses: actions/upload-artifact@v4
with:
name: ios-ui-tests-metal
path: artifacts
if-no-files-found: warn
retention-days: 14
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,4 @@ dependency-reduced-pom.xml
/.playwright-cli
package-lock.json
package.json
.claude/
19 changes: 19 additions & 0 deletions CodenameOne/src/com/codename1/ui/animations/CommonTransitions.java
Original file line number Diff line number Diff line change
Expand Up @@ -862,6 +862,25 @@ public void paint(Graphics g) {
paintInterformContainers(g);
return;
case TYPE_SLIDE_AND_FADE: {
// Final transition frame: instead of repeating the cross-
// fade (which intentionally leaves both source + dest
// titles visible at varying alpha), paint the destination
// form fully. The form's normal paint clears the title
// area properly, which matters on persistent-backing
// renderers (iOS Metal MTLLoadActionLoad) that faithfully
// preserve every previous-frame pixel -- without this
// cleanup, the cross-fade's accumulated alpha-blended
// title pixels remain in the screenTexture and the next
// captured frame shows two titles overlapping. iOS GL ES2
// happens to mask this because CAEAGLLayer.retainBacking
// is permissively lossy about partial-alpha pixels.
if (firstFinished) {
Form finalForm = (Form) getDestination();
if (finalForm != null) {
paint(g, finalForm, 0, 0, true);
}
return;
}

Form sourceForm = (Form) getSource();
Form destForm = (Form) getDestination();
Expand Down
Loading
Loading