Skip to content

Rebuild native themes via CSS compiler (phase 2: module split)#4793

Draft
liannacasper wants to merge 31 commits intomasterfrom
rebuild-themes
Draft

Rebuild native themes via CSS compiler (phase 2: module split)#4793
liannacasper wants to merge 31 commits intomasterfrom
rebuild-themes

Conversation

@liannacasper
Copy link
Copy Markdown
Collaborator

Summary

First slice of the native-themes refactor planned in /plan. Extracts the Codename One CSS compiler into a thin maven/css-compiler module with clean dependencies (core + flute + sac) so the shipped iOS Modern (liquid-glass) and Android Material themes can be generated at framework build time without pulling in JavaSE / JavaFX / CEF / the Designer GUI.

  • Phase 1strictNoCef flag + enforceNoCef() pre-scan in CSSTheme + -no-cef CLI arg on CN1CSSCLI + new NoCefCSSCLI minimal entry point.
  • Phase 2EditableResources physically moved into maven/css-compiler; designer/javase imports stripped; four throwing hooks introduced; EditableResourcesEditor subclass in the Designer overrides the hooks. New com.codename1.ui.util.SVGDocument interface in core replaces the compile-time dep on impl.javase.SVG. CSSTheme, ResourcesMutator, Color, helpers, and the com.codename1.ui.util.xml package moved alongside. maven/designer now depends on codenameone-css-compiler.
  • Build pipelinescripts/build-native-themes.sh + smoke CSS at native-themes/{ios-modern,android-material}/theme.css + Themes/.gitignore.
  • CIpr.yml gains a step that installs css-compiler and runs the native-themes build; designer.yml switched to Maven for building the Designer jar + CLI CSS smoke + native-themes smoke under xvfb.

Plan: /Users/shai/.claude/plans/at-the-moment-we-dapper-origami.md (approved earlier).

Known follow-ups (not in this PR)

  • Ant Designer build (CodenameOneDesigner/build.xml) still expects all CSS classes under src/; needs source-root awareness of maven/css-compiler or NetBeans/Ant devs to switch to Maven.
  • ResourceEditorView ~line 2382 still calls EditableResources.open(...) returning a base instance — fine for the override-resource side path but a future EditableResourcesEditor.open(...) factory would be tidier.
  • Phase 3+ (real component CSS, port installNativeTheme() rewrites, simulator bundling + override menu, cn1.nativeTheme build hint, screenshot fidelity tests).

