Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
844ee33
fix(sdk): add illegal state cause constructors
flsobral Jul 22, 2026
ff829dd
refactor(sdk): relocate illegal state compatibility class
flsobral Jul 22, 2026
894febb
build(android): package modular TCZ runtime files
flsobral Jul 22, 2026
16c9e4e
docs(vm): record skia image baseline
flsobral Jul 23, 2026
9bf9fae
refactor(vm): relocate skia sources
flsobral Jul 23, 2026
24ca5c8
docs(vm): record skia relocation
flsobral Jul 23, 2026
627dcf6
refactor(vm): split skia rendering sources
flsobral Jul 23, 2026
6c840cd
refactor(vm): own skia image surfaces together
flsobral Jul 23, 2026
2a8e8c1
fix(vm): route skia drawing to target surfaces
flsobral Jul 23, 2026
72bec9d
docs(vm): record skia surface milestone
flsobral Jul 23, 2026
14082b5
fix(vm): make skia bitmap authoritative
flsobral Jul 23, 2026
5973bd8
fix(vm): draw image surfaces through skia
flsobral Jul 23, 2026
4933637
docs(vm): record skia authority milestone
flsobral Jul 23, 2026
3c20258
test(vm): add issue 417 image smoke test
flsobral Jul 23, 2026
f06182c
docs(vm): record issue 417 smoke milestone
flsobral Jul 23, 2026
3d9127e
docs(vm): reconcile skia execplan report
flsobral Jul 23, 2026
0ef5417
docs(vm): finalize skia execplan state
flsobral Jul 23, 2026
9010988
fix(vm): correct skia pixel color order
flsobral Jul 23, 2026
84b618d
test(vm): harden generated image smoke test
flsobral Jul 23, 2026
7187910
docs(vm): record final skia matrix
flsobral Jul 23, 2026
8b469ab
chore(agents): align skills with repository rules
flsobral Jul 25, 2026
0fe70d5
fix(ci): detect renamed source files
flsobral Jul 25, 2026
2ef7059
fix(ci): preserve history for moved files
flsobral Jul 25, 2026
08c9c95
fix(vm): remove duplicate skia swap helper
flsobral Jul 25, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions .agent/evidence/skia-generated-image.jsonl

Large diffs are not rendered by default.

798 changes: 798 additions & 0 deletions .agent/exec-plan-skia-generated-image.md

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions .agent/reports/skia-generated-image-editorial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!--
Copyright (C) 2026 Amalgam Solucoes em TI Ltda

SPDX-License-Identifier: LGPL-2.1-only
-->

# Editorial Report: Skia Generated Image

Issue 417 was reproduced from the attached `Tcsort.zip`: the Android
baseline exported the 576x576 `MonoImage` as a fully transparent PNG despite
the white fill and black inset border. The checked-in smoke test preserves
that exact `MonoImage`/`getGraphics()`/drawing/`createPng()` flow.

The fix gives generated images an owned `SkBitmap`/`SkCanvas` pair, promotes
the Java array only once, and routes drawing, pixel, RGB, row, image-to-image,
and PNG output through the authoritative Skia surface. Array-only transforms
such as scale, rotate, and color transforms remain outside this issue path.
Pixel conversion is explicit scalar ARGB, independent of host byte order.

## Final matrix

The corrected smoke passed on all three requested targets from one revision:

- Java SE: `java-byte-array`, checker passed, process exit 0.
- macOS arm64: `native-skia`, checker passed, process exit 0.
- Android emulator `emulator-5554`: `native-skia`, APK deployment and checker
passed. The app was force-stopped after artifact collection to avoid the
asynchronous Android loader teardown race documented in the smoke README.

The macOS headless Ninja configuration reports `Settings.platform=Linux` in
the JSON, although the executable and native library are macOS arm64. Java SE
also emitted a non-fatal optional telemetry `NoClassDefFoundError` for
`net.harawata.appdirs.AppDirsFactory`.

Final source sizes: `skia.cpp` 351 lines, `skia_surface.cpp` 233,
`skia_primitives.cpp` 279, `GraphicsPrimitives_c.h` 1,507,
`GraphicsPrimitivesSkia_c.h` 418, `Tcsort.java` 171, and `check_result.py`
65.

