Skip to content

Releases: TIMER-err/qml4j

qml4j 0.2.32

Choose a tag to compare

@TIMER-err TIMER-err released this 30 Aug 07:26

What's Changed

Full Changelog: v0.2.29...v0.2.32

qml4j 0.2.31

Choose a tag to compare

@Ink-Stained-Clouds Ink-Stained-Clouds released this 29 Aug 01:03

What's Changed

  • feat: real per-pixel MultiEffect masking (source composited against the mask subtree's own rendered alpha via DST_IN, instead of an approximated rounded-rect clip)
  • feat: MultiEffect maskThresholdMin/maskThresholdMax/maskSpreadAtMin/maskSpreadAtMax, ported from Qt's actual threshold/spread formula
  • feat: MultiEffect shadowEnabled + maskEnabled now compose correctly (shadow generated from the source, then the whole result masked -- matching Qt's shader order)
  • feat: MultiEffect blur/brightness/contrast/saturation/colorization now apply (blur via a real Gaussian; colour grading is an exact port of Qt's per-pixel formula)
  • feat: persistent compiled scene cache

qml4j 0.2.30

Choose a tag to compare

@Ink-Stained-Clouds Ink-Stained-Clouds released this 27 Aug 15:15
deece0f

What's Changed

  • feat: Text.style/styleColor/styleWidth for outlined/raised/sunken text effects (#16)
  • ci: update Java setup action, pin Qodana 2026.2, clear Qodana resource warnings

qml4j 0.2.29

Choose a tag to compare

@TIMER-err TIMER-err released this 24 Aug 05:37

Performance and resource management

  • Allocate Property listener storage lazily and store single listeners without an ArrayList, substantially reducing large QML scene heaps.
  • Deterministically close cached Skija Font, Typeface, and temporary Data resources when fonts are replaced or the renderer is disposed.
  • Add regression coverage for listener storage and font resource ownership.

v0.2.27

Choose a tag to compare

@TIMER-err TIMER-err released this 17 Aug 03:26

What's Changed

  • fix(render): support independent per-corner radii on Rectangle by @dwgx in #15
  • perf(canvas): add a batched sine-wave path API that preserves the existing sampled geometry while avoiding hundreds of JavaScript-to-Java calls per frame
  • perf(md3): move the wavy linear progress path generation onto the batched Canvas fast path, reducing Android allocation rate and GC pressure
  • test(canvas): verify track, determinate-tip, and indeterminate-segment path commands bit-for-bit against the previous QML loops

Full Changelog: v0.2.26...v0.2.27

v0.2.26

Choose a tag to compare

@TIMER-err TIMER-err released this 28 Jul 15:01

What's Changed

  • fix(input): fail closed when a masked field's text would leave the process by @dwgx in #8
  • fix(quality): silence the Qodana findings on the echoMode reader by @dwgx in #10
  • fix(quality): read echoMode through a parameter, not a widened local by @dwgx in #11
  • fix(desktop): release resources and exit 0 on non-Linux hosts by @dwgx in #9
  • fix(input): stop PasswordEchoOnEdit revealing text it should not by @dwgx in #12
  • fix(input): a refused copy no longer clobbers the clipboard by @dwgx in #13

Full Changelog: v0.2.25...v0.2.26

v0.2.25

Choose a tag to compare

@TIMER-err TIMER-err released this 28 Jul 01:48

What's Changed

  • fix(input): clamp selection indices before taking a substring by @dwgx in #6
  • fix(run): launch the JDK that JAVA_HOME selects, with the macOS first thread by @dwgx in #7

Full Changelog: v0.2.24...v0.2.25

v0.2.24

Choose a tag to compare

@TIMER-err TIMER-err released this 24 Jul 14:23
e53388a

What's Changed

  • feat(desktop): add macOS native profiles by @dwgx in #4
  • fix(text): WordWrap should break between CJK characters, not just at spaces by @Ink-Stained-Clouds in #5

Full Changelog: v0.2.23...v0.2.24

v0.2.23

Choose a tag to compare

@TIMER-err TIMER-err released this 20 Jul 14:17

qml4j 0.2.23

Fix: a colour-hex string keeps its String methods in JS

A Java String that happens to match a hex-colour pattern (e.g. "#ff33aa55") is wrapped as
JsColor when it crosses into JS. JsColor previously exposed only .r/.g/.b/.a and returned
NOT_FOUND for every other member, so any ordinary string op on it -- charAt, substring,
indexOf, length, ... -- was undefined. Calling one inside a compiled QML function body
silently aborted the rest of the function with no exception, making the failure invisible
(a colour picker seeding HSV from a "#aarrggbb" model value would just do nothing).

JsColor now falls back to the underlying hex String's String.prototype members (named and
indexed) for anything that isn't an r/g/b/a channel, so a colour-hex value behaves as both
a colour (channels) and a string (methods/length). "#ff33aa55".charAt(0) === "#",
.length === 9, etc. No app-side "" + hex coercion needed anymore.

Also

  • Removed the unused QmlView.pumpLayout test hook (its callers went with the incremental
    layout removed in 0.2.22).

Compatibility

No API breakage. New test JsColorStringMethodTest; 604 tests green.

Full Changelog: v0.2.22...v0.2.23

v0.2.22

Choose a tag to compare

@TIMER-err TIMER-err released this 20 Jul 09:47

qml4j 0.2.22

Crisp raster in the picture cache at high DPI

The per-boundary SkPicture cache recorded subtrees in logical coordinates, so a raster
backing inside a cached boundary (a Canvas FBO, a saveLayer/layer.effect offscreen, a
blur/DropShadow/Glow) rasterized at logical size and was upscaled on replay -> blurry at high
DPI (crisp while animating, soft once cached). Boundaries are now recorded at the target
canvas' device scale (rc.scale(sf)), replayed with scale(1/sf), and a GUI-scale / DPI
change forces one re-record. Net size/position is unchanged; vector content stays pixel-exact.
Downstream can now enable setPictureCache on Canvas/effect views too.

Incremental layout removed -> always whole-tree measure

The Qt-style per-Item incremental (polish-queue) layout is gone. It had a first-appearance
reflow bug (a collapsed section expanded for the first time with a nested RowLayout landed
at y=0 / didn't grow until a full relayout), and measure was never the frame-rate bottleneck
(draw is, which the picture cache targets). The whole tree is measured every settle again, with
the existing multi-pass binding-settle loop and the opt-in Item.cachedLayout static-subtree
fast path. Removed: PolishQueue, Renderer.setIncrementalLayout / requestFullLayout /
settleLayoutIncremental / measureSelf, Item dirty bits + markLayout* + anchor-dependent
tracking + layoutDerivesSizeFromChildren, and the -Dqml4j.incrementalLayout flag. Hosts that
set setIncrementalLayout(false) can drop the call -- it's now the only behaviour.

Code-quality sweep (Qodana)

Resolved the full Qodana report: folded manual min/max, removed redundant type args/casts,
migrated deprecated skija APIs (makeFromEncoded -> makeDeferredFromEncodedBytes,
makeRasterN32Premul -> makeRaster(ImageInfo.makeN32Premul)), and suppressed justified false
positives. Includes a real fix: Renderer.culled() leaked a native Paint per frame for
layer-effected nodes (allocated via layerEffectPaint and discarded) -- now closed.

Compatibility

No consumer API breakage beyond the removed opt-in incremental-layout knobs. The draw-phase
picture cache remains opt-in (-Dqml4j.pictureCache=true), off by default.

Tests

603 green. New device-scale coverage (deviceScaleRecordedAndInvalidatesOnScaleChange,
highDpiVectorPixelsMatchDirectPaint). Incremental-layout tests removed with the feature.

Full Changelog: v0.2.21...v0.2.22