Test plan

  • pr.yml matrix (Java 8/17/21) builds green including the new "Build CSS compiler and smoke native-themes" step.
  • designer.yml builds the Designer jar via Maven, the CLI CSS compile smoke produces a non-empty .res, and the native-themes smoke step writes Themes/iOSModernTheme.res + Themes/AndroidMaterialTheme.res.
  • ant.yml (Java CI) full reactor mvn install -Plocal-dev-javase passes.
  • Manual: ./scripts/build-native-themes.sh locally after mvn -pl css-compiler -am install produces both .res files and an intentional forbidden rule (e.g. box-shadow: 0 2px 4px #000 in a theme CSS) fails the build with the offending-UIID list.
  • Manual: open an existing .res file in the Designer GUI and confirm all resource types still open editors correctly (proves the EditableResourcesEditor wiring).

🤖 Generated with Claude Code

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

Android screenshot updates

Compared 63 screenshots: 37 matched, 26 missing references.

  • ButtonTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ButtonTheme_dark.png.

    ButtonTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ButtonTheme_dark.png in workflow artifacts.

  • ButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ButtonTheme_light.png.

    ButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ButtonTheme_light.png in workflow artifacts.

  • CheckBoxRadioTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/CheckBoxRadioTheme_dark.png.

    CheckBoxRadioTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as CheckBoxRadioTheme_dark.png in workflow artifacts.

  • CheckBoxRadioTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/CheckBoxRadioTheme_light.png.

    CheckBoxRadioTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as CheckBoxRadioTheme_light.png in workflow artifacts.

  • DialogTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/DialogTheme_dark.png.

    DialogTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as DialogTheme_dark.png in workflow artifacts.

  • DialogTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/DialogTheme_light.png.

    DialogTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as DialogTheme_light.png in workflow artifacts.

  • FloatingActionButtonTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/FloatingActionButtonTheme_dark.png.

    FloatingActionButtonTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as FloatingActionButtonTheme_dark.png in workflow artifacts.

  • FloatingActionButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/FloatingActionButtonTheme_light.png.

    FloatingActionButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as FloatingActionButtonTheme_light.png in workflow artifacts.

  • ListTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ListTheme_dark.png.

    ListTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ListTheme_dark.png in workflow artifacts.

  • ListTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ListTheme_light.png.

    ListTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ListTheme_light.png in workflow artifacts.

  • MultiButtonTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/MultiButtonTheme_dark.png.

    MultiButtonTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as MultiButtonTheme_dark.png in workflow artifacts.

  • MultiButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/MultiButtonTheme_light.png.

    MultiButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as MultiButtonTheme_light.png in workflow artifacts.

  • PickerTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/PickerTheme_dark.png.

    PickerTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as PickerTheme_dark.png in workflow artifacts.

  • PickerTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/PickerTheme_light.png.

    PickerTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as PickerTheme_light.png in workflow artifacts.

  • ShowcaseTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ShowcaseTheme_dark.png.

    ShowcaseTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ShowcaseTheme_dark.png in workflow artifacts.

  • ShowcaseTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ShowcaseTheme_light.png.

    ShowcaseTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ShowcaseTheme_light.png in workflow artifacts.

  • SpanLabelTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SpanLabelTheme_dark.png.

    SpanLabelTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SpanLabelTheme_dark.png in workflow artifacts.

  • SpanLabelTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SpanLabelTheme_light.png.

    SpanLabelTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SpanLabelTheme_light.png in workflow artifacts.

  • SwitchTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SwitchTheme_dark.png.

    SwitchTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SwitchTheme_dark.png in workflow artifacts.

  • SwitchTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/SwitchTheme_light.png.

    SwitchTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as SwitchTheme_light.png in workflow artifacts.

  • TabsTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TabsTheme_dark.png.

    TabsTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TabsTheme_dark.png in workflow artifacts.

  • TabsTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TabsTheme_light.png.

    TabsTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TabsTheme_light.png in workflow artifacts.

  • TextFieldTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TextFieldTheme_dark.png.

    TextFieldTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TextFieldTheme_dark.png in workflow artifacts.

  • TextFieldTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/TextFieldTheme_light.png.

    TextFieldTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as TextFieldTheme_light.png in workflow artifacts.

  • ToolbarTheme_dark — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ToolbarTheme_dark.png.

    ToolbarTheme_dark
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ToolbarTheme_dark.png in workflow artifacts.

  • ToolbarTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/android/screenshots/ToolbarTheme_light.png.

    ToolbarTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ToolbarTheme_light.png in workflow artifacts.

Native Android coverage

  • 📊 Line coverage: 8.36% (4453/53288 lines covered) [HTML preview] (artifact android-coverage-report, jacocoAndroidReport/html/index.html)
    • Other counters: instruction 6.56% (21961/334731), branch 3.07% (988/32204), complexity 3.92% (1210/30848), method 6.93% (999/14411), class 11.43% (219/1916)
    • 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 717.000 ms
Base64 CN1 encode 136.000 ms
Base64 encode ratio (CN1/native) 0.190x (81.0% faster)
Base64 native decode 632.000 ms
Base64 CN1 decode 191.000 ms
Base64 decode ratio (CN1/native) 0.302x (69.8% faster)
Image encode benchmark status skipped (SIMD unsupported)

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

✅ Continuous Quality Report

Test & Coverage

Static Analysis

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

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

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

JavaScript port screenshot updates

Compared 38 screenshots: 34 matched, 4 missing references.

  • ButtonTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/javascript/screenshots/ButtonTheme_light.png.

    ButtonTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ButtonTheme_light.png in workflow artifacts.

  • CheckBoxRadioTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/javascript/screenshots/CheckBoxRadioTheme_light.png.

    CheckBoxRadioTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as CheckBoxRadioTheme_light.png in workflow artifacts.

  • TextFieldTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/javascript/screenshots/TextFieldTheme_light.png.

    TextFieldTheme_light
    Preview info: JPEG preview quality 50; JPEG preview quality 50.
    Full-resolution PNG saved as TextFieldTheme_light.png in workflow artifacts.

  • ToolbarTheme_light — missing reference. Reference screenshot missing at /home/runner/work/CodenameOne/CodenameOne/scripts/javascript/screenshots/ToolbarTheme_light.png.

    ToolbarTheme_light
    Preview info: JPEG preview quality 70; JPEG preview quality 70.
    Full-resolution PNG saved as ToolbarTheme_light.png in workflow artifacts.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

Developer Guide build artifacts are available for download from this workflow run:

Developer Guide quality checks:

  • AsciiDoc linter: No issues found (report)
  • Vale: 15147 alert(s) (1106 errors, 4479 warnings, 9562 suggestions) (exit code 1) (report)
  • Image references: No unused images detected (report)

shai-almog and others added 24 commits April 22, 2026 19:40
First slice of the native-themes refactor: the CSS compiler now lives in
its own Maven module with clean dependencies (core + flute + sac) so the
shipped platform themes (iOS Modern liquid-glass + Android Material) can
be generated at framework build time without pulling in JavaSE / JavaFX /
CEF / the Designer GUI.

Phase 1 (no-cef enforcement):
- CSSTheme.strictNoCef static flag + enforceNoCef() pre-scan that lists
  every UIID state requiring CEF-backed image rasterization and throws
  before any WebView call.
- CN1CSSCLI gained a -no-cef CLI arg.
- New NoCefCSSCLI minimal entry point (no JavaSEPort/BrowserComponent
  bootstrap) with a throwing WebViewProvider as a safety net.

Phase 2 (module split):
- New maven/css-compiler Maven module; registered in the reactor between
  factory and sqlite-jdbc. Produces a jar and a fat
  jar-with-dependencies whose main class is NoCefCSSCLI.
- maven/designer now depends on codenameone-css-compiler.
- EditableResources physically moved into maven/css-compiler, with its
  com.codename1.designer.* and com.codename1.impl.javase.* imports
  stripped. GUI functionality exposed as protected throwing hooks
  (persistUIContainer, onOpenFileComplete, writeUIXml,
  getRuntimeNativeTheme) plus a settable loadedBaseFile field and an
  inline IS_MAC constant replacing ResourceEditorApp.IS_MAC.
- New EditableResourcesEditor subclass lives in the Designer and
  overrides every hook, reinstating the GUI behavior (UserInterfaceEditor,
  ThemeEditor, JavaSEPortWithSVGSupport, getResourceEditor, ...).
- New com.codename1.ui.util.SVGDocument interface in core; javase-svg's
  SVG class implements it. EditableResources casts to SVGDocument so the
  thin module avoids the compile-time dep on impl.javase.SVG.
- EditableResourcesForCSS, CSSTheme, ResourcesMutator, Color,
  MissingNativeBrowserException, PollingFileWatcher, and the
  com.codename1.ui.util.xml package moved alongside EditableResources.
- Designer callers bulk-updated: new EditableResources(...) ->
  new EditableResourcesEditor(...) with imports added, in
  ResourceEditorView, ResourceEditorApp, AddThemeResource, AddUIResource,
  CodenameOneTask, CN1CSSCLI, CN1CSSCompiler, CN1CSSInstallerCLI.
- ResourceEditorView.loadedResources retyped to EditableResourcesEditor.

Build pipeline:
- scripts/build-native-themes.sh drives the thin jar (prefers a fresh
  target/ build, falls back to ~/.m2). Writes iOSModernTheme.res and
  AndroidMaterialTheme.res under Themes/ (gitignored).
- Smoke CSS sources in native-themes/{ios-modern,android-material}/theme.css
  with light+dark tokens and includeNativeBool:false to avoid the
  self-inheriting recursion trap.
- native-themes/README.md documents the CEF-free subset.

CI:
- pr.yml gains a step that installs css-compiler and runs the
  native-themes build, failing on missing outputs.
- designer.yml switched from Ant to Maven for building the Designer jar
  and running the CLI CSS smoke test (the Ant Designer build is broken
  until its source roots are taught about maven/css-compiler; Maven is
  the preferred path per CLAUDE.md anyway). Also runs the native-themes
  smoke under xvfb.

Known follow-ups (not in this commit):
- Ant-based Designer build (CodenameOneDesigner/build.xml) still expects
  all CSS classes under src/; local NetBeans/Ant developers will need
  source-tree awareness of maven/css-compiler or a switch to Maven.
- ResourceEditorView line ~2382 still calls EditableResources.open(...)
  returning a base instance; fine for the override-resource side path
  but a future EditableResourcesEditor.open(...) factory would be tidier.
- Phase 3+ (real CSS themes, port integration, simulator bundling,
  build hints, screenshot tests) pending.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
maven/designer/pom.xml declared a dependency on codenameone-css-compiler
without a version, expecting the root pom's dependencyManagement to fill
it in. The entry was missing, so every downstream module failed to
resolve the POM (observed in PR CI). Add the managed version entry next
to codenameone-core.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CI (Java CI + Designer CI) surfaced two classes of errors that the
refactor missed:

1. Accessor/helper classes declared in core-like packages but living in
   the Designer source tree (EditorFont, EditorTTFFont, CodenameOneAccessor,
   animations.AnimationAccessor, plaf.Accessor, plaf.ProtectedUIManager)
   were left behind when EditableResources moved to the css-compiler
   module. They use package-private access into core, so they must
   travel with EditableResources. Moved them into the css-compiler src
   tree. Designer still sees them via the codenameone-css-compiler
   dependency.

2. EditableResources.openFile() directly instantiated
   CodenameOneDesigner's UIBuilderOverride to materialize an XML-stored
   UI container before re-serializing. UIBuilderOverride imports
   com.codename1.designer.* (ActionCommand, UserInterfaceEditor) so it
   cannot live in the thin module. Introduced a new protected hook
   loadUIContainerFromXml(ComponentEntry) that returns null in the
   base (triggering the binary-blob fallback already in the loop) and
   is overridden by EditableResourcesEditor to drive UIBuilderOverride.

3. SimpleWebServer and WebviewSnapshotter (used by ResourcesMutator's
   CEF image rasterization) had clean imports and were still referenced
   by the compile path, so they moved to the css-compiler module too.
   In strict-no-cef builds they are still never invoked.

4. SVGDocument.java switched from /** classic Javadoc to /// markdown
   comments per the repo's java25-markdown-docs style validator.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two leftover references prevented the css-compiler module from compiling:

- EditableResources.saveXMLFile() still instantiated UIBuilderOverride
  directly in the MAGIC_UI branch to materialize a container from a
  binary UI resource before writing it back as XML. Wrapped in a new
  materializeUIContainer(resourceName) hook; base throws, the Designer
  EditableResourcesEditor overrides with the UIBuilderOverride call.
- ResourcesMutator.createScreenshots() used Logger.getLogger(CN1CSSCompiler
  .class.getName()) purely as a logger name. Rerouted to
  Logger.getLogger(ResourcesMutator.class.getName()).

Also tightened NoCefCSSCLI's header comment (plain text instead of a
broken {@link CN1CSSCLI} reference that javadoc-plugin would flag).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
.claude/scheduled_tasks.lock slipped into the previous commit because it
wasn't covered by .gitignore. It's a Claude Code session-local
scheduled-wakeup lock, not repo content. Untrack and ignore.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ditor

Retyping ResourceEditorView.loadedResources to EditableResourcesEditor
broke generateStateMachineCodeEx (takes a base EditableResources and
assigns it to the field). Narrower fix: field stays base-typed and the
single .getResourceEditor(...) call site casts to the editor subclass.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two CI fixes on top of the now-green Java CI:

- build-native-themes.sh: ensure_jar() used log() (which went to stdout)
  AND echo "$jar" inside the same function whose output was captured via
  $(...) by the caller. Result: the log line "Using CSS compiler jar:
  <path>" got concatenated with the path and handed to java -jar, which
  responded with "Unable to access jarfile". Redirect log() to stderr so
  only the jar path lands on stdout.
- designer.yml: the Maven-produced
  codenameone-designer-*-jar-with-dependencies.jar is actually a ZIP
  wrapper around the runnable designer_1.jar (see the antrun
  add-designer-jar-with-dependencies execution in maven/designer/pom.xml).
  Unzip to a temp dir and run the inner jar.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Both PR CI and Designer CI are hitting 'Cannot assign field "cssFile"
because "theme" is null' at NoCefCSSCLI.java - meaning CSSTheme.load
returned null without any diagnostic. The Designer's original NPE
catch logged nothing for non-"encoding properties" NPEs (the
Logger.log line was commented out). Re-enable logging for the general
case, null-guard the message check, and have NoCefCSSCLI fail with a
helpful message if the parser returns null. Next CI run should show
the real stack trace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stack trace from PR CI shows:
  at com.codename1.io.Util.copy(Util.java:211)
  at com.codename1.io.Util.readInputStream(Util.java:402)
  at com.codename1.designer.css.CSSTheme.load(CSSTheme.java:7110)
  at com.codename1.designer.css.NoCefCSSCLI.main(NoCefCSSCLI.java:55)

Util.copy(in, out, bufferSize) unconditionally dereferences
Util.getImplementation() to route cleanup() through the platform impl.
In the native-themes build the css-compiler runs headless - no Display
has been initialized, no Util implementation is set, and the unwrapped
null crashes before CSSTheme can even parse the CSS. Guard the cleanup
path: if no implementation is set, close the streams directly (which is
what every impl's cleanup(Object) ends up doing for InputStream/OutputStream
anyway).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Designer CI logs (now with working stack traces) show:
  CSSException: Unsupported CSS condition type 10 for ElementSelectorImpl
  at com.codename1.designer.css.CSSTheme.getElementForSelector(CSSTheme.java:6561)

My smoke CSS used :pressed / :disabled pseudo-classes. The CN1 CSS
compiler actually handles state selectors as dot-class conditions
(.pressed, .disabled) - see docs/developer-guide/css.asciidoc line 38
("Button.pressed defines styles for the 'Button' UIID's 'pressed' state")
and the SAC_CLASS_CONDITION branch in CSSTheme.getElementForSelector.
The pseudo-class syntax (condition type 10) is not recognized. Switch
smoke themes to .state syntax and clarify the native-themes README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Next NPE after the pseudo-class fix:
  at com.codename1.ui.Font.<init>(Font.java:176)
  at com.codename1.ui.Font.createSystemFont(Font.java:452)
  at CSSTheme$Element.getThemeFont(CSSTheme.java:4671)
  at CSSTheme.updateResources(CSSTheme.java:1887)

Font(int, int, int) dereferences Display.getInstance().getImplementation()
to create a native font - null in the headless css-compiler run. The
smoke themes don't need a font to exercise the no-cef pipeline end to
end, so drop font-family. Phase 3 will add a minimal headless impl (or
make Font creation degrade gracefully when Display is uninitialized) so
real themes can specify fonts.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3: replace the smoke placeholder CSS with real component coverage.
Both themes now style ~25 UIIDs each with light/dark palettes, including:

- base (Component, Form, ContentPane, Container)
- typography (Label, SecondaryLabel, TertiaryLabel, SpanLabel*)
- buttons (Button, RaisedButton, FlatButton + .pressed / .disabled)
- text input (TextField, TextArea, TextHint + focused/disabled)
- selection controls (CheckBox, RadioButton, OnOffSwitch + .selected)
- toolbar (Toolbar, TitleArea, Title, MainTitle, Back/Title commands)
- tabs (Tabs, TabsContainer, Tab, Selected/UnselectedTab)
- side menu (SideNavigationPanel, SideCommand)
- list + MultiButton (List, ListRenderer, MultiButton, MultiLine1..4)
- dialog/sheet (Dialog, DialogBody, DialogTitle, Dialog{Content,Command}Area)
- FAB (FloatingActionButton + .pressed)
- misc (Separator, PopupContent)

Palettes:
- iOS Modern — Apple system colors (accent=#007aff light / #0a84ff dark,
  Apple grouped-background surfaces, separator colors); liquid-glass feel
  is approximated via solid fills with subtle tonal surface variants.
- Android Material — Material 3 baseline tonal palette (primary=#6750a4
  light / #d0bcff dark, Material surface-container tiers). Elevation is
  approximated with surface-container-high tonal values since box-shadow
  would force CEF rasterization.

Font.java (core) small fix: the package-private Font(int,int,int)
constructor used to NPE when Display.impl was null. The css-compiler
native-themes build is headless (no Display.init) and needs to serialize
font descriptors without actually allocating native font handles. Guard
the createFont call; headless serialization writes face/style/size only
and the native handle is recreated when the resource is loaded in a
running app.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Phase 3 Designer CI revealed:
  RuntimeException: Unsupported CSS property cn1-pill-border
  RuntimeException: Unsupported CSS property cn1-round-border

Those are not top-level CSS properties in the CN1 compiler; they are
values of the cn1-background-type property. Rewrite to
  cn1-background-type: cn1-pill-border;
  cn1-background-type: cn1-round-border;

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…iter)

Phase 3 CI error was a cascade: the CSS compiler's
transformDarkModeMediaQueries turns any selector inside
@media (prefers-color-scheme: dark) into $DarkSelector. For component
selectors this produces the wanted $DarkButton etc. But for :root the
rewrite emits $DarkComponent:root which Flute rejects ("encountered
' '. Was expecting ':' <IDENT> <FUNCTION>"), and every declaration
inside that dark :root block is skipped. The light :root block then
survives just fine, but because Flute aborts the dark block early the
parser never registers those variables. When update_resources later
tries to serialize a fg color it finds a raw var() FUNCTION
lexical-unit instead of a resolved color and throws
"Unsupported color type 41".

Simplest path that keeps the compiler as-is: drop CSS variables from
the shipped themes and inline hex values per UIID. Light values go in
the top-level rules, dark values go in the @media
(prefers-color-scheme: dark) block which the compiler maps to
$DarkUIID. Every UIID now has a matching dark entry. When the
compiler grows real :root-in-@media support (separate change), we can
re-introduce variables.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two more headless NPEs surfaced by the real themes:

1. EditorTTFFont.refresh() loaded /com/codename1/impl/javase/Roboto-*.ttf
   via getClass().getResourceAsStream. That resource ships in the javase
   port jar, not in our thin css-compiler jar, so the stream is null and
   java.awt.Font.createFont(null) throws IOException. Guard the null
   stream and return early; the .res serialization only needs the
   nativeFontName descriptor, and the native AWT font is recreated at
   app runtime when the platform impl is available.

2. RoundBorder.<init> calls Display.getInstance().convertToPixels(2) to
   set its shadowSpread - which dereferences a null impl in the headless
   build. Make convertToPixels return a 1:1 fallback when impl is null.
   Conversions are recomputed at runtime.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Next NPE in Phase 3:
  at com.codename1.ui.Font.getFace(Font.java:742)
  at com.codename1.ui.util.EditableResources.saveTheme(EditableResources.java:2095)

EditableResources serializes system fonts by calling Font.getFace(),
getSize(), getStyle(), each of which dereferences Display.impl. In the
headless css-compiler build impl is null. Capture face/style/size in
the Font(int,int,int) constructor into headlessFace/Style/Size fields
and return them from the three accessors when impl is null. Non-system
fonts (TTF, bitmap) never enter this path and keep the fields at zero.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Feedback: "SVGDocument should be package private to avoid polluting the
UI. Looking at the code I don't see why it needs to be in the core API
to begin with."

Deleted com.codename1.ui.util.SVGDocument from core. Reverted
javase-svg's SVG class to a plain class (no implements). The few
EditableResources code paths that need SVG fields now go through a
package-private static SvgBridge inside EditableResources itself,
which reflectively calls SVG's methods. This is cold code from the
css-compiler point of view (SVG paths only fire when the resource
being serialized contains SVG images, which the native-themes build
never produces) so reflection overhead is a non-issue. Bridge lives
where it is used, no cross-module interface or API surface is added.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Port integration for the CSS-generated iOSModernTheme.res and
AndroidMaterialTheme.res:

- IOSImplementation.installNativeTheme() resolves theme by the
  existing ios.themeMode hint. "modern" / "liquid" / "auto" loads
  /iOSModernTheme.res (with a graceful fall-through to iOS7Theme if
  the generator hasn't produced it yet, so apps still boot in a
  partial build); "ios7" / "flat" keeps the flat theme; everything
  else falls back to the pre-flat iPhone theme. "auto" now defaults
  to modern, per the decided release plan.

- AndroidImplementation.installNativeTheme() reads a new
  cn1.androidTheme property ("material" | "hololight" | "legacy");
  and.hololight=true still maps to hololight for back-compat. Default
  is material. Drops the SDK_INT<14 gate (universal Android today)
  and swaps the holo-unless-hint logic for the cleaner hint-first
  path. Falls back to holo light if the apk doesn't contain the
  modern .res (partial build).

- Ports/iOSPort/build.xml -pre-compile copies
  ../../Themes/iOSModernTheme.res into nativeSources/ so it ends up
  in dist/nativeios.jar alongside the legacy .res files.
  failonerror=false lets the port still build if
  scripts/build-native-themes.sh hasn't produced the file yet
  (runtime fallback kicks in).

- Ports/Android/build.xml -pre-compile copies
  ../../Themes/AndroidMaterialTheme.res into src/ so it lands on the
  APK classpath via the existing <fileset dir="src" includes="*.res"/>
  jar packaging. Same failonerror=false guard.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The java25-markdown-docs validator rejects /** ... */ Javadoc blocks
in CodenameOne/ and Ports/CLDC11/. My Phase 3 edit to Font.java added
one for the headlessFace/Style/Size fields. Convert to /// markdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
SpotBugs on core-unittests flagged DE_MIGHT_IGNORE for the inline
catch (IOException ignored) blocks I added for the headless close
fallback. Refactor into a closeQuietly(Closeable) helper that prints
the exception to stderr instead of silently swallowing it. Semantics
preserved (close failure doesn't propagate) but no more "might ignore"
warning.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three pieces of the JavaSE simulator integration:

- maven/javase/pom.xml antrun build-skins execution copies the six
  shipped .res themes (iOSModernTheme, AndroidMaterialTheme, plus the
  four legacy ones) from Themes/ into ${project.build.outputDirectory}
  alongside iPhoneX.skin. These end up at the root of the simulator
  jar-with-dependencies so the simulator can pick any theme at runtime
  without requiring a skin-repo update. failonerror=false so the
  simulator still builds if the native-themes generator hasn't run.

- JavaSEPort.loadSkinFile(): after the skin archive's platformName is
  parsed, consult -Dcn1.forceSimulatorTheme and the
  simulatorNativeTheme Preference. If neither is set (or is "auto"),
  map ios -> iOSModernTheme and and -> AndroidMaterialTheme; other
  platforms fall through to the skin's embedded theme. "embedded"
  bypasses the override entirely. When a theme id is resolved the
  bundled /<id>.res from the simulator jar replaces nativeThemeData,
  and the existing downstream installNativeTheme path picks it up.

- JavaSEPort.createNativeThemeMenu(): new top-level "Native Theme"
  JMenu next to "Skins" with a radio group for the six themes plus
  "Auto" and "Use skin's embedded theme". Selection writes the
  simulatorNativeTheme Preference, flips reload.simulator, and
  disposes the current window so the skin reloader kicks in with the
  new theme.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CodenameOne/ compiles against Ports/CLDC11/dist/CLDC11.jar as the
bootclasspath (see endorsed.classpath.cmd.line.arg in
CodenameOne/nbproject/project.properties). CLDC11 is a stripped J2ME-
style surface and does not ship java.io.Closeable. My generic
closeQuietly(Closeable) helper therefore fails the CodenameOne Ant
compile. Split into two overloads on InputStream and OutputStream;
both types are in CLDC11 and are all Util.copy needs anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- New Ports/JavaSE/src/com/codename1/impl/javase/BuildHintSchemaDefaults
  registers codename1.arg.{{...}}.label/type/values/description system
  properties for a new "Native Theme" group containing
  cn1.nativeTheme (Shared override), ios.themeMode, and cn1.androidTheme.
  Simulator.main() calls register() right after NSHighResolutionCapable
  so the Build Hints GUI picks them up on every simulator launch.
- IPhoneBuilder now falls back to cn1.nativeTheme when ios.themeMode is
  unset (modern -> modern, legacy -> ios7, otherwise auto).
- docs/developer-guide/Advanced-Topics-Under-The-Hood.asciidoc: updated
  ios.themeMode row, added cn1.androidTheme and cn1.nativeTheme rows
  describing the new values.

Android side: cn1.androidTheme is read at runtime from
Display.getProperty (see AndroidImplementation.installNativeTheme);
generic hint-to-Display-property propagation already exists for build
hints in the Android build path, so no further builder surgery is
needed here.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds a DualAppearanceBaseTest helper plus four initial
<Component>ThemeScreenshotTest subclasses under
scripts/hellocodenameone/common/.../tests/:

- DualAppearanceBaseTest - sequences two captures (light, dark) by
  toggling Display.setDarkMode(false/true), refreshing the global
  theme props, building a fresh Form per appearance, waiting for
  onShowCompleted, emitting CN1SS chunks named <baseName>_light and
  <baseName>_dark. Resets setDarkMode(null) on completion.

- ButtonThemeScreenshotTest covers Button / RaisedButton / FlatButton
  in default, pressed, and disabled states.
- TextFieldThemeScreenshotTest covers TextField with value, hint,
  disabled + TextArea.
- CheckBoxRadioThemeScreenshotTest covers CheckBox / RadioButton in
  unselected, selected, and disabled states.
- ToolbarThemeScreenshotTest covers Toolbar with title, left/right
  material-icon commands, and an overflow command.

All four registered in Cn1ssDeviceRunner's TEST_CLASSES list right
before the terminal OrientationLockScreenshotTest so they execute as
part of the existing iOS/Android/JavaScript screenshot runs. Goldens
(scripts/hellocodenameone/goldens/<platform>/<theme>/...) are captured
manually on a trusted baseline; the diff pipeline
(scripts/common/java/RenderScreenshotReport.java +
PostPrComment.java) picks them up automatically.

More scenes (ComboBox/Picker, Dialog, Tabs, SideMenu, List+MultiButton,
FloatingActionButton, SpanLabel, Layouts) land in a follow-up.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
shai-almog and others added 2 commits April 22, 2026 19:40
Build failure:
  incompatible types: HashMap cannot be converted to Hashtable
  getThemeProps() is not public in com.codename1.ui.plaf.UIManager

I was trying to force a global theme refresh by round-tripping
getThemeProps/setThemeProps. That API is package-private and the
return type has changed. Dropping the refresh entirely: because
DualAppearanceBaseTest creates a FRESH Form per appearance, each
component is styled at attach time against the current CN.isDarkMode()
flag. No global refresh needed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rebased onto master to pull in PR #4677 (Initial work on the new
JavaScript port). Follow-up to make the JS port consume the new
native-themes output:

- HTML5Implementation.installNativeTheme(): new default-theme
  resolution parallel to the iOS/Android ports. Android defaults to
  /AndroidMaterialTheme.res (hololight / legacy reachable via
  cn1.androidTheme); iOS defaults to /iOSModernTheme.res (ios7 / legacy
  reachable via ios.themeMode). javascript.native.theme still wins if
  set. If the modern .res is missing (partial build) the loader falls
  back to the legacy theme so the app still boots.

- scripts/build-native-themes.sh now mirrors the generated
  iOSModernTheme.res and AndroidMaterialTheme.res into
  Ports/JavaScriptPort/src/main/webapp/assets/ alongside the existing
  legacy .res files. .gitignore in that directory treats the mirrors
  as build artifacts (sources in native-themes/ stay authoritative).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR CI Java 8 quality gate flagged:
  ControlStatementBraces: CodenameOne/src/com/codename1/io/Util.java:226
  ControlStatementBraces: CodenameOne/src/com/codename1/io/Util.java:235

Rewrite the two "if (c == null) return;" one-liners with explicit braces.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Apr 22, 2026

✅ ByteCodeTranslator Quality Report

Test & Coverage

  • Tests: 644 total, 0 failed, 2 skipped

Benchmark Results

  • Execution Time: 10738 ms

  • Hotspots (Top 20 sampled methods):

    • 25.95% java.util.ArrayList.indexOf (491 samples)
    • 23.52% java.lang.String.indexOf (445 samples)
    • 18.23% com.codename1.tools.translator.Parser.isMethodUsed (345 samples)
    • 3.33% java.lang.Object.hashCode (63 samples)
    • 2.75% com.codename1.tools.translator.BytecodeMethod.optimize (52 samples)
    • 2.33% java.lang.System.identityHashCode (44 samples)
    • 2.06% com.codename1.tools.translator.ByteCodeClass.updateAllDependencies (39 samples)
    • 1.32% com.codename1.tools.translator.ByteCodeClass.calcUsedByNative (25 samples)
    • 1.16% com.codename1.tools.translator.BytecodeMethod.appendMethodSignatureSuffixFromDesc (22 samples)
    • 0.95% com.codename1.tools.translator.ByteCodeClass.markDependent (18 samples)
    • 0.85% java.lang.StringBuilder.append (16 samples)
    • 0.79% com.codename1.tools.translator.Parser.cullMethods (15 samples)
    • 0.74% com.codename1.tools.translator.bytecodes.Invoke.addDependencies (14 samples)
    • 0.74% sun.nio.fs.UnixNativeDispatcher.open0 (14 samples)
    • 0.74% com.codename1.tools.translator.Parser.getClassByName (14 samples)
    • 0.69% com.codename1.tools.translator.BytecodeMethod.appendCMethodPrefix (13 samples)
    • 0.63% com.codename1.tools.translator.BytecodeMethod.isMethodUsedByNative (12 samples)
    • 0.58% java.io.FileOutputStream.writeBytes (11 samples)
    • 0.53% com.codename1.tools.translator.ByteCodeClass.isDefaultInterfaceMethod (10 samples)
    • 0.53% com.codename1.tools.translator.Parser.generateClassAndMethodIndexHeader (10 samples)
  • ⚠️ Coverage report not generated.

Static Analysis

  • ✅ SpotBugs: no findings (report was not generated by the build).
  • ⚠️ PMD report not generated.
  • ⚠️ Checkstyle report not generated.

Generated automatically by the PR CI workflow.

@shai-almog
Copy link
Copy Markdown
Collaborator

shai-almog commented Apr 22, 2026

iOS screenshot updates

Compared 45 screenshots: 37 matched, 8 missing references.

  • ButtonTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ButtonTheme_dark.png.

    ButtonTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ButtonTheme_dark.png in workflow artifacts.

  • ButtonTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ButtonTheme_light.png.

    ButtonTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ButtonTheme_light.png in workflow artifacts.

  • CheckBoxRadioTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/CheckBoxRadioTheme_dark.png.

    CheckBoxRadioTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as CheckBoxRadioTheme_dark.png in workflow artifacts.

  • CheckBoxRadioTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/CheckBoxRadioTheme_light.png.

    CheckBoxRadioTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as CheckBoxRadioTheme_light.png in workflow artifacts.

  • TextFieldTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/TextFieldTheme_dark.png.

    TextFieldTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as TextFieldTheme_dark.png in workflow artifacts.

  • TextFieldTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/TextFieldTheme_light.png.

    TextFieldTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as TextFieldTheme_light.png in workflow artifacts.

  • ToolbarTheme_dark — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ToolbarTheme_dark.png.

    ToolbarTheme_dark
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ToolbarTheme_dark.png in workflow artifacts.

  • ToolbarTheme_light — missing reference. Reference screenshot missing at /Users/runner/work/CodenameOne/CodenameOne/scripts/ios/screenshots/ToolbarTheme_light.png.

    ToolbarTheme_light
    Preview info: Preview provided by instrumentation.
    Full-resolution PNG saved as ToolbarTheme_light.png in workflow artifacts.

Benchmark Results

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

Build and Run Timing

Metric Duration
Simulator Boot 99000 ms
Simulator Boot (Run) 1000 ms
App Install 20000 ms
App Launch 20000 ms
Test Execution 192000 ms

Detailed Performance Metrics

Metric Duration
Base64 payload size 8192 bytes
Base64 benchmark iterations 6000
Base64 native encode 2044.000 ms
Base64 CN1 encode 2313.000 ms
Base64 encode ratio (CN1/native) 1.132x (13.2% slower)
Base64 native decode 902.000 ms
Base64 CN1 decode 1243.000 ms
Base64 decode ratio (CN1/native) 1.378x (37.8% slower)
Base64 SIMD encode 701.000 ms
Base64 encode ratio (SIMD/native) 0.343x (65.7% faster)
Base64 encode ratio (SIMD/CN1) 0.303x (69.7% faster)
Base64 SIMD decode 454.000 ms
Base64 decode ratio (SIMD/native) 0.503x (49.7% faster)
Base64 decode ratio (SIMD/CN1) 0.365x (63.5% faster)
Image encode benchmark iterations 100
Image createMask (SIMD off) 68.000 ms
Image createMask (SIMD on) 11.000 ms
Image createMask ratio (SIMD on/off) 0.162x (83.8% faster)
Image applyMask (SIMD off) 194.000 ms
Image applyMask (SIMD on) 73.000 ms
Image applyMask ratio (SIMD on/off) 0.376x (62.4% faster)
Image modifyAlpha (SIMD off) 140.000 ms
Image modifyAlpha (SIMD on) 123.000 ms
Image modifyAlpha ratio (SIMD on/off) 0.879x (12.1% faster)
Image modifyAlpha removeColor (SIMD off) 234.000 ms
Image modifyAlpha removeColor (SIMD on) 69.000 ms
Image modifyAlpha removeColor ratio (SIMD on/off) 0.295x (70.5% faster)
Image PNG encode (SIMD off) 1399.000 ms
Image PNG encode (SIMD on) 1160.000 ms
Image PNG encode ratio (SIMD on/off) 0.829x (17.1% faster)
Image JPEG encode 518.000 ms

shai-almog and others added 4 commits April 23, 2026 03:43
Three user-reported issues fixed in one round:

1. Dark screenshots were actually light in every test.
   Root cause: UIManager caches resolved Style objects per UIID in
   styles/selectedStyles. A Style created while CN.isDarkMode()==false is
   the light variant; the cache then returns it on later lookups even
   after Display.setDarkMode(true) flips the flag. Components built on
   the fresh dark Form were picking up the cached light Style.
   Fix in DualAppearanceBaseTest: reflectively clear UIManager.styles and
   selectedStyles between appearance flips (and after the test finishes)
   so the next Component.initLaf -> UIManager.getComponentStyle goes
   through the full resolution path. shouldUseDarkStyle consults
   CN.isDarkMode() on every call and picks up the $Dark<UIID> entries
   emitted by the native themes' @media (prefers-color-scheme: dark)
   block.

2. iOS CheckBox / RadioButton disabled state looked weak.
   Previously only "color: #c7c7cc" was set on .disabled so the only
   visible change was a slightly lighter check glyph. Add a
   background-color: #e5e5ea (tertiary surface) for light and #2c2c2e
   for dark, plus an explicit transparent background on the default
   state. RadioButton also now inherits CheckBox's padding + base
   background instead of just deriving the label.

3. Test coverage was too thin (only Button/TextField/CheckBoxRadio/Toolbar).
   Added nine more theme-fidelity tests under scripts/hellocodenameone:
   - SwitchThemeScreenshotTest (OnOffSwitch default/on/disabled)
   - PickerThemeScreenshotTest
   - TabsThemeScreenshotTest
   - MultiButtonThemeScreenshotTest (1..4 line variants)
   - ListThemeScreenshotTest
   - DialogThemeScreenshotTest (inline Dialog/DialogBody/DialogTitle/
     DialogCommandArea to avoid modal animation flake)
   - FloatingActionButtonThemeScreenshotTest
   - SpanLabelThemeScreenshotTest
   - DarkLightShowcaseThemeScreenshotTest (mixed-components stress)
   All registered in Cn1ssDeviceRunner; each emits light+dark pair.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Android and JavaScript port builds flagged:
  SpanLabelThemeScreenshotTest.java:5 - cannot find symbol SpanLabel
  DarkLightShowcaseThemeScreenshotTest.java:9 - cannot find symbol SpanLabel
  DialogThemeScreenshotTest.java:9 - cannot find symbol SpanLabel
  PickerThemeScreenshotTest.java:5 - cannot find symbol Picker

SpanLabel lives in com.codename1.components, Picker in
com.codename1.ui.spinner - not com.codename1.ui. Update imports in all
four tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The JavaScript port bytecode-compliance check flagged
DualAppearanceBaseTest's reflective UIManager cache-clear as forbidden
API usage (Class.getDeclaredField, Field.setAccessible, Field.get are
not on the CN1-allowed surface). Also the wider concern: apps should
not need reflection to re-resolve styles after a Display.setDarkMode()
flip.

Added a tiny public API on UIManager:

  public void refreshTheme() {
      // snapshot current themeProps and re-run setThemePropsImpl,
      // which clears styles/selectedStyles/themeConstants/imageCache
      // and re-runs buildTheme against the current CN.isDarkMode().
  }

Using this instead of reflection in DualAppearanceBaseTest. Clean,
compliant, and generally useful for any CN1 app that wants to respond
to a dark-mode flip without reloading its theme from disk.

The previous commit (3bfcc05) found this via the JS port compliance
check, so the new tests already exercise the new API end-to-end.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CN1_JS_BROWSER_LIFETIME_SECONDS is 150s and
"Timed out waiting for CN1SS:SUITE:FINISHED" - the JS port ran the
13 new theme tests but never finished the whole suite, since each one
shows two forms sequentially at 1500ms each = ~3s per test, pushing
the cumulative time past the browser's budget. Mark the native-theme
fidelity tests to force-timeout in HTML5 the same way existing heavy
tests (MediaPlaybackScreenshotTest etc.) already do.

iOS, Android, and the JavaSE simulator runs each have their own
lifetime / timeout settings that comfortably fit the expanded suite
(JavaSE already validated green), so the visual coverage the user
cares about is preserved - JS is the odd one out.

Co-Authored-By: Claude Opus 4.7 (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.

RFE: Create an example of how to mimic the new liquid glass look and feel in CN1

2 participants