Releases: TIMER-err/qml4j
Release list
qml4j 0.2.32
What's Changed
- Add Text.style/styleColor/styleWidth for outlined/raised/sunken text by @Ink-Stained-Clouds in #16
Full Changelog: v0.2.29...v0.2.32
qml4j 0.2.31
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
What's Changed
- feat:
Text.style/styleColor/styleWidthfor outlined/raised/sunken text effects (#16) - ci: update Java setup action, pin Qodana 2026.2, clear Qodana resource warnings
qml4j 0.2.29
Performance and resource management
- Allocate
Propertylistener storage lazily and store single listeners without anArrayList, substantially reducing large QML scene heaps. - Deterministically close cached Skija
Font,Typeface, and temporaryDataresources when fonts are replaced or the renderer is disposed. - Add regression coverage for listener storage and font resource ownership.
v0.2.27
What's Changed
- fix(render): support independent per-corner radii on
Rectangleby @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
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
v0.2.24
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
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.pumpLayouttest 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
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