Repository navigation
CSSThemeCompiler: #Constants, font-size and box semantics matching the build-time compiler #6032
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+4,482
−223
Merged
Changes from all commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
63a6e38
CSSThemeCompiler: #Constants, font-size and box semantics matching th…
shai-almog 821dc2c
CSSThemeCompiler: color and image constants, state fonts inherit the …
shai-almog bc3cbf4
CSSThemeCompiler: constants in source order, var() color constants, d…
shai-almog 51a606e
CSSThemeCompiler: resolve var() before looking up an image constant
shai-almog 3435ab5
CSSThemeCompiler: defer image constants past rules, quote-aware rule …
shai-almog 6df549f
CSSThemeCompiler: rgba() and quoted constants, quote-aware comments, …
shai-almog 5a719cf
CSSThemeCompiler: every rule resolves var() against the final constants
shai-almog 2abd19c
CSSThemeCompiler: cn1rgb constants, literal aliases, state derives in…
shai-almog 8f097f3
CSSThemeCompiler: match the build-time compiler on ordering, * fonts,…
shai-almog 24a44eb
CSSThemeCompiler: per-compile constant typing, sibling-state derives,…
shai-almog 8e55384
CSSThemeCompiler: in-rule custom property order, last state derive wi…
shai-almog 6c955f3
CSSThemeCompiler: earlier compiles' constants stay text, same-state r…
shai-almog a58fdb4
CSSThemeCompiler: strip !important, keep system font families and ear…
shai-almog 0fd2f0d
CSSThemeCompiler: a quoted custom property stays a string token in st…
shai-almog b70aedb
CSSThemeCompiler: last derive wins for every state, build-time family…
shai-almog 25236ab
CSSThemeCompiler: #Constants aliases resolve where declared
shai-almog 81cdb2c
CSSThemeCompiler: #Constants in source order, var() fallbacks; CSSThe…
shai-almog 42597d5
CSSThemeCompiler: track the open quote for !important, reject #Consta…
shai-almog af0590d
CSSThemeCompiler: #Constants stores numbers as the build does, reject…
shai-almog 507d975
CSSThemeCompiler: keyword size keeps an inherited native family, font…
shai-almog 87578bd
CSSThemeCompiler: drop constants with an undefined var(), reject unte…
shai-almog c3768fb
CSSThemeCompiler: only --name declarations are variables, dark fonts …
shai-almog d9b8f3d
CSSThemeCompiler: a color or number named ...Image is not an image; i…
shai-almog e831d78
CSSThemeCompiler: #Constants aliases resolve against earlier declarat…
shai-almog 16e04f9
CSSThemeCompiler: a plain #Constants entry no longer hides a custom p…
shai-almog df69ee6
CSSThemeCompiler: a later :root property does not change an exported …
shai-almog e1200fb
CSSThemeCompiler: variables kept apart from exported constants, multi…
shai-almog e45c42d
CSSThemeCompiler: constant names must be identifiers, image aliases d…
shai-almog 43f32fd
CSSThemeCompiler: a direct multi-token constant exports its leading t…
shai-almog e5c2eda
CSSThemeCompiler: an image alias of a color or number is typed as one…
shai-almog 313a87d
GUI builder: cache canvas support per declaration value, not per prop…
shai-almog 63b9e91
CSSThemeCompiler: legacy @constants stay overridable, self-referencin…
shai-almog b0d26b2
CSSThemeCompiler: image constants look up their leading token; escape…
shai-almog 02bfc37
CSSThemeCompiler: quoted image names survive alias chains, escaped se…
shai-almog 450f107
CSSThemeCompiler: an escaped quote outside a string opens no string
shai-almog 1732c45
CSSThemeCompiler: dark font chains read only dark derives, #Constants…
shai-almog 58543d7
CSSThemeCompiler: escaped var() names decoded, --digit custom propert…
shai-almog c70b2e1
CSSThemeCompiler: a pressed-only derive inherits the target's normal …
shai-almog 3f2dd3e
CSSThemeCompiler: escaped alias targets decoded for type lookup; a da…
shai-almog 64d6855
CSSThemeCompiler: legacy @constants aliases stay live until the final…
shai-almog 259eb51
CSSThemeCompiler: quoted var() fallbacks stay text, escaped custom pr…
shai-almog 91cc7f3
CSSThemeCompiler: universal rules set no style property; a functional…
shai-almog 699f677
CSSThemeCompiler: a pressed derive wins over the owner's, a size-only…
shai-almog 82d95d8
CSSThemeCompiler: only CSS whitespace ends a hex escape inside a string
shai-almog daee10e
CSSThemeCompiler: a universal derive is ignored; a quoted image varia…
shai-almog 07e0d66
CSSThemeCompiler: quoted image fallbacks keep the whole name, image-n…
shai-almog 617245d
CSSThemeCompiler: escaped commas stay in a family name, an unsupporte…
shai-almog 83bef32
Merge remote-tracking branch 'origin/master' into css-theme-compiler-…
shai-almog 1e4c9c3
CSSThemeCompiler: nested quoted fallbacks stay text, an image constan…
shai-almog 269adfb
CSSThemeCompiler: a UIID's font reaches its selected, pressed and dis…
shai-almog acfbbe9
CSSThemeCompiler: an alias of a quoted constant keeps its text, not r…
shai-almog de92522
Merge remote-tracking branch 'origin/master' into css-theme-compiler-…
shai-almog 121c849
Baselines: take #6059's repair of #5976's merged overlays (rows maste…
shai-almog bfd6654
CSSThemeCompiler: fold CSS keywords, property names, colors and media…
shai-almog 588eee3
CSSThemeCompiler: carry unselected styles and derives into every stat…
shai-almog eb6822e
CSSThemeCompiler: prefix UIIDs for platform/density/device @media lik…
shai-almog 47fe448
CSSThemeCompiler: write @cn1-bind keys for var() colors, accept --var…
shai-almog fd264e6
CSSThemeCompiler: carry only the bare rule's values into states, drop…
shai-almog 5b88e8b
CSSThemeCompiler: compile .unselected as a layer over the bare rule, …
shai-almog f868e76
Baselines: calibrate linux binary size for the runtime CSS theme comp…
shai-almog c53c970
CSSThemeCompiler: use HashMap for the compile's own scratch maps
shai-almog File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
2,451 changes: 2,321 additions & 130 deletions
2,451
CodenameOne/src/com/codename1/ui/css/CSSThemeCompiler.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1,528 changes: 1,525 additions & 3 deletions
1,528
maven/core-unittests/src/test/java/com/codename1/ui/css/CSSThemeCompilerTest.java
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
155 changes: 155 additions & 0 deletions
155
maven/css-compiler/src/test/java/com/codename1/designer/css/RuntimeCompilerParityTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,155 @@ | ||
| /* | ||
| * Copyright (c) 2026, Codename One and/or its affiliates. All rights reserved. | ||
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | ||
| * This code is free software; you can redistribute it and/or modify it | ||
| * under the terms of the GNU General Public License version 2 only, as | ||
| * published by the Free Software Foundation. Codename One designates this | ||
| * particular file as subject to the "Classpath" exception as provided | ||
| * by Oracle in the LICENSE file that accompanied this code. | ||
| * | ||
| * This code is distributed in the hope that it will be useful, but WITHOUT | ||
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | ||
| * version 2 for more details (a copy is included in the LICENSE file that | ||
| * accompanied this code). | ||
| * | ||
| * You should have received a copy of the GNU General Public License version | ||
| * 2 along with this work; if not, write to the Free Software Foundation, | ||
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | ||
| * | ||
| * Please contact Codename One through http://www.codenameone.com/ if you | ||
| * need additional information or have any questions. | ||
| */ | ||
| package com.codename1.designer.css; | ||
|
|
||
| import com.codename1.ui.css.CSSThemeCompiler; | ||
| import com.codename1.ui.util.MutableResource; | ||
| import org.junit.jupiter.api.BeforeAll; | ||
| import org.junit.jupiter.api.Test; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.Arrays; | ||
| import java.util.Hashtable; | ||
|
|
||
| /** | ||
| * The runtime compiler in core ({@link CSSThemeCompiler}, used for live reload and by | ||
| * applications that build a theme on the device) against this one, on the declarations both | ||
| * support: the same sheet has to store the same constants, padding, margin and unit metadata. | ||
| */ | ||
| public class RuntimeCompilerParityTest { | ||
|
|
||
| private static final String CSS = "#Constants {\n" | ||
| + " includeNativeBool: true;\n" | ||
| + " customMessage: \"Hello\";\n" | ||
| + " quotedFlagBool: 'false';\n" | ||
| + " accentColor: #ff2d95;\n" | ||
| + " shortColor: #abc;\n" | ||
| + " switchTrackScaleY: 1.5;\n" | ||
| + " pctColor: rgb(100%, 0%, 50%);\n" | ||
| + " clampColor: rgb(200%, 300, 0);\n" | ||
| + "}\n" | ||
| + "Label { padding: 1px 2px 3px 4px; margin: 1mm 2mm; }\n" | ||
| + "One { padding: 5px; margin: 0.5mm; }\n" | ||
| + "Three { padding: 1mm 2px 3mm; }\n" | ||
| + "Mixed { padding: 1mm 2px 3pt 4mm; margin: 1px 2mm 3px 4mm; }\n" | ||
| + "Mixed.pressed { padding: 2mm 1mm; }\n" | ||
| + "Mixed.selected { margin: 3pt; }\n"; | ||
|
|
||
| @BeforeAll | ||
| static void installHeadlessImplementation() throws Exception { | ||
| HeadlessTestSupport.installHeadlessImplementation(); | ||
| } | ||
|
|
||
| @Test | ||
| void constantsMatch() throws Exception { | ||
| Hashtable standard = compileStandard(CSS); | ||
| Hashtable runtime = compileRuntime(CSS); | ||
| for (String key : new String[]{"@includeNativeBool", "@customMessage", "@quotedFlagBool"}) { | ||
| assertEquals(standard.get(key), runtime.get(key), key); | ||
| } | ||
| // Hex case differs between the compilers for every color, not just constants (the | ||
| // build-time one writes upper case); both are read with Integer.parseInt(value, 16). | ||
| for (String key : new String[]{"@accentColor", "@shortColor", "@pctColor", "@clampColor"}) { | ||
| assertEquals(Integer.valueOf(Integer.parseInt((String) standard.get(key), 16)), | ||
| Integer.valueOf(Integer.parseInt((String) runtime.get(key), 16)), key); | ||
| } | ||
| assertEquals("true", runtime.get("@includeNativeBool"), "@includeNativeBool"); | ||
| assertEquals("Hello", runtime.get("@customMessage"), "@customMessage"); | ||
| } | ||
|
|
||
| @Test | ||
| void spacingMatches() throws Exception { | ||
| Hashtable standard = compileStandard(CSS); | ||
| Hashtable runtime = compileRuntime(CSS); | ||
| String[] keys = { | ||
| "Label.padding", "Label.margin", "Label.padUnit", "Label.marUnit", | ||
| "One.padding", "One.margin", "One.padUnit", "One.marUnit", | ||
| "Three.padding", "Three.padUnit", | ||
| "Mixed.padding", "Mixed.margin", "Mixed.padUnit", "Mixed.marUnit", | ||
| "Mixed.press#padding", "Mixed.press#padUnit", | ||
| "Mixed.sel#margin", "Mixed.sel#marUnit"}; | ||
| for (String key : keys) { | ||
| Object expected = standard.get(key); | ||
| Object actual = runtime.get(key); | ||
| if (expected == null || actual == null) { | ||
| throw new AssertionError(key + " standard=" + expected + " runtime=" + actual); | ||
| } | ||
| if (expected instanceof byte[]) { | ||
| if (!Arrays.equals((byte[]) expected, (byte[]) actual)) { | ||
| throw new AssertionError(key + " units standard=" + Arrays.toString((byte[]) expected) | ||
| + " runtime=" + Arrays.toString((byte[]) actual)); | ||
| } | ||
| } else if (!Arrays.equals(floats((String) expected), floats((String) actual))) { | ||
| throw new AssertionError(key + " standard=" + expected + " runtime=" + actual); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private static float[] floats(String box) { | ||
| String[] parts = box.split(","); | ||
| float[] out = new float[parts.length]; | ||
| for (int i = 0; i < parts.length; i++) { | ||
| out[i] = Float.parseFloat(parts[i].trim()); | ||
| } | ||
| return out; | ||
| } | ||
|
|
||
| private static Hashtable compileRuntime(String css) { | ||
| MutableResource resource = new MutableResource(); | ||
| new CSSThemeCompiler().compile(css, resource, "Theme"); | ||
| return resource.getTheme("Theme"); | ||
| } | ||
|
|
||
| private static Hashtable compileStandard(String css) throws Exception { | ||
| Path cssFile = Files.createTempFile("cn1-parity", ".css"); | ||
| Path resFile = Files.createTempFile("cn1-parity", ".res"); | ||
| try { | ||
| Files.write(cssFile, css.getBytes(StandardCharsets.UTF_8)); | ||
| CSSTheme theme = CSSTheme.load(cssFile.toUri().toURL()); | ||
| theme.resourceFile = resFile.toFile(); | ||
| theme.res = new com.codename1.ui.util.EditableResourcesForCSS(resFile.toFile()); | ||
| theme.res.setTheme("Theme", new Hashtable()); | ||
| theme.updateResources(); | ||
| return theme.res.getTheme("Theme"); | ||
| } finally { | ||
| deleteIfExists(cssFile); | ||
| deleteIfExists(resFile); | ||
| } | ||
| } | ||
|
|
||
| private static void deleteIfExists(Path path) { | ||
| try { | ||
| Files.deleteIfExists(path); | ||
| } catch (IOException ignored) { | ||
| } | ||
| } | ||
|
|
||
| private static void assertEquals(Object expected, Object actual, String message) { | ||
| if (expected == null ? actual != null : !expected.equals(actual)) { | ||
| throw new AssertionError(message + " expected=" + expected + " actual=" + actual); | ||
| } | ||
| } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| { | ||
| "pr": 6032, | ||
| "rebaseline": { | ||
| "linux": { | ||
| "gallery": { | ||
| "code_bytes": { | ||
| "from": { | ||
| "value": 14523602 | ||
| }, | ||
| "reason": "CSSThemeCompiler (runtime CSS theme compiler in core) gained build-compiler parity: state inheritance, per-side insets, media prefixes, var() bindings, the CSS named-color table", | ||
| "runs": 1, | ||
| "value": 14592242 | ||
| }, | ||
| "install_bytes": { | ||
| "from": { | ||
| "value": 116342496 | ||
| }, | ||
| "reason": "CSSThemeCompiler (runtime CSS theme compiler in core) gained build-compiler parity: state inheritance, per-side insets, media prefixes, var() bindings, the CSS named-color table", | ||
| "runs": 1, | ||
| "value": 116468448 | ||
| }, | ||
| "wire_bytes": { | ||
| "from": { | ||
| "value": 84685068 | ||
| }, | ||
| "reason": "CSSThemeCompiler (runtime CSS theme compiler in core) gained build-compiler parity: state inheritance, per-side insets, media prefixes, var() bindings, the CSS named-color table", | ||
| "runs": 1, | ||
| "value": 84687971 | ||
| } | ||
| } | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.