The Android blank baseline and all final artifact paths/hashes are recorded in
`.agent/evidence/skia-generated-image.jsonl`. No later milestone validations
were run.
46 changes: 46 additions & 0 deletions .agent/state/skia-generated-image.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!--
Copyright (C) 2026 Amalgam Solucoes em TI Ltda

SPDX-License-Identifier: LGPL-2.1-only
-->

# Estado do ExecPlan Skia Generated Image

Milestone ativo: nenhum; a matriz final foi concluída em 2026-07-23.

O caminho solicitado no prompt, `.agent/state/exec-plan-skia-generated-image.md`,
continua ausente. Este arquivo é o estado canônico referenciado pelo próprio
ExecPlan.

Commits lógicos desta retomada:

- `90109883a fix(vm): correct skia pixel color order`
- `84b618d93 test(vm): harden generated image smoke test`

Resultado da matriz final, executada a partir da mesma revisão do smoke:

- Java SE: passou; checker `java-byte-array`, exit 0;
- macOS arm64: passou; checker `native-skia`, exit 0;
- Android `emulator-5554`: passou; APK implantado, checker `native-skia` passou.

No Android, o app foi parado externamente depois da coleta. `MainWindow.exit`
podia correr contra o teardown assíncrono do loader e abortar ao bloquear um
mutex destruído; os artefatos já estavam completos e o novo procedimento não
produziu novo crash. No macOS headless, o JSON informa `Settings.platform` como
`Linux` por causa da configuração Ninja/CMake, embora o binário seja macOS
arm64 e use `native-skia`. Java SE emitiu apenas o erro não fatal de telemetria
opcional `NoClassDefFoundError: net/harawata/appdirs/AppDirsFactory`.

Validações executadas nesta retomada:

- build nativo macOS arm64 com CMake/Ninja: passou;
- `:tcvm:fetchNativeDependencies`: passou;
- `:tcvm:externalNativeBuildCleanRelease`: passou;
- `:app:assembleStandardRelease`: passou;
- compilação/deployment/runtime/checker Java SE: passou;
- compilação/deployment/runtime/checker macOS: passou;
- compilação/deployment/runtime/checker Android: passou;
- `git diff --check`: passou.

Logs e artefatos detalhados estão em `.agent/evidence/skia-generated-image.jsonl`.
Não foram executadas validações de milestones posteriores.
137 changes: 137 additions & 0 deletions .agents/skills/logical-commits/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
---
# Copyright (C) 2026 Amalgam Solucoes em TI Ltda
#
# SPDX-License-Identifier: LGPL-2.1-only

name: logical-commits
description: Create focused Git commits that follow this repository's validated commit-message format, with required scopes, focused validation, and preservation of unrelated local changes; invoke only when the user asks to commit or an active ExecPlan explicitly requires commits.
---

# Commit logical repository changes

This skill changes Git state. Confirm that committing is explicitly requested by the user or required by an active ExecPlan whose execution was requested.

1. Read the active ExecPlan state first when executing an ExecPlan. Determine
the current functional slice and intended paths. Follow `.agent/PLANS.md`
when a plan is present.

2. Inspect scoped changes:

git status --short -- <task paths>
git diff --stat -- <task paths>
git diff -- <task paths>

Inspect staged changes separately. Do not run destructive cleanup and do not include unrelated modifications.

3. Split changes by behavior or contract, not by file count. Suitable commit boundaries include:

- one shared interface plus its focused tests;
- one platform-family migration;
- one dependency scaffold and its documentation;
- one release-policy change and its idempotence tests;
- one follow-up fix discovered by validation.

Do not create a commit for formatting-only fragments that belong to the same functional change. Do not combine architecture, unrelated cleanup, generated artifacts, and documentation for another feature.

4. Before each commit, run the `validate-headers` skill and the smallest
validation sufficient for that slice. Always run:

git diff --check --cached

Save verbose build output to a log and record only a compact summary.

5. Stage only intended paths:

git add -- <paths>

Review:

git diff --cached --stat
git diff --cached -- <paths>

6. Write an English commit message in the repository's
Conventional-Commits-inspired format:

