Detect unbalanced Graphics state in the simulator (#5058)#5060
Merged
Conversation
The simulator now wraps each user-overrideable paint dispatch (Component.paint, paintBackground, Painter.paint, Form glass pane) in a begin/end scope. On exit it verifies the Graphics is in the same state it entered (clip stack depth, clip rect, transform, color, font, composite/alpha) and auto-restores any drift while logging a warning that names the offending component. JavaSEPort.popClip also throws IllegalStateException when there is no matching pushClip, catching the leak at its source. The hook is a no-op default on CodenameOneImplementation, so device ports pay nothing (one virtual call to an empty method per scope, inlinable by the iOS C compiler / Android JIT). Disable with -Dcn1.disable.paint.scope.checks=true if needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Compared 11 screenshots: 11 matched. |
Contributor
✅ Continuous Quality ReportTest & Coverage
Static Analysis
Generated automatically by the PR CI workflow. |
Contributor
Cloudflare Preview
|
Collaborator
Author
|
Compared 45 screenshots: 45 matched. |
Collaborator
Author
|
Compared 116 screenshots: 116 matched. Native Android coverage
✅ Native Android screenshot tests passed. Native Android coverage
Benchmark ResultsDetailed Performance Metrics
|
Collaborator
Author
|
Compared 115 screenshots: 115 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
input-validation.yml computed its own cn1-built cache key with a different file set than _build-ios-port.yml saves under (e.g. no svg-transcoder/src/main), so the restore always missed with fail-on-cache-miss whenever a PR touched a file in the workflow's paths filter (Component.java, Form.java, ...). Reuse the cn1_built_cache_key output from build-port the way scripts-ios.yml already does. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Collaborator
Author
|
Compared 116 screenshots: 116 matched. Benchmark Results
Build and Run Timing
Detailed Performance Metrics
|
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
beginPaintScope/endPaintScopehooks onCodenameOneImplementation(no-op default; one virtual call per scope on device, inlinable on iOS / JIT'd on Android).Component.paint,Component.paintBackground,Painter.paint, and theFormglass pane are now wrapped in begin/end scopes.JavaSEPortoverrides those hooks to snapshot Graphics state (clip-stack depth, clip rect, transform, color, font, composite/alpha) and on scope exit:JavaSEPort.popClipnow throwsIllegalStateExceptionwhen there is no matchingpushClip, catching the bug at its source instead of silently no-oping and surfacing as a crash on iOS many frames later — which is what happened in crash in IOS graphics - probably a regression #5058.Disable with
-Dcn1.disable.paint.scope.checks=trueif a third-party component triggers false positives.The device ports are untouched: the base impl's
beginPaintScope/endPaintScopeare empty methods, andpopClipkeeps its existing behaviour on every non-JavaSE port.Test plan
mvn test -Plocal-dev-javase -pl core,javase(70 tests, all green)PaintScopeTestcovers: excess pop throws, scope auto-restores stack depth / transform / color, nested scopes pop LIFO, clean scope is silent🤖 Generated with Claude Code