rust_widgets 2.0.0

Pure Rust cross-platform native GUI library with hardware-adaptive rendering, 60+ widgets, touch/gesture support, i18n, and SVG-pipeline-accurate output
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
# Changelog

All notable changes to this project are documented in this file.

## 2.0.0 (2026-09-14) — Self-Drawn Controls Everywhere (BLUE15)

A major release that completes the move to a **fully self-drawn** architecture. Every
platform backend used to build native OS controls alongside the Rust renderer; now all
ten backends build none. The library paints 100% of its own controls, so a control is
pixel-identical on every platform, needs no GUI toolkit linked, and works on targets
with no operating system at all.

The release also collapsed the property layer onto a per-control contract (deleting a
535-arm centralised dispatch), removed the duplicated platform probes and date/text
helpers, and replaced 117 hand-written `Default` impls with a macro — **net −2,288 lines
of source**, with no capability removed and four new mechanical contract gates added.

Full detail, with reproduction commands, is in
[docs/log/log-20260914-1.md](log/log-20260914-1.md).

### ⚠️ Breaking changes

#### 1. No native control construction on any platform

Every backend's native control constructor implementations were deleted. `fn create_*`
**implementations** in `src/platform/**` went from **606 → 0**, across all ten backends:

| Backend | Removed |
|---|---|
| Windows | `CreateWindowExW`-based control creation |
| macOS (cocoa + objc2) | `NSButton` / `NSTextView` / `NSComboBox` construction |
| Linux GTK | `gtk_button_new` and siblings |
| Wayland | xdg-shell control surfaces |
| iOS | `UIButton` / `UILabel` / `UITextField` |
| Android | `android.widget.*` via JNI |
| Harmony / WASM | state-backed control records |

**Migration:** controls are created through the control backend / `WidgetFactory`:

```rust
let factory = WidgetFactory::new_with_defaults();
let mut button = factory.create("button", Rect::new(10, 10, 100, 30), "OK").unwrap();
```

Controls are still addressed by id; only their construction moved.

> **Note on `Platform::create_*`.** The 42 trait *declarations* are kept, each with a
default that returns `0` and documents why. They are not removed because a backend
that genuinely owns a native primitive can still opt in deliberately, in one place,
without an API change — and because returning `0` is the honest answer, whereas a
constructor that reported success while creating nothing is the dishonesty the
defaults exist to remove. **No shipped backend overrides any of them.**

A backend now owns exactly four things: a surface, the event loop, input translation,
and platform services (IME, clipboard, accessibility, native menus, file dialogs, DPI).

> **The C ABI is unaffected.** `rw_create_button` and its 21 siblings, `rw_set_widget_text`,
> `rw_get_widget_text` and the rest of the `rw_*` surface still exist and still work —
> they are the control-backend API's C face, not the platform backends'.
> `rw_bindings_api_version` remains `8`.

#### 2. The property layer is per-control

Every control implements `WidgetProperties` in its own file. The centralised
`read_widget_property_legacy` / `write_widget_property_legacy` dispatch — 18 include
files, **535 match arms**, and the 98 imports that only it used — was deleted, because
it restated the contract for 39 controls and the two copies had already drifted.

**Migration:** read and write through `WidgetFactory::{read_property, write_property}`,
or the id-level `read_widget_property_by_id` / `write_widget_property_by_id`.
`Platform::get_*`/`set_*` control-property methods are gone.

#### 3. `Platform` de-controlified — 75 required methods → 6

The removed methods now have honest defaults reporting `UnsupportedOnWidget` / `None`
for a capability the host lacks, rather than a write that reports success without taking
effect.

#### 4. `NativeCapabilityContract` is now a type alias

`pub type NativeCapabilityContract = PlatformCapabilities;`. The two held the same five
flags and were kept in step by a field-by-field copy — the classic way such a pair
drifts. The name is unchanged; `from_platform_caps` is gone.

#### 5. Unused public modules deleted

Each had **zero** references in `src/`, `tests/`, `examples/` and `tools/`, verified
before removal:

| Removed | Was reachable as | Use instead |
|---|---|---|
| `platform::detector` | `DeviceEnvironment` (406 lines) ||
| `platform::virtual_keyboard` | `VirtualKeyboard` (331 lines) ||
| `render::text_cache` | `TextCache` / `GlyphCache` (318 lines) ||
| `style::css_watcher` | `CssWatcher` (206 lines) ||
| `util::asset_watcher` | re-export shim | `crate::asset::{AssetWatcher, AssetEvent}` |
| `widget::image` | re-export shim | `crate::image::{Image, ImageFormat}` |
| `platform::ime_stubs` | doc-comment-only file | `platform::ime_windows` / `ime_macos` |
| `widget::overlay_widgets::pull_to_refresh` | duplicate alias | `widget::PullToRefresh` |

Also deleted: four `macos_objc2` modules that contained only an SPDX header
(`clipboard_dnd`, `dialog_creation`, `menu_impl`, `widget_state`).

#### 6. Android Java binding trimmed

`bindings/java/RustWidgetsAndroid.java` no longer declares `nativeCreate*`,
`nativeSetView*`, `nativeDestroyView` or `nativeSelfTest*`, because the Rust symbols
they bound to no longer exist. A Java method whose Rust symbol is gone fails with
`UnsatisfiedLinkError` at the first call, which is worse than its absence. The class
keeps the platform handshake (`nativeInit`, `nativeAttachContext`,
`nativeDetachContext`), the diagnostics, and `nativeOpenDocument(String mimeType)`.

### Added

- **Four factory-driven property-contract gates.** These are the substantive change of
  the release: they turned "is every control's property surface complete?" from manual
  review into a machine check. On first run they found — and this release fixes:

  | Defect | Scale |
  |---|---|
  | Controls with no `WidgetProperties` contract at all | **59** |
  | Shared `WidgetKind`s silently reading *another* control's schema | **10** |
  | Published properties answering `UnknownProperty` where `ReadOnlyProperty` is right | **42** |
  | Schema tables omitting the shared `visible`/`geometry` names | **155 of 155** |

- **`surface_policy()`** — one strategy table for how each profile obtains a drawing
  surface, with monotonicity invariant tests.
- **A `portable` backend** (`platform::portable`) for targets with no OS behind them;
  it carries `mini` and host-less `embedded`, and is fully testable because nothing in
  the paint path is OS-dependent.
- **`platform::os_probes`** — the `/proc` and `/sys` probes shared by the five
  Linux-kernel backends (was 296 byte-identical lines across six files), plus the unix
  print-spooler helper.
- **`widget::text_utils::floor_char_boundary`** — shared by six text controls (was six
  copies).
- **`widget::misc_widgets::date_utils`** — month/day tables, leap-year arithmetic and an
  ISO-8601 parser shared by three date pickers (was a third copy of `MONTH_NAMES`). It
  also gains `parse_iso_date_checked`, which distinguishes "not a date" from "the day is
  out of range for the month", so `2026-02-30` is rejected instead of clamped.
- **`impl_default_via_new!`** — one macro replacing **117** identical `Default` impls.
- **New control capabilities:** `Arc` gained readable `minimum`/`maximum`/`sweep_angle`/
  `thickness`/`indeterminate` (they were writable but unpublished, i.e. undiscoverable);
  `TabBar` gained `clear_current_index()` so `current_index` can round-trip through
  `Null`; `TagInput` gained a real, settable `placeholder` that the renderer honours
  (previously a hardcoded string); `DropdownMenu` gained `selected_index` accessors.

### Changed

- **`tools/check_apple_native.sh` now asserts self-painting.** The iOS Simulator probe
  previously asserted that `rw_create_button` produced a real `UIButton` subview — it
  asserted the *absence* of the feature this release implements, and so failed on correct
  code. It now asserts the opposite via `no_backend_owned_window` and
  `self_painted_no_native_views`, which **fail if native construction ever returns**.
- **`tools/check_jni_signatures.sh`** repaired from 20 errors to 0.
- **Android feature gating widened** so `--features android` and `--features android,android-jni`
  build cleanly; fixed a real pre-existing bug where `LOGCAT_LOGGER` was referenced but
  never declared.

### Performance & size

- **Net −2,288 lines of source**, with no capability removed.
- A property read is **one direct `match`**, replacing up to nine serial category probes.
  `property_names()` returns `&'static [&'static str]` — zero allocation.
- `src/platform` shrank from **43,151 → 22,010** lines across the BLUE15 series.
- One fewer parse of `/proc/meminfo`, `/sys/class/power_supply` and `/proc/self/status`
  in five backends (the code existed five times, though only one copy ran per process).

### Verification

```text
cargo test --no-default-features --features desktop  --lib   4016 passed; 0 failed
cargo test --no-default-features --features embedded --lib   1459 passed; 0 failed
cargo test --no-default-features --features mini     --lib   1388 passed; 0 failed
cargo fmt -- --check                                         0 diff
cargo clippy --features desktop|embedded|mini --all-targets -- -D warnings
                                                             0 warnings (all three)
9 real feature combinations x --all-targets                  0 errors
16 QA gates                                                  all PASS
  (including a real iOS Simulator run)
```

> **No ABI change**: `rw_bindings_api_version` remains `8`; no exported `rw_*` symbol was
> added, removed or changed.

## 1.1.3 (2026-09-13) — Unified Native-Control Property API Release

A feature release that closes the gap between "native controls exist" and "native controls are
usable without writing per-OS code". Before it, the only OS-independent way to reach a control's
state was `set_widget_text` — lossy for anything whose payload is not its display text, and
unavailable for selection indices, ranges, busy states or window attributes. Each round of work
was verified by compilation on every target, by tests whose teeth were proven with negative
controls, and by a runtime probe on the real Cocoa backend.

### Added — one property API, every OS

`Platform` gained 36 semantic property methods, matched by 45 crate-root functions, 41
`WidgetHandle` trait methods, and implementations in every backend (macOS/AppKit, Windows/Win32,
Linux/GTK, and the state-only stub/mobile/wasm paths). Nothing at the call site branches on the OS.

| Group | Capability |
|---|---|
| Value controls | `set_widget_value` / `widget_value`, `set_widget_range` / `widget_range`, `set_widget_step` / `widget_step` |
| Selection | `set_widget_selected_index` / `widget_selected_index`, `set_widget_group` / `widget_group` |
| Checkable | `set_widget_checked` / `is_widget_checked`, `set_widget_tristate` / `is_widget_tristate` |
| Progress | `set_widget_indeterminate` / `is_widget_indeterminate` |
| Text entry | `set_widget_read_only` / `is_widget_read_only`, `set_widget_max_length` / `widget_max_length`, `set_widget_placeholder` / `widget_placeholder`, `set_widget_echo_mode` / `widget_echo_mode`, `set_widget_selection` / `widget_selection` |
| Window | `set_window_state` / `is_window_in_state`, `set_window_min_size` / `window_min_size`, `set_window_icon` / `window_icon` |
| Slider | `set_slider_orientation` / `slider_orientation` (creation-time; see below) |
| Scroll | `set_widget_scroll_position` / `widget_scroll_position` |

New public types: `WindowStateFlag` (an enum instead of five booleans, so a backend dispatches
with `match` rather than a chain of `if`/`else`), `WindowStateRecord`, and `EchoMode` moved from
`app` to `platform` so backends can name it without inverting the layering (`app` re-exports it,
so existing import paths keep working).

### Design decision — unify the call shape, not the capabilities

A control may carry a value on one OS and not on another; that is a genuine platform difference,
not a defect. The defaults return `false` / `None` — never a made-up value — so a backend that has
no such property reports it as *absent*, and the caller branches on the result at runtime if it
cares. Every refusal carries a doc comment explaining which toolkit limit causes it:

| Refused | Why |
|---|---|
| macOS placeholder / echo-mode | The macOS line edit is an `NSTextView`; `placeholderString` and `NSSecureTextField` belong to the `NSTextField` family, and changing class would rebuild the view (out of scope for an attribute write) |
| `NoEcho` on all three desktops | AppKit, Win32 and GTK each expose a mask character but no "echo nothing" mode |
| `set_widget_max_length` on macOS | `NSTextField` has no direct limit (it is enforced via a delegate) |
| Slider orientation on Win32 | `TBS_VERT` is a creation style; the full `TBM_*` message set has no orientation message |

### Changed

- **`SliderHandle::set_orientation` removed; orientation is now creation-time.** It was a setter
  that could not be honoured on two of three toolkits, which is exactly the kind of lie this release
  removes. Use `WindowHandle::new_slider_with_orientation(...)` (applies the orientation in one call
  on every OS) and read it back with `SliderHandle::orientation()`. The only in-tree caller
  (`demo/control`) was updated.
- `EchoMode` is now defined in `platform` and re-exported from `app`; `use rust_widgets::app::EchoMode`
  continues to compile.

### Fixed — macOS

- **20 `create_*` constructors registered no handle.** `list_view`, `group_box`, `frame`,
  `tab_widget`, `splitter`, `toggle_button`, `calendar`, `scroll_bar`, `double_spin_box`,
  `font_combo_box`, `context_menu`, `popup_window`, `dialog`, `input_dialog`, `progress_dialog`,
  `directory_dialog`, `date_picker`, `time_picker`, `date_time_picker` and `activity_indicator`
  called `state.create_widget` but never registered a handle, so every handle-gated property
  refused with "unknown id" — while the constructor still returned a non-zero id, and purely
  state-backed reads (text, visibility) kept working. All 20 now use `register_state_only_handle`.
- **Full-screen could not be turned off.** The guard compared the request against `styleMask`,
  which is still the pre-transition value while `toggleFullScreen:` animates, so `on == false`
  never sent the toggle.
- **`minimized` and `fullscreen` always read back stale.** Both transitions complete on the run
  loop, so an immediate read returned the old value. Reads now prefer the recorded request until
  the native state agrees, then trust the native query — so a user-initiated change is still seen.
- **`create_spin_box` registered no handle** (same class as the 20 above), so its value API
  refused.
- **`create_line_edit` builds an `NSTextView` with `setEditable: NO`**, i.e. macOS line edits start
  read-only. The state model now records that so `is_widget_read_only` reports the control's real
  state instead of the cross-platform default.

### Fixed — Windows

- `SendMessageW` argument widths corrected throughout the new code (`wparam: usize`, `lparam: isize`).
- `TBS_VERT` sourced from `commctrl` (not `winuser`); `SetScrollPos`/`GetScrollPos` take `c_int`.
- Scroll areas are created as `Static` windows carrying `WS_HSCROLL | WS_VSCROLL`, so `WM_GETMINMAXINFO`
  is routed through the real window procedure to enforce a window minimum size (Win32 has no setter).

### Fixed — Linux (GTK)

- `hadjustment()`/`vadjustment()` return an `Adjustment`, not an `Option` (GTK synthesises one);
  the first version unwrapped an `Option` that never existed.
- GTK 0.18 exposes `fullscreen()`/`unfullscreen()` but **no** `is_fullscreen()`, and no
  `is_iconified()`; those reads are served from the state model rather than inventing a
  `GdkWindow` query.

### Fixed — process

- **A regression test that could not fail was caught and fixed.** The first macOS guard for the 20
  missing handles asserted `set_widget_text``get_widget_text` round-trip plus `is_widget_visible`.
  A negative control (temporarily reverting one constructor) showed it still passed, because those
  two properties read the state model directly and never consult the handle table. The test now
  asserts handle registration itself, and the negative control fails loudly with the constructor's
  name.

### Tooling

- `tools/add_spdx_headers.py` — idempotent SPDX header writer (`--check` supported).
- `tools/gtk_property_check.py` — type-checks the Linux backend's GTK calls on a non-Linux host by
  lifting the property accessors into a scratch crate against the real `gtk` 0.18. It found two
  genuine defects this release (the `hadjustment` misuse and a duplicated function signature).
- `examples/control_property_uniform.rs`, `examples/macos_window_state_async_probe.rs`,
  `examples/macos_created_controls_are_usable.rs` — runtime probes for the new API, the AppKit
  transition timing, and handle registration respectively.

### Compatibility

- **No ABI change**: `rw_bindings_api_version` remains `8`; no exported `rw_*` symbol changed.
- One API shape change (slider orientation), with the replacement documented above and the sole
  in-tree caller migrated.

### Known issue (observed once, not reproduced)

During the version bump, one combined invocation reported
`test result: FAILED. 4004 passed; 1 failed` for the lib test binary. It has not reproduced in
more than ten subsequent runs, including the exact concurrency condition (a `cargo clippy`
contending for the build lock) and a forced full rebuild via `touch src/lib.rs`. No test asserts
the crate version, so the bump cannot be the cause. The failure is recorded rather than dismissed:
the suite contains tests backed by process-global state (the i18n manager, the platform singleton,
the JS-engine setter), so an order- or timing-dependent flake remains plausible. It is **not**
claimed fixed, and no test was changed to hide it.

## 1.1.2 (2026-09-12) — Platform Correctness & Unsafe-Surface Audit Release

An audit-driven release. Work began as "complete the Apple-related items in `blue14.md`" and
continued through seven rotated audit directions (FFI soundness, error-path leaks, concurrency/panic
safety, memory/long-run, API-contract consistency, doc/code consistency, and unsafe-impl necessity).
Every fix below was reproduced first, then closed with a regression test and **negative verification**
(revert the fix → the test must fail).

### Fixed — Apple (host-visible only on macOS, so latent for the project's whole history)
- **`MacOSPlatform` (cocoa-legacy) made unguarded AppKit calls from any thread.** Creating a window
  or touching any of ~30 other call sites from a worker thread made AppKit raise a foreign
  Objective-C exception, which Rust cannot catch, so the **entire test process died with SIGABRT**
  (`cargo test --lib --features desktop` aborted in `c_abi_widget_lifecycle_roundtrip`).
  Added an `is_main_thread()` guard plus a state-only fallback handle to every AppKit entry point,
  and made `add_to_parent_window`/`sync_list_box_native` skip nil receivers (the `cocoa` crate
  dereferences null and aborts).
- **`macos_objc2` native FFI was gated on the alias feature `objc2-macos` instead of `macos`.**
  Because feature aliases are one-way, `--features macos` left **43 native call sites silently
  compiled out**, degrading the backend to state-only with no error. Now gated on the canonical
  feature.
- **`set_native_text` declared `performSelector:withObject:` as returning `()`**, but it returns
  `id`; the mismatch aborted at runtime. Return type corrected.
- **`ime_macos` declared `ImeCtx` as four identically-named *local* structs.** `Any::downcast_ref`
  matches on `TypeId`, not memory layout, so every downcast silently returned `None` and **three
  native IME paths were no-ops**. Types hoisted to module level.

### Fixed — FFI soundness
- **Removed three unnecessary `unsafe impl Sync`, each proven redundant by a delete-and-compile
  test**: `EventHandlerContext` (`json/events.rs`), `LinuxPlatform` (`linux/types.rs`), and
  `TsfThreadMgr` (`ime_windows.rs`). Each removal compiled clean across desktop, `--all-features`,
  every profile, and `x86_64-pc-windows-gnu`. `EventHandlerContext` was the sharpest case: it exposes
  both `user_data<T>() -> &T` and `user_data_mut<T>() -> &mut T` from the same unowned pointer, so a
  `Sync` impl would have legalized a genuine data race. `AndroidPlatform`'s `Sync` was **kept**  removing it produces 55 `E0277` errors, i.e. real code depends on it. The crate now has exactly
  one `unsafe impl Sync`.

### Fixed — resource leaks on error paths
- **`ffmpeg_encoder` leaked its temp file on any encode failure.** `format::output_as` creates the
  file before many `?` early-returns, so failures after that point left the file behind. Now guarded
  by RAII (`TempFileGuard`).
- **`ffmpeg_decoder` leaked on write failure** — same class, fixed the same way.

### Fixed — concurrency, panic safety, timing
- **i18n hot-reload trusted `mtime` alone**, so on coarse-granularity filesystems a change could be
  missed entirely. Replaced with a content fingerprint.
- **`undo/stack` test fixture used `static mut`**, a real data race between concurrent tests. Now atomic.
- **Data-binding's `syncing` re-entrancy flag stayed stuck forever if a callback panicked**, silently
  disabling all future two-way sync. Now an RAII guard, so a panic unwinds it.

### Fixed — API contracts and lifecycle
- **`StubPlatform` contradicted itself**: 21 `create_*` methods ignored their `parent` argument while
  19 sibling methods validated it. All 21 now validate, so tests built on the stub are a valid
  contract baseline. `create_menu_bar` requires a `Window` parent; `create_menu` requires
  `MenuBar | Menu`.
- **`macos`/cocoa's `create_spin_box`/`create_list_view`/`create_scroll_area` ignored `parent`**
  while the `create_group_box` directly beneath them validated it. Fixed.
- **Added `Platform::destroy_widget()` and `widget_count()`** (plus `rw_destroy_widget` in the C ABI,
  all 11 backends, and the `ControlBackend` trait). Previously there was **no way to destroy a
  widget at all**, so dynamic UIs accumulated registry entries without bound. Cleanup is real, not
  cosmetic: objc2 releases derived submenu ids and cascades menu children; cocoa now calls the
  previously-never-called `a11y_bridge.unregister_handle`; iOS releases its `ButtonTarget`.
- **GTK clipboard panicked off the main thread.** `gtk_clipboard()` called
  `gdk::Display::default()` directly, and GDK panics ("may only be used from the main thread") on a
  non-GTK thread, aborting the process; the function's own doc comment claimed it returned `None`
  there. Now guarded by `gtk::is_initialized_main_thread()` with the documented mirror fallback.
- **`libvorbis` was hard-coded as an external encoder.** This had been misattributed as an
  "environment failure"; `brew deps ffmpeg` / `otool -L` proved Homebrew's ffmpeg ships no vorbis.
  Now falls back to ffmpeg's native Vorbis encoder.

### Fixed — test coverage that was not actually running
- **50 logic-only tests were excluded from the build** by module-level `#[cfg(target_os = ...)]`:
  `ime_macos` (19), `macos_objc2` (17), `android` (8), `ios` (6). All now execute on the host.
  Un-gating them exposed a previously-uncompilable `assert_eq!` in the `android` tests
  (`AndroidHandleKind` lacked `Debug`).
- Earlier rounds likewise recovered `ime_windows` (15) and `windows_notify` (11) tests that were
  trapped behind `target_os` gates despite being pure state-machine logic.
- Added `platform::contract_tests` (11 tests, incl. a 17-method parent-rejection matrix) and
  `platform::teardown_tests` (3 tests asserting the library's own registry sizes).

### Added
- `tools/check_widget_kind_count.sh` — mechanically parses `src/widget/kind.rs` and fails if any
  document's stated widget-kind count has drifted. Wired into the CI `validation-gates` job.
- `tools/check_apple_native.sh`, `tools/check_apple_thread_safety.sh`, `tools/build_ios_testapp.sh`,
  `tools/run_ios_testapp.sh` — a real iOS `.app` (staticlib + ObjC host, no Xcode project) that
  boots an iOS simulator, installs, launches, and asserts `RESULT: PASS`; plus AppKit probes for
  both macOS backends.
- `examples/apple_appkit_probe_objc2.rs` — a separate probe for the objc2 backend (the two macOS
  backends use different Objective-C crates).
- An `apple-native` CI job covering both macOS backends and the iOS simulator run.

### Changed
- Crate version bumped `1.1.1``1.1.2`. **No ABI change**: `rw_bindings_api_version` remains `8`.
  `rw_destroy_widget` is a new symbol in the generated header (106 declarations, up from 105).
- Version references aligned to `1.1.2` in `Cargo.toml`, the `CoreConfig` runtime version contract,
  Node.js/Python package metadata, the demo banner, and the en/zh-CN/zh-TW cookbooks.
- **Docs corrected where they contradicted the code**: `codemap.md` claimed 166 `WidgetKind`
  variants (actual 167), and both READMEs advertised "80+ widgets" (actual 167 kinds).

### Verification
- `cargo test --lib`: **3854 passed**, 0 failed (desktop) / **3946** (full) / **1869**
  (`--all-features`); mobile 3662, tablet 3653, wasm 2263, harmony 2268 — all 0 failed.
- `clippy --all-features --all-targets -- -D warnings`: **0 warnings**; `cargo fmt --check` clean.
- `cargo check --all-targets` across desktop/full/mini/embedded/mobile/tablet/wasm/harmony: 0 errors.
- Eight CI gates pass: profiles, ABI, widget-kind count, platform capability matrix, capability
  truthfulness, control route matrix, platform impl matrix, Apple thread safety.
- Both macOS AppKit probes report `RESULT: PASS` (12 named checks each) against live AppKit objects.

### Notes on what was deliberately *not* changed
- **Dialog parent validation stays as-is.** `create_message_box` / `create_file_dialog` /
  `create_color_dialog` / `create_font_dialog` ignore the parent on 7 of 11 backends and validate on
  4. Ignoring is the majority convention and is semantically right (dialogs are top-level modals,
  not children of a widget); forcing uniformity would break the 7 backends behaving correctly. The
  contract is now pinned by a test so future audits do not re-flag it.
- **`accessibility/windows` stays gated.** It references `winapi::um::winuser::EVENT_*`
  unconditionally, so it genuinely cannot compile off Windows, and un-gating it would only produce
  an empty assertion body (false coverage).
- **An RSS-based leak claim was retracted as wrong.** A draft report asserted a leak from
  "8000 widgets → +49 MB RSS". Three independent checks disproved it: macOS `leaks --atExit`
  reported `0 leaks for 0 total leaked bytes`, malloc node counts did not grow under churn, and a
  pure-AppKit control (no rust-widgets code) reproduced the same RSS curve. The growth is AppKit's
  own caching. Regression tests now assert registry state, not RSS.

## 1.1.1 (2026-09-11) — Cross-compilation & Coverage Visibility Release

### Fixed — cross-compilation
- **AVIF now uses the pure-Rust `avif` codec instead of `avif-native`.**
  `avif-native` pulled in `dav1d-sys`, a system C library that fails to cross-compile for
  Android/iOS/wasm unless a pkg-config sysroot is configured by hand. This made the
  `mobile`/`tablet`/`desktop` profiles impossible to build for any foreign target.
  Trade-off: slower AVIF decode and ~15 extra build-time crates (`rav1e` et al.), in exchange
  for genuinely cross-compilable builds. Verified: Android (2 ABIs × 5 profiles), iOS,
  Windows (msvc/gnullvm), and wasm32 all compile clean.
- **Cross-target cfg-gating mismatches fixed** in `platform/runtime.rs`, `platform/android/types.rs`,
  `platform/ios/types.rs`, `gpu/adapter.rs`, and `compat.rs`. Several imports and helpers were gated on
  `target_os` alone while their users were also gated on `not(feature = "mini")` /
  `not(feature = "embedded")`, producing `E0432`/`E0433`/`E0599` on the affected combinations.
- **`compat::OnceLock` gained `set()`** so the `mini` profile matches the `std::sync::OnceLock` API
  surface (the Windows notify path calls it).

### Fixed — control routing
- **`NativeControlBackend` delegated to the wrong platform primitives**, discarding real Win32
  implementations:
  - `create_checkbox``create_toggle_button` (bypassed `BS_AUTOCHECKBOX`)
  - `create_spin_box``create_double_spin_box` (bypassed `msctls_updown32`)
  - `create_scroll_area``create_panel` (bypassed the scrollable child window)
  The two reverse delegations (`create_toggle_button`, `create_double_spin_box`) were dead code and
  now preserve widget identity.
- **Per-OS routing for `SpinBox`/`ListView`/`ScrollArea`.** They have real Win32 implementations but
  were listed in the global `CustomRequired` arm, so the native path was unreachable on Windows while
  other platforms (which have no such primitive) genuinely need the custom backend. Routing now
  promotes them to `NativePreferred` **only under `cfg(target_os = "windows")`**, pinned by two
  complementary tests.

### Fixed — test coverage visibility
- **50 pure-logic tests that never compiled or ran on any reachable path** are now part of the host
  build, following the BLUE14 rule that "not in the build" must be distinguished from "failed" and
  "ignored": `ime_macos` (19), `android` (8), `ios` (6), `macos_objc2` (17). Each was verified by
  mechanical scan to touch no OS API.
- **`AndroidHandleKind` was missing `Debug`**, which made three of its own `assert_eq!` tests
  impossible to compile. Never surfaced because the module was excluded from the host build.
- **`cargo test --all-features` (the actual CI command) did not compile** (`E0277`): `serialize_state`
  was gated more loosely than the `BackendState` `Serialize` derive it depends on.
- **`tools/generate_platform_capability_matrix.py`** now derives the degradation table by mechanically
  parsing `native.rs`; the capability-matrix doc is gated against drift in CI. Its prose is generated,
  so hand-editing the markdown is no longer possible without the freshness check failing.

### CI
- **`wasm-check` job was permanently broken**: it ran `--features wasm` without
  `--no-default-features`, which pulled in the whole `desktop` profile (audio, JS engine) for a wasm32
  target. Now pinned to `--no-default-features --features wasm`.
- **`android-cross-check` job was a no-op**: it passed `-Zlinker-features`/`-C linker` (rustc flags,
  invalid for `cargo check`) and swallowed every failure with `|| echo skipped`. It now exports the
  NDK linker/compiler via `CARGO_TARGET_*`/`CC_*` and checks 2 ABIs × 5 profiles with no failure mask.

### Changed
- Crate version bumped `1.1.0``1.1.1`. **No ABI change**: `rw_bindings_api_version` remains `8`
  and no exported symbols were added or removed.
- Version references aligned to `1.1.1` across `Cargo.toml`, the `CoreConfig` runtime version contract,
  Node.js/Python package metadata, the demo banner, and the en/zh-CN/zh-TW cookbooks.

### Documentation
- README (en + zh-CN) refreshed: corrected the stale test-count badge (`3700+`/`3400+``3850+`),
  documented the AVIF codec switch and its trade-off, added the CI cross-compile commands, and
  filled in zh-CN sections that had drifted (Web widget list, Special widgets, `performance`/`memory`
  core modules, Performance section).
- `docs/plans/blue14.md` updated with the round-8 audit record (E-class), including the one item
  deliberately left gated (`accessibility/windows`) because un-gating it would only produce an
  empty assertion body.

### Verification
- `cargo test --lib`: **3853 passed**, 0 failed (was 3820).
- `cargo test --all-features` (CI command): 0 failed (previously failed to compile).
- `clippy --all-targets -D warnings` and `clippy --all-features --all-targets -D warnings`: 0 warnings.
- All profiles (desktop/mobile/tablet/mini/embedded/full) and cross-targets
  (iOS / wasm32 / Windows gnullvm) build with 0 errors, 0 warnings.
- Android JNI test APK builds and signs via `tools/build_android_testapp.sh`.

## 1.1.0 (2026-09-09) — Version Contract Sync Release

### Changed
- Crate version bumped `1.0.0``1.1.0` (stable line; **not** an ABI break).

### Bindings & docs
- Version references aligned to `1.1.0` across code, demo banner, and documentation:
  `Cargo.toml`, package metadata (Node.js `package.json`, Python `setup.py`), demo/control banner,
  CoreConfig default version contract, and all cookbook/README version mentions.

### Connectivity
- `CoreConfig::desktop()/embedded()/mobile()` default version synced to `1.1.0`
  (runtime `Version` contract mirrors the crate semantic version; existing `Version`-type API
  examples and ABI contract `rw_bindings_api_version` = `8` are unchanged).

## 1.0.0 (2026-09-02) — Stable Release

### Stability & Quality
- **Stable public API line declared**; `rw_bindings_api_version` bumped to `8` for the 1.0 ABI contract.
- **Full compile matrix at zero errors/warnings**: every profile (desktop/tablet/mobile/mini/embedded/bare),
  every capability feature and cross-combination, plus all installed targets
  (windows-msvc, android aarch64/x86_64/armv7, wasm32-unknown-unknown/wasip1/wasip1-threads) verified clean.
- **Platform code compiled for the first time**: Windows (TSF `Send` safety, winapi pointer types) and
  Android backends now build and lint cleanly.
- **WASM end-to-end**: real `cargo test` on `wasm32-wasip1` (2158 tests passing via wasmtime);
  browser wasm (`wasm32-unknown-unknown`) builds/lints clean.
- **Tablet/mobile profiles compile for the first time**: dependency/feature gaps fixed
  (i18n/video feature cohesion, `tr!` macro gating, runtime stub cfg), 3509/3514 tests passing.

### Honest implementation pass (no fake/stub behavior)
- Audio: removed synthetic FLAC/OGG/AAC/Opus decoding and PCM-impersonating encoders; missing codec
  features now return explicit `Err`. Real FFmpeg/symphonia paths verified (2195 tests).
- Image: PNG decoder rewritten (scanline filters, RGBA stride, 16-bit sampling, bounds safety);
  GIF/WebP/TIFF/AVIF/ICO/SVG decoders now refuse instead of fabricating pixels.
- Video MJPEG failures are explicit (`FrameType::Synthetic` + diagnostics); web-engine JS evaluation
  wired to a real engine; PDF security markers no longer leak passwords.
- Line-edit clipboard shortcuts wired; undo zero-capacity panic fixed; software text rastering
  handles Unicode instead of truncating to `u8`.
- Dead code removed (`misc_widgets/chip.rs`, `image/svg_utils.rs`); dead test file mounted (`pdf/tests.rs`).

### Bindings & docs
- FFI bindings complete: C++ header and Python wrapper cover all 105 exported symbols (105/105);
  `rw_bindings_api_version` = 8 for the 1.0 ABI line.
- Capability matrix regenerated at 167 rows matching the 167 `WidgetKind` variants, with honest
  degradation notes; `unexpected_cfgs` lint restored to `warn`.
- README/docs aligned with code; version bumped 0.9.10 → 1.0.0 everywhere (Cargo, demo banner,
  Node.js package, migration guide).

### Full release backlog (folded in from the former `[Unreleased]` section)
### Added

- Signal-first event model migration notes for `v9`:
  - generic `Signal<T>` core with typed payload dispatch
  - `connect_once` one-shot slot semantics
  - scoped auto-disconnect via owner lifetime drop
- Expanded typed widget trigger kinds in platform/C ABI routing:
  - `3`: `selection-changed`
  - `4`: `closed`
- Geometry/style baseline primitives for `v10`:
  - `Point::new/origin`, `Size::new/is_empty`, `Rect::new/from_position_size/position/size/decompose/is_valid`
  - `Color::parse_hex` (`#RGB/#RGBA/#RRGGBB/#RRGGBBAA`), canonical hex serializers, `u32` pack/unpack
  - `Font` weight baseline (`100..=900`), shared defaults, and normalization helpers
  - `Padding`/`Margin` per-side types with `all/symmetric/normalized` constructors
  - axis-specific alignment enums and mapping helpers (`HorizontalAlignment`/`VerticalAlignment`)
- Basic widget full-class baseline for `v12`:
  - `Label`: deterministic text/alignment/image/word-wrap state with change signals
  - `LineEdit`: return-pressed signal, password-mode masking, selection/copy/cut/paste contract
  - `CheckBox`/`RadioButton`: tri-state + group-selection routing with explicit state/selected signals
  - `ComboBox`/`Slider`/`ProgressBar`: deterministic index/value range-clamped change signaling
- CI signal-first guard:
  - `tools/check_event_model_signal_first.sh` blocks wxWidgets-style event table patterns
  - validation gate wired in `.github/workflows/ci.yml`
- Layout system baseline for `v13`:
  - explicit `HBoxLayout` / `VBoxLayout` named layout types with `Layout` parity
  - deterministic `BoxLayout` major-axis allocation (remainder-aware, constraint-safe)
  - spacing/margin/item-count tuning APIs for directional layout control
  - focused layout regressions for box/grid/stack placement and auto geometry conversion
- Action system baseline for `v14`:
  - shared action routing parity across menu/button/toolbar hosts plus shortcut triggers
  - deterministic trigger contract with enabled gating and trigger result semantics
  - checkable action semantics (`checkable`, `checked`, toggle-on-trigger)
  - action state signals for signal-first routes (`triggered`, `toggled`, `enabled_changed`)
  - focused regressions for action binding/trigger/toggle behavior
- Intermediate widgets slice for `v15`:
  - `ScrollBar` full-state contract (`min/max/value/page_step/single_step`) with deterministic `value_changed`
  - `ScrollArea` baseline contract (`content_size`/`viewport_size`/`scroll_offset`) with signal-first change events
  - focused widget regressions for bounded scroll behavior and offset normalization
  - `GroupBox` title/checkable/checked deterministic contract with state change signals
  - `TabWidget` deterministic selected-index routing (`add/remove/select`) with `current_index_changed`
  - `Splitter` pane-ratio/size distribution contract with orientation/layout change signals
  - `MenuBar`/`Menu`/`ToolBar`/`StatusBar` intermediate host contracts for action routing and status/message state signals
  - dialog-family baseline contracts: `Dialog`, `MessageBox`, `FileDialog`, `ColorDialog`, `FontDialog`
    with deterministic result/state signals for accept/reject/select flows
- Model/view architecture baseline for `v16`:
  - observable model signal surface via `data_changed_signal` on `ListModel`/`TreeModel`/`TableModel`
  - in-memory observable model contracts: `VecListModel`, `VecTreeModel`, `VecTableModel`
  - auto-refresh wiring in `TreeView::set_model` and `TableWidget::set_model` (model changes trigger redraw/layout requests)
  - focused regressions for model signal propagation and tree/table view refresh behavior
- Advanced widgets kickoff for `v17`:
  - `ListView` baseline contract with `ListModel` projection, deterministic selection, and model-driven auto-refresh wiring
  - dedicated `TableView` contract wrapper with `TableWidget` parity for model/delegate/selection APIs
  - expanded tree/table/list advanced view state contracts with focused row/node state and projection-safe normalization on model rebind
  - `RichEdit` baseline contract with text/selection/read-only state and deterministic edit/cursor signals
  - container baselines: `DockPanel` pane-placement contract and `MdiArea` document/active-document state contract
  - focused regressions for `ListView`/`TableView` baseline behavior and full widget-suite compatibility
- Runtime GUI mode contract for `v18`:
  - `RuntimeGuiMode::{NativeInteractive, PreviewOrStub}` and active-backend resolvers
  - startup mode reporting in `demo_main` for explicit backend behavior visibility
  - v18 startup smoke matrix and evidence template in `docs/QA_HARNESS.md`

### Changed

- Native signal bridge routing now normalizes covered widget interactions through typed trigger routes
  (`clicked`, `value-changed`, `selection-changed`, `closed`) instead of per-kind ad-hoc paths.
- Widget interaction baseline now emits explicit selection/closed signals for covered controls
  (window, combo box, tree view, table widget).
- Representative widget/layout entry points now accept primitive geometry/style workflows:
  - widget trait helpers: `position/size`, `set_position/set_size`, `padding/margin`, `set_padding/set_margin`
  - layout trait helper: `update_from_position_size(position, size, ...)`
- XML style parsing now reuses shared color parser (`Color::parse_hex`) and supports short/alpha hex forms.
- Advanced widget runtime kinds are now disambiguated for `RichEdit`, `ListView`, `DockPanel`, and `MdiArea`
  (no longer aliased to baseline kinds like `TextEdit`/`ListBox`/`Panel`/`StackWidget`).
- Historical roadmap audit coverage for `v1~v9` is now explicitly recorded and re-validated against code/tests/scripts.
- Embedded profile behavior-matrix validation now stays green by gating `serde_json`-dependent core deserialization test behind `desktop-runtime` feature.
- Validation sweep for this audit slice is green: `check_profiles`, `check_event_model_signal_first`, `cargo test --lib`, `check_behavior_matrix`, `check_visual_regression`, and `check_abi`.
- Windows runtime lifecycle path now uses active message pumping with stable loop-alive behavior for `demo_main`.
- Non-native preview backends now emit explicit runtime diagnostics:
  - Linux (non-`gtk-native`)
  - Harmony desktop preview path
  - Android mobile preview backend
  - macOS objc2 preview backend
- Cross-platform control creation routing now uses explicit backend `create_*` implementations (Linux/Harmony/macOS-objc2/mobile + Windows overrides) with no implicit demo/C-ABI button fallback shims for slider/progress/combo paths.
- Platform default `create_*` methods now fail explicitly (`0`) when unsupported; Windows backend create failures also return `0` with runtime diagnostics instead of silent button downgrade.

### Migration Notes

- Existing `Font::new(family, size, bold, italic)` remains supported; it now derives normalized `weight`
  (`400` regular, `700` bold). Prefer `Font::with_weight(...)` for explicit typography contracts.
- Existing uniform spacing behavior is preserved (`Padding::all`, `Margin::all`), while per-side values are
  now available for forward-compatible style contracts.
- Geometry callers can incrementally adopt primitive helpers without breaking existing `Rect` call sites.

## 0.9.10 (2026-07-23) — Code Quality Release

### Infrastructure
- **mod.rs refactoring (20/20 complete)**: All module declaration files now contain only `pub mod` declarations and `pub use` re-exports; implementation code moved to dedicated files (custom_paint, init, legacy_types, a11y_wiring, arc_helpers, gpu_types, backend, test_types)
- **Three profiles at 0 errors**: `default`, `mini`, and `embedded` all pass `cargo check` with zero errors
- **0 clippy warnings**: All unnecessary casts and manual range checks eliminated
- **0 `#[deprecated]` items**: All 28 deprecated annotations removed
- **0 `todo!()` / `unimplemented!()`** across the entire codebase

### Bug Fixes
- PdfPage naming conflict: struct renamed to `ExportPage`, trait retained as `PdfPage`
- Control backend dispatcher: fixed overlapping `#[cfg]` conditions causing duplicate function definitions in mini profile
- Embedded profile: 70 errors fixed (chrono/serde dependency gating, advanced widget module gating)

### Dependency Management
- `serde::Serialize`/`Deserialize` derives made conditional: `#[cfg_attr(feature = "serde", derive(...))]` across core types (Color, Font, WidgetRecord, etc.)
- `chrono` imports gated behind `not(mini)` / `not(embedded)` in capability layer
- `serde_json::Value` usage gated behind `not(embedded)` for json module
- Asset, advanced_widgets, media_widgets modules gated behind `cfg` for embedded profile

### Test
- Total: 3771 tests passing (3676 lib, 70 integration, 25 doctests)

## [0.10.0] - 2026-06-10

### Added

- **WidgetKind cleanup**: Removed orphan/duplicate variants from the widget kind enum
  for a cleaner, more maintainable categorisation.
- **macOS + iOS native FFI wiring**: Full native platform FFI bridges for macOS
  (AppKit/NSAccessibility) and iOS (UIKit/UIAccessibility), enabling native control
  creation and accessibility event routing.
- **i18n system (complete)**: Fully functional internationalisation with locale
  loading, plural rules, and context-based message translation.
- **StyleSheet engine**: CSS-like declarative style system with selector matching,
  cascading, and computed property resolution.
- **New layouts**:
  - `FlexLayout` — flex-box style responsive layout
  - `WrapLayout` — flow-based wrapping layout
  - `KeyboardAwareLayout` — auto-offset layout for soft keyboard
  - `ConstraintLayout` — anchor/constraint-based positioning
  - `Center` — centred container layout
  - `AspectRatio` — fixed-ratio sizing wrapper
- **New infrastructure**:
  - `App Lifecycle` — structured application lifecycle management
  - `Undo/Redo` — full undo/redo framework with command stack and composite commands
  - `Data Binding` — reactive model-to-view automatic synchronisation
  - `Print framework` — cross-platform print and preview API
  - `PDF export` — PDF document generation with form, image, and security support
- **New widgets** (65+):
  - Tooltip, SegmentedButton, NavigationStack, ProgressCircle, Icon
  - Popover, MenuButton, DropdownMenu
  - MaskedEdit, AutoCompleteEdit, MultiSelectComboBox
  - RangeSlider, FloatingLabel
  - TabView, SearchBar
  - Cupertino* controls: CupertinoNavigationBar, CupertinoSegmentedControl,
    CupertinoDatePicker
  - SwipeToDismiss, Pager/PageView, RefreshControl
  - ModalBottomSheet
  - FindReplaceDialog, PropertiesPanel
  - Charts: LineChart, BarChart, PieChart, Sparkline
  - EditableComboBox, DateRangePicker
  - AnimatedImage — frame-based animation widget with loop control
  - HeroAnimation — shared-element transition animation widget
  - BezierCurveEditor — interactive cubic Bézier curve editor
  - ColorHistory — colour swatch history with selection/hover signals
  - FontPreview — live font preview with configurable sample text
  - ShortcutEditor — keyboard shortcut configuration editor
  - InplaceEditor — click-to-edit text field with accept/cancel signals
- **Platform backends**:
  - `android` — full Android Platform trait implementation (state-driven)
  - `wasm` — WASM platform module for web browser execution
- **IME implementations**:
  - `macOS` — NSTextInputContext-based IME bridge
  - `Windows` — TSF-based IME bridge
  - `Linux` — IBus-based IME bridge
- **A11y enhancements**:
  - `A11yRole` enum with 27 semantic roles (Button..Unknown)
  - `A11yState` / `A11yNode` / `A11yTree` for screen reader tree management
  - `A11yProvider` trait for cross-platform screen reader integration
  - NSAccessibility protocol helpers (macOS) and UIA control type helpers (Windows)
  - `DefaultA11yProvider` in-memory implementation with focus traversal
- **Text shaping & rich text**:
  - `TextShaper` / `SimpleTextShaper` — text measurement and glyph run shaping
  - `RichText` / `TextSpan` / `TextStyle` — multi-span styled text rendering
  - `TextOverflow` / `TextClamp` — ellipsis, clip, and multi-line clamp handling
  - `GraphemeCluster` / `GraphemeProcessor` — Unicode emoji, combining marks, and ZWJ grapheme support
- **Platform backend refactoring**:
  - `macOS` (objc2) — `platform_impl.rs` split into `widget_creation.rs`, `menu_impl.rs`,
    `widget_state.rs`, `clipboard_dnd.rs`, `dialog_creation.rs`, `native.rs` for maintainability
  - `Linux``platform_impl.rs` split into `widget_creation.rs`, `menu_impl.rs`,
    `widget_state.rs` for maintainability
- **Render pipeline refactoring**:
  - `render/pipeline/` split — `containers.rs` extracted from monolithic pipeline
    into dedicated sub-module per widget family for maintainability
- **Testing**: 3400+ test cases across all subsystems

### Changed

- Missing docs lint changed from `allow` to `warn` to surface documentation gaps.

## 0.9.6 (2026-06-09) — BLUE11 Release

### New Widgets (28 new controls)
- **Popular Controls**: Switch, SearchBox, Chip, Badge, SkeletonLoader, FAB, Avatar, Rating, Stepper, Divider, Carousel, EmptyState, ColorWell, QRCode
- **Mobile-First**: PullToRefresh, BottomSheet, BottomNavigationBar, NavigationDrawer, AppBar, MobileDatePicker, ContextMenu (alias)
- **Platform Styles**: CupertinoSwitch, MaterialSnackbar, AdaptiveScaffold
- **Desktop Advanced**: PropertyGrid, WizardDialog, TagInput
- **Input Support**: ImePreedit
- **Layout**: MasonryLayout

### Visual Effects (R5)
- BoxShadow, Blur, ClipPath, BlendMode (16 modes), ConicGradient render commands
- Software and SVG backend support for all new commands

### Animation System (R6)
- KeyframeAnimation with multi-keyframe interpolation
- TransitionManager for CSS-style property transitions
- SpringAnimation with physical spring dynamics
- ThemeStateManager dark/light auto mode

### Accessibility (R7)
- AccessibleRole mappings for all 30+ new widgets
- AriaProperties struct for platform API bridging
- FocusTraversalStrategy (TabOrder, RowMajor, ColumnMajor)
- HighContrastMode support (BlackOnWhite, WhiteOnBlack, Custom)
- ReducedMotionPreference detection

### Event System (R8)
- Pointer Events with pressure and tilt support
- Gamepad Events (press, release, axis, connect/disconnect)
- AsyncTask with thread-local task queue
- IdleTask with frame-threshold scheduling

### Configuration & Documentation (R4)
- Cargo.toml enhanced (authors, categories, include/exclude)
- deny.toml for cargo-deny license auditing
- ARCHITECTURE.md and TUTORIAL.md documentation
- WIDGET_GALLERY.md visual reference
- .gitignore coverage improvements

### Quality & CI (R3)
- 130+ new tests across all new widgets
- CI: cargo-deny license audit job
- CI: docs-build check job
- Full feature build verification

### Architecture (R9)
- Widget re-export normalization
- containers.rs confirmed at 849 lines (no split needed)
- missing_docs and unsafe_code lint warnings added

## [0.5.19] - 2026-03-03

### Added

- v19 GPU visual parity coverage builders and regressions for covered controls:
  - base controls: `Window`/`Panel`/`Label`/`Button`/`CheckBox`/`RadioButton`/`LineEdit`
  - data/range controls: `ComboBox`/`ListBox`/`ProgressBar`/`Slider`/`ScrollBar`
  - host/navigation controls: `MenuBar`/`Menu`/`ToolBar`/`StatusBar`/`TabWidget`/`StackWidget`
- GPU parity aggregate regression tests:
  - `render::tests::gpu_parity_covered_controls_emit_non_empty_command_suite`
  - `render::tests::gpu_parity_covered_controls_auto_compose_runs_with_gpu_or_cpu_backend`
- New covered-control GPU parity demo:
  - `demos/demo_wgpu_control_parity.rs` (`cargo run --features gpu-wgpu --example demo_wgpu_control_parity`)
- QA/profile gate integration for P3g parity checks:
  - `tools/check_behavior_matrix.sh`
  - `tools/check_profiles.sh`

### Changed

- Embedded v19 closure stream is now fully documented as complete (`P4a`..`P4d`) with explicit residual embedded host-control unsupported boundaries.
- Version updated from `0.5.0` to `0.5.19` in `Cargo.toml`.

### Notes

- GPU implementation mode remains the light-weight route by design for this cycle:
  CPU command rasterization + `wgpu` upload/readback through the unified auto backend selection path.
- Controls without explicit GPU parity builders remain documented as uncovered in roadmap/docs for follow-up expansion.

## [0.5.0] - 2026-03-02

### Added

- Basic widgets milestone is complete and stabilized (Button/Label/LineEdit/CheckBox/RadioButton/ComboBox/SpinBox/Slider/ProgressBar).

### Changed

- Project crate version is now `0.5.0`.

## [0.1.0] - 2026-03-01

### Added

- CI validation gate job in `.github/workflows/ci.yml`:
  - profile matrix gate via `tools/check_profiles.sh`
  - ABI gate via `tools/check_abi.sh`
- New C ABI profile-aware capability contract query:
  - `rust_widgets_platform_capability_contract(profile_code)`
- Demo smoke script:
  - `tools/smoke_demos.sh` for `default` (`demo_main`) and `embedded` (`demo_button`) checks.
- First Python binding adapter path:
  - `examples/python/rust_widgets.py` (ctypes adapter)
  - `examples/python/demo_basic.py` (basic usage demo)
- Feature-completeness CI artifact pipeline:
  - `feature-completeness-matrix` job in `.github/workflows/ci.yml`
  - artifact upload for `target/qa/feature_completeness_matrix.md`
- Allowlist-aware matrix auditing inputs:
  - `tools/feature_completeness_allowlist.toml`

### Implemented

- PDF form serialization baseline in `src/pdf/mod.rs`:
  - `PdfPage` form APIs now emit `/AcroForm` and page `/Annots` widget objects
  - text/checkbox/button widgets are serialized into the object graph
- PDF security persistence diagnostics path in `src/pdf/mod.rs`:
  - `PdfSecurity` settings are persisted via explicit unsupported-encryption diagnostic entries
  - reader path restores those diagnostics on round-trip load
- PDF image deterministic encoding route in `src/pdf/mod.rs`:
  - image normalization routes (`exact-rgb`, `exact-rgba-drop-alpha`, `exact-gray-expand`, `raw-truncate-pad`)
  - removed synthetic payload-tiling behavior and added stream route metadata comments
- PDF regression expansion:
  - focused and combined tests now cover forms + security + image pipelines and reader round-trip behavior

### Changed

- Release preparation baseline for `0.1.0` (metadata hardening + publish dry-run workflow).
- Runtime diagnostics output is now structured as:
  - `[rust_widgets.runtime] stage=<...> profile=<...> backend=<...> route=<...>`
- Feature-completeness report format now includes:
  - raw/effective/suppressed signal counts
  - allowlist suppression reasons by file/category

## [0.0.2] - 2026-03-01

### Added

- GitHub project governance and collaboration files:
  - `LICENSE` (MIT), `CONTRIBUTING.md`, `CODE_OF_CONDUCT.md`, `SECURITY.md`, `SUPPORT.md`
  - Issue templates and PR template under `.github/`
  - CI workflow and Dependabot configuration
- Desktop shell capability parity improvements:
  - richer menu/menu item lifecycle support in desktop backends
  - typed widget trigger event model (clicked/value-changed)
- C ABI enhancements:
  - typed trigger polling API: `rust_widgets_poll_widget_trigger_event`
  - expanded core control constructors (`label`, `radio_button`, `slider`, `progress_bar`, `combo_box`, `list_box`, `panel`)
  - trigger injection APIs for host/native event sources
  - Harmony callback entrypoints for direct ArkUI/NAPI integration
  - node-handle registry APIs (`node_handle ↔ widget_id`) for Harmony integration
- New bridge and onboarding assets:
  - `docs/C_ABI_QUICKSTART.md`
  - `docs/HARMONY_NATIVE_BRIDGE.md` and localized variants
  - `examples/rust_widgets.h`
  - `examples/c_abi_poll_demo.c`
  - `examples/harmony_napi_bridge_sample.c`
- New runtime demo:
  - `demos/demo_native_events.rs`
- v2 validation tooling:
  - `tools/check_profiles.sh` for default/examples/embedded matrix checks
  - `tools/check_abi.sh` for ABI header drift + symbol and version gate checks

### Implemented

- Real print backend path in `src/print/mod.rs`:
  - system spool submission via `lpr`/`lp` on macOS/Linux
  - print-verb submission path on Windows
  - `Printer::print_with_result` for explicit backend error reporting
- Real PDF backend path in `src/pdf/mod.rs`:
  - valid minimal PDF (`%PDF-1.4`) serialization with catalog/pages/xref/trailer
  - page drawing commands mapped to PDF operators (`BT/Tj`, `m/l/S`, `re`, `f`)
  - reader supports `/Count` page parsing for round-trip loading baseline
- Real chart backend path in `src/chart/mod.rs`:
  - SVG rendering context (`SvgChartContext`) for concrete vector output
  - file export helper `render_chart_to_svg_file`
  - demo integration that exports `target/debug/demo_chart.svg`
- Embedded deep trimming path:
  - embedded builds exclude `xml`, `i18n`, `theme`, and `bindings` modules
  - `init()` uses a no-op i18n initializer under `embedded` profile
  - verified by `cargo check --no-default-features --features embedded`
- Dual-engine architecture baseline:
  - new `render_engine` module with `RenderEngine` trait
  - `NativeRenderEngine` and `EmbeddedRenderEngine` implementations
  - lifecycle APIs (`init`/`run`/`quit`) routed through default engine selection
- Object reflection/property enhancement:
  - dynamic `PropertyValue` model in `src/object/mod.rs`
  - reflective property APIs (`set_property`, `property`, `remove_property`, `property_keys`)
- Platform capability expansion:
  - `PlatformCapabilities` model and DPI scale query in `src/platform/mod.rs`
  - C ABI exposure via `rust_widgets_platform_capabilities` and `rust_widgets_platform_dpi_scale_factor`
  - C header sync in `examples/rust_widgets.h`
- ABI engineering improvements:
  - automated header generator `tools/generate_c_header.py`
  - generated artifact `examples/rust_widgets.generated.h`
  - C ABI versioning advanced to `5`

### Changed

- Linux backend now supports optional native GTK signal path under feature `gtk-native`.
- Documentation index expanded in `README.md` and localized help docs for C ABI and Harmony bridge coverage.
- C ABI version increased to `5` to reflect newly added public ABI functions.
- Lifecycle routing boundaries are profile-explicit:
  - desktop profile calls native platform lifecycle directly
  - embedded profile keeps lifecycle routed through `RenderEngine`
- Desktop-only dependencies (`serde_json`, `lazy_static`, `roxmltree`) are now optional via `desktop-runtime` feature to reduce embedded footprint.

### Notes

- Default builds remain stable and pass `cargo check` and `cargo check --examples`.
- Optional feature checks pass for `gtk-native` and `harmony-native`.