Skip to content

JavaSE: upstream JCEF (fixes maps #5290) + bundled-ffmpeg default media#5294

Draft
shai-almog wants to merge 7 commits into
masterfrom
jcef-upstream-ffmpeg
Draft

JavaSE: upstream JCEF (fixes maps #5290) + bundled-ffmpeg default media#5294
shai-almog wants to merge 7 commits into
masterfrom
jcef-upstream-ffmpeg

Conversation

@shai-almog

Copy link
Copy Markdown
Collaborator

What

Updates the JavaSE simulator's embedded browser from the home-built Chromium 84 JCEF to upstream prebuilt JCEF (me.friwi, currently pinned to Chromium 95), and replaces the simulator's media engine accordingly.

Fixes #5290 — the simulator's Chromium 84 lacks Element.replaceChildren (added in Chromium 86), which breaks the current Google Maps JS (markers fail with TypeError: this.replaceChildren is not a function). Any Chromium ≥ 86 resolves it.

Supersedes #4630 (closed). This is a fresh branch off current master that reuses the salvageable parts of that PR and changes direction on media.

Why the media rework

In the simulator the CN1 Media API plays through CEFJavaCEFSEPort.CodenameOneMediaPlayer loads an HTML <video>/<audio> page into a hidden CEFBrowserComponent. The home-built CEF carried proprietary codecs, so it was effectively the media engine. Upstream JCEF ships no proprietary codecs, so swapping it in would break H.264/AAC/MP3 for the whole Media API, not just in-page video.

Rather than rebuild CEF with proprietary_codecs/x264 in CI (expensive, fragile), this routes the Media API onto ffmpeg:

  • FFMPEGMedia resolves ffmpeg/ffprobe from the bundled org.bytedeco:ffmpeg-platform binaries via Loader.load (reflectively, so the dep stays optional). No externally installed ffmpeg required.
  • ffmpeg's native decoders cover H.264/AAC/MP3 and need no GPL/x264 (x264 is encode-only) — so plain bytedeco ffmpeg plays proprietary media.
  • Media routing flips from opt-in to default-on; -Dcn1.javase.mediaImplementation=cef is the escape hatch.

This also removes the PATH-installed-ffmpeg dependency that broke #4630's windows-latest smoke test.

Scope decision

In-browser H.264 <video> inside a BrowserComponent is out of scope (it's the only thing that would require a proprietary-codec CEF). Free codecs (WebM/VP9/AV1/Opus) still play in-page; the CN1 Media API handles everything via ffmpeg. On real devices nothing changes (native WebView / native maps).

Commits

  1. Reuse Updated JCEF to use upstream version #4630's upstream-JCEF + ffmpeg work on a fresh branch (27 files).
  2. Make bundled ffmpeg the default simulator media engine.

Deferred (follow-ups)

  • Bump Chromium 95 → 135 (all six native classifiers confirmed available). Kept at 95 here so the JCEF-API-compat surface of the org.cef glue is validated separately.
  • Automate updates: a scheduled job / Dependabot that bumps the jcef.version property when me.friwi publishes a newer build. With this architecture "update CEF" is a one-line version bump — no CEF build pipeline.
  • Optionally trim ffmpeg-platform to the current platform to cut simulator download size, and remove the now-redundant ffmpeg-install steps from the smoke workflow.

🤖 Generated with Claude Code

shai-almog and others added 2 commits June 27, 2026 09:07
Reproduces the salvageable parts of PR #4630 (branch new-jcef-support) on a
clean branch off current master:
 - replace the home-built Chromium-84 com.codenameone:jcef system jar with
   upstream prebuilt me.friwi JCEF artifacts (new maven/cn1-binaries module)
 - add FFMPEGMedia as a media backend + the JavaSE CEF/ffmpeg smoke test

Seed commit only. The new-direction changes (bundled self-contained ffmpeg as
the default media engine, no proprietary-codec CEF, current Chromium) follow as
separate commits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With upstream codec-free CEF, the CN1 Media API (which in the simulator plays
through a hidden CEFBrowserComponent) can no longer decode H.264/AAC/MP3. Route
the Media API to the ffmpeg backend instead:

 - FFMPEGMedia.resolveExecutable now falls back to the ffmpeg/ffprobe binaries
   bundled by the org.bytedeco:ffmpeg-platform dependency (resolved reflectively
   via Loader.load), so no externally installed ffmpeg is needed. ffmpeg's
   native decoders cover H.264/AAC/MP3 -- those need no GPL/x264 encoder -- which
   is exactly what codec-free upstream CEF dropped.
 - Media routing flips from opt-in (-Dcn1.javase.mediaImplementation=ffmpeg) to
   default-on, with -Dcn1.javase.mediaImplementation=cef as the escape hatch.

This also removes the PATH-installed-ffmpeg dependency that broke #4630's
windows-latest smoke test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
import platform
import shutil
import subprocess
import sys
print(f"[javase-cef-ffmpeg-smoke] {message}", flush=True)


def run(cmd, cwd=None, env=None, log_name=None, timeout=None):
@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 11 screenshots: 11 matched.
✅ JavaSE simulator integration screenshots matched stored baselines.

@github-actions

github-actions Bot commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

✅ Continuous Quality Report

Test & Coverage

Static Analysis

  • SpotBugs [Report archive]
    • ByteCodeTranslator: 0 findings (no issues)
    • android: 0 findings (no issues)
    • codenameone-maven-plugin: 0 findings (no issues)
    • core-unittests: 0 findings (no issues)
    • ios: 0 findings (no issues)
  • PMD: 0 findings (no issues) [Report archive]
  • Checkstyle: 0 findings (no issues) [Report archive]

Generated automatically by the PR CI workflow.

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 139 screenshots: 139 matched.

Native Android coverage

  • 📊 Line coverage: 14.61% (8980/61459 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.84% (44181/373047), branch 5.24% (1840/35083), complexity 6.30% (2119/33613), method 10.91% (1714/15708), class 17.74% (395/2227)
    • 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)

✅ Native Android screenshot tests passed.

Native Android coverage

  • 📊 Line coverage: 14.61% (8980/61459 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 11.84% (44181/373047), branch 5.24% (1840/35083), complexity 6.30% (2119/33613), method 10.91% (1714/15708), class 17.74% (395/2227)
    • 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
SIMD kernel backend scalar fallback (no native SIMD)
SIMD int-add (64K x300) java 267ms / native 166ms = 1.6x speedup
SIMD float-mul (64K x300) java 187ms / native 112ms = 1.6x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path gated to scalar (CPU autovectorizes scalar; explicit SIMD not beneficial here)
Base64 CN1 encode 347.000 ms
Base64 CN1 decode 227.000 ms
Base64 native encode 769.000 ms
Base64 encode ratio (CN1/native) 0.451x (54.9% faster)
Base64 native decode 1350.000 ms
Base64 decode ratio (CN1/native) 0.168x (83.2% faster)
Image encode benchmark status skipped (SIMD unsupported)

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 131 screenshots: 131 matched.
✅ JavaScript-port screenshot tests passed.

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 214 screenshots: 214 matched.
✅ Native Apple Watch (watchOS, Core Graphics) screenshot tests passed.

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 134 screenshots: 134 matched.
✅ Native iOS screenshot tests passed.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 64000 ms
Simulator Boot (Run) 1000 ms
App Install 14000 ms
App Launch 3000 ms
Test Execution 445000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 253ms / native 3ms = 84.3x speedup
SIMD float-mul (64K x300) java 63ms / native 3ms = 21.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 472.000 ms
Base64 CN1 decode 224.000 ms
Base64 native encode 959.000 ms
Base64 encode ratio (CN1/native) 0.492x (50.8% faster)
Base64 native decode 897.000 ms
Base64 decode ratio (CN1/native) 0.250x (75.0% faster)
Base64 SIMD encode 57.000 ms
Base64 encode ratio (SIMD/CN1) 0.121x (87.9% faster)
Base64 SIMD decode 48.000 ms
Base64 decode ratio (SIMD/CN1) 0.214x (78.6% faster)
Base64 encode ratio (SIMD/native) 0.059x (94.1% faster)
Base64 decode ratio (SIMD/native) 0.054x (94.6% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 20.000 ms
Image createMask (SIMD on) 2.000 ms
Image createMask ratio (SIMD on/off) 0.100x (90.0% faster)
Image applyMask (SIMD off) 101.000 ms
Image applyMask (SIMD on) 159.000 ms
Image applyMask ratio (SIMD on/off) 1.574x (57.4% slower)
Image modifyAlpha (SIMD off) 320.000 ms
Image modifyAlpha (SIMD on) 73.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.228x (77.2% faster)
Image modifyAlpha removeColor (SIMD off) 209.000 ms
Image modifyAlpha removeColor (SIMD on) 304.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.455x (45.5% slower)

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 136 screenshots: 136 matched.
✅ Native Apple TV (tvOS, Metal) screenshot tests passed.

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 137 screenshots: 137 matched.
✅ Native Mac screenshot tests passed.

Benchmark Results

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

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 91ms / native 6ms = 15.1x speedup
SIMD float-mul (64K x300) java 79ms / native 3ms = 26.3x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 436.000 ms
Base64 CN1 decode 290.000 ms
Base64 native encode 1607.000 ms
Base64 encode ratio (CN1/native) 0.271x (72.9% faster)
Base64 native decode 1119.000 ms
Base64 decode ratio (CN1/native) 0.259x (74.1% faster)
Base64 SIMD encode 76.000 ms
Base64 encode ratio (SIMD/CN1) 0.174x (82.6% faster)
Base64 SIMD decode 69.000 ms
Base64 decode ratio (SIMD/CN1) 0.238x (76.2% faster)
Base64 encode ratio (SIMD/native) 0.047x (95.3% faster)
Base64 decode ratio (SIMD/native) 0.062x (93.8% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 58.000 ms
Image createMask (SIMD on) 19.000 ms
Image createMask ratio (SIMD on/off) 0.328x (67.2% faster)
Image applyMask (SIMD off) 296.000 ms
Image applyMask (SIMD on) 224.000 ms
Image applyMask ratio (SIMD on/off) 0.757x (24.3% faster)
Image modifyAlpha (SIMD off) 224.000 ms
Image modifyAlpha (SIMD on) 241.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.076x (7.6% slower)
Image modifyAlpha removeColor (SIMD off) 219.000 ms
Image modifyAlpha removeColor (SIMD on) 225.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 1.027x (2.7% slower)

@shai-almog

shai-almog commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator Author

Compared 138 screenshots: 138 matched.
✅ Native iOS Metal screenshot tests passed.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 88000 ms
Simulator Boot (Run) 1000 ms
App Install 13000 ms
App Launch 0 ms
Test Execution 335000 ms

Detailed Performance Metrics

Metric Duration
SIMD kernel backend SSE2 (x64) / NEON (arm64) native kernels
SIMD int-add (64K x300) java 63ms / native 2ms = 31.5x speedup
SIMD float-mul (64K x300) java 63ms / native 3ms = 21.0x speedup
SIMD kernel correctness PASS (native result == scalar reference)
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 SIMD byte path active (NEON-accelerated)
Base64 CN1 encode 513.000 ms
Base64 CN1 decode 212.000 ms
Base64 native encode 1142.000 ms
Base64 encode ratio (CN1/native) 0.449x (55.1% faster)
Base64 native decode 363.000 ms
Base64 decode ratio (CN1/native) 0.584x (41.6% faster)
Base64 SIMD encode 57.000 ms
Base64 encode ratio (SIMD/CN1) 0.111x (88.9% faster)
Base64 SIMD decode 50.000 ms
Base64 decode ratio (SIMD/CN1) 0.236x (76.4% faster)
Base64 encode ratio (SIMD/native) 0.050x (95.0% faster)
Base64 decode ratio (SIMD/native) 0.138x (86.2% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 56.000 ms
Image createMask (SIMD on) 40.000 ms
Image createMask ratio (SIMD on/off) 0.714x (28.6% faster)
Image applyMask (SIMD off) 186.000 ms
Image applyMask (SIMD on) 259.000 ms
Image applyMask ratio (SIMD on/off) 1.392x (39.2% slower)
Image modifyAlpha (SIMD off) 156.000 ms
Image modifyAlpha (SIMD on) 179.000 ms
Image modifyAlpha ratio (SIMD on/off) 1.147x (14.7% slower)
Image modifyAlpha removeColor (SIMD off) 308.000 ms
Image modifyAlpha removeColor (SIMD on) 149.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.484x (51.6% faster)

shai-almog and others added 5 commits June 27, 2026 10:51
setupFFmpeg copied a PATH ffmpeg/ffprobe into ffmpeg.dir. On Windows that picks
up a chocolatey shimgen shim which does not work once copied out of place, so
the video process produced zero decoded frames silently -- and because
resolveExecutable checks ffmpeg.dir first, the bundled bytedeco binaries were
never reached (this was the windows-latest smoke failure).

Drop the PATH staging entirely; the runtime resolves ffmpeg/ffprobe from the
bundled org.bytedeco:ffmpeg-platform binaries, with ffmpeg.dir kept only as an
explicit user override. Removes the now-unused findExecutableOnPath helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Updates jcef.version from Chromium 95 to the current upstream me.friwi release
(Chromium 135; all six native classifiers verified on Maven Central) and adapts
the custom CEF glue to the org.cef API changes between 95 and 135:
 - CefBrowser_N's constructor gained a trailing CefBrowserSettings parameter
 - CefRequestHandler.onPluginCrashed was removed
 - onRenderProcessTerminated gained (int errorCode, String errorString)

All other overridden handler signatures are unchanged between the two versions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
JCEF 135 added addOnPaintListener/setOnPaintListener/removeOnPaintListener to
CefRenderHandler, and me.friwi's CefRenderHandlerAdapter leaves them abstract.
CN1's anonymous render handler must therefore implement them; CN1 renders
directly in onPaintImpl and does not use the listener convenience API, so they
are no-ops.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The Ant build of the JavaSE port compiles against cn1-binaries/javase/jcef.jar
(the legacy home-built Chromium-84 API jar) while Maven now uses me.friwi. At
Chromium 95 the two APIs were compatible, but the 135 bump diverged and broke
the Ant-based jobs (build-test, javase-simulator-tests).

Add scripts/ci-install-upstream-jcef-jar.sh, which installs the me.friwi
jcef-api jar matching maven/pom.xml's jcef.version as cn1-binaries/javase/jcef.jar
(from the local ~/.m2 if present, else Maven Central), and invoke it before each
Ant JavaSE compile (pr.yml build-test, run-javase-simulator-integration-tests.sh,
run-javase-device-tests.sh). Keeps both build systems on the same JCEF; the Ant
build only needs the API jar for compilation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The build-port job skipped setup-workspace whenever the prebuilt-jars cache
(cn1-built) hit, assuming the separately-keyed codenameone-tools cache was also
present. Under cache pressure GitHub can evict cn1-tools while cn1-built
survives; setup-workspace is then skipped and tools/env.sh never gets created,
breaking every dependent app job (build-ios*, native-ios, packaging,
mac-native), which only restore caches and never run setup-workspace themselves.

Give the codenameone-tools cache an id and also run setup-workspace when that
cache misses.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

Problem in my simulator using maps hot to fix?

1 participant