<type>(<scope>): imperative description
<type>(<scope>,<platform>): imperative description
<type>!(<scope>[,<platform>]): imperative description
<type>(<scope>[,<platform>])!: imperative description

Use only these types: `fix`, `feat`, `refactor`, `perf`, `style`, `test`,
`docs`, `build`, `ci`, `chore`, or `revert`. The scope is required and may
contain letters, numbers, underscores, and hyphens. The optional platform
must be lowercase and is the second qualifier. Architecture is not a title
qualifier; mention it in the body instead.

The title must be English, start with a lowercase letter, use the
imperative mood, contain at least three words, be at most 80 characters,
and not end with a period. If there is a body, separate it from the title
with one blank line. Keep every body line at 80 characters or less; the CI
check ignores Markdown link URLs when measuring body lines.

For every non-trivial change, add a body that explains:

- why the change is needed;
- what behavior or contract changes;
- platform, compatibility, artifact, or release impact;
- focused validation completed and important deferrals.

Example:

refactor(build): centralize native target policy

Resolve Android, Linux, and Windows platform settings from the shared
native-build configuration so workflows and explicit target wrappers no
longer repeat toolchain values.

Keep minizip on Android API 24 while the default remains API 23. Validate
configuration resolution and the zlib build-only workflow.

For breaking changes, put `!` in the title and add a `BREAKING CHANGE:`
footer describing the compatibility impact. For `revert` commits, name the
reverted commit hash or hashes in the body.

7. Commit without amending or rewriting history unless explicitly requested.

8. Validate the created commit message against the same rules embedded in
`.github/workflows/commit.yml`. There is no standalone repository script;
run this focused local check:

python3 - <<'PY'
import re
import subprocess
import sys

message = subprocess.check_output(["git", "show", "-s", "--format=%B", "HEAD"], text=True).rstrip("\n")
title = message.split("\n", 1)[0]
title_format = re.compile(
r"^(fix|feat|refactor|perf|style|test|docs|build|ci|chore|revert)"
r"(!\([A-Za-z0-9_-]+(,[a-z0-9_-]+)?\)|"
r"\([A-Za-z0-9_-]+(,[a-z0-9_-]+)?\)!?): [a-z0-9 ].*$"
)
link_urls_removed = lambda line: re.sub(r"\[([^\]]*)\]\([^)]+\)", r"\1", line)
failures = []
if not title_format.match(title): failures.append("invalid title format")
if re.search(r"[A-Z]", title[:1]): failures.append("title starts uppercase")
if not re.match(r"^[^ ]+([ \t]+[^ ]+){2,}$", title): failures.append("title has fewer than 3 words")
if len(title) > 80: failures.append("title exceeds 80 characters")
if title.endswith("."): failures.append("title ends with a period")
if len(message) > len(title) and not message.startswith(title + "\n\n"):
failures.append("body is not separated by a blank line")
if any(len(link_urls_removed(line)) > 80 for line in message.split("\n")[1:]):
failures.append("body line exceeds 80 characters")
if failures:
print("; ".join(failures), file=sys.stderr)
sys.exit(1)
print("Commit message validation passed.")
PY

This mirrors the workflow's structural checks for the current `HEAD`.
Keep the title and body in English and use the repository's imperative
wording convention; CI remains the authoritative automated check.

9. Update the active ExecPlan state after the logical commit. Update the active
plan only when this commit reaches a functional-family, architecture, ABI,
release-policy, or milestone checkpoint.

10. Report the commit hash, subject, paths, focused validations, and any deferred expensive validation. Do not push unless explicitly requested.
10 changes: 10 additions & 0 deletions .agents/skills/logical-commits/agents/openai.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Copyright (C) 2026 Amalgam Solucoes em TI Ltda
#
# SPDX-License-Identifier: LGPL-2.1-only

interface:
display_name: "Logical repository commits"
short_description: "Create validated logical repository commits"
default_prompt: "Use $logical-commits to prepare a focused, validated commit."
policy:
allow_implicit_invocation: false
70 changes: 70 additions & 0 deletions .agents/skills/validate-headers/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
---
# Copyright (C) 2026 Amalgam Solucoes em TI Ltda
#
# SPDX-License-Identifier: LGPL-2.1-only

name: validate-headers
description: Validate the repository's LGPL-2.1-only copyright headers on changed or staged first-party files before a commit; use for new files, header fixes, or copyright-check failures, not for generated or vendored artifacts.
---

# Validate changed-file headers

Use the repository validator from the repository root and the narrowest file set
that matches the intended commit. This repository uses LGPL-2.1-only headers;
do not introduce a different license identifier in first-party files.

1. Identify the scope without dumping the whole worktree:

git diff --name-only --diff-filter=ACMR --cached -- <task paths>

If nothing is staged, inspect the intended working-tree paths with:

git diff --name-only --diff-filter=ACMR -- <task paths>

2. Respect the exclusions implemented by
`scripts/validate-copyright-headers.sh` and documented in `AGENTS.md`.
In particular, skip `TotalCrossVM/deps/`, `build/`,
`TotalCrossSDK/src/main/java/totalcross/util/regex/`, and
`TotalCrossSDK/src/main/java/totalcross/db/sqlite/`, except for
`SQLiteUtil.java` and `ui/DBListBox.java`. The validator also ignores
unsupported file types and `.agent/PLANS.md`. Do not add repository headers
to upstream, vendored, generated, or exempt files merely to make validation
pass.

3. Prefer changed-file validation when the validator supports it:

python3 scripts/validate-copyright-headers.sh --files <changed files>

For staged changes, omit `--files` so the validator discovers the staged
paths (or the working-tree diff when nothing is staged):

python3 scripts/validate-copyright-headers.sh

It also accepts `--commit <commit>`, or a base and head commit as positional
arguments. Save verbose output to a temporary log when the file set is
broad, and report only failures relevant to the intended change.

4. Fix headers with the comment style appropriate to the file. New
first-party files use the current year and:

// Copyright (C) 2026 Amalgam Solucoes em TI Ltda
//
// SPDX-License-Identifier: LGPL-2.1-only

Use `#` for shell, Python, Ruby, and YAML files, and an HTML comment for
Markdown and HTML files. A Markdown skill with YAML frontmatter keeps the
repository header as YAML comments inside the frontmatter so the metadata
remains valid.

For existing files, preserve historical ownership: SuperWaba ranges end in
2013, TotalCross ranges end in 2021, and Amalgam covers 2022 through the
current year. For files created from 2014 through 2021, the TotalCross range
starts in the Git creation year. For files created from 2000 through 2013,
retain the SuperWaba, TotalCross, and Amalgam sequence required by
`AGENTS.md`.

5. Rerun the focused check and `git diff --check -- <task paths>`.

6. Report only the files checked, pass/fail status, and log path. Do not paste the full repository validation output.

Do not stage, commit, amend, or push unless the user explicitly requests those actions or the active ExecPlan requires a commit checkpoint.
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Copyright (C) 2000-2013 SuperWaba Ltda.
// Copyright (C) 2014-2021 TotalCross Global Mobile Platform Ltda.
// Copyright (C) 2022-2026 Amalgam Solucoes em TI Ltda
//
// SPDX-License-Identifier: LGPL-2.1-only

package jdkcompat.lang;

public class IllegalStateException4D extends RuntimeException {
static final long serialVersionUID = -1848914673093119416L;

public IllegalStateException4D() {
}

public IllegalStateException4D(String message) {
super(message);
}

public IllegalStateException4D(String message, Throwable cause) {
super(message, cause);
}

public IllegalStateException4D(Throwable cause) {
super(cause);
}
}

This file was deleted.

4 changes: 3 additions & 1 deletion TotalCrossVM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,9 @@ endif(NOT MSVC)

if(TCVM_ENABLE_SKIA)
set(TC_SKIA_SOURCES
${TC_SRCDIR}/nm/ui/android/skia.cpp
${TC_SRCDIR}/nm/ui/skia/skia.cpp
${TC_SRCDIR}/nm/ui/skia/skia_surface.cpp
${TC_SRCDIR}/nm/ui/skia/skia_primitives.cpp
)
endif(TCVM_ENABLE_SKIA)

Expand Down
Loading
Loading