Commit Graph
479 Commits
Author SHA1 Message Date
aiongg 42c87e7e60 Merge #187: narrow-group splits 2026-10-24 03:54:18 +00:00
aiongg 2f90228e10 docking: a narrow group splits when its neighbours have room for both halves
A side split that leaves a half at its minimum is taken when the
dividers along that half can still travel, the groups beyond giving
way as they do for a dragged divider. An 80 pt group, whose halves
need 84, splits on all four sides and takes the rest from its
neighbour; only when the groups beyond are at their minimums too does
the drop join the group's tabs.
2026-10-24 03:41:27 +00:00
aiongg 2529d038b4 Merge #244: ui: floating panels in their own OS windows (native-windows) 2026-10-24 03:13:34 +00:00
aiongg 2cad4d2bec docking: clippy, a type for a split's children and one argument for a node and its rect 2026-10-24 03:13:34 +00:00
aiongg 7fdbab4f0d Merge #187: ui: shared panel docking with floating window trees, and task panes for office apps 2026-10-24 03:13:34 +00:00
aiongg 1c24845a17 Merge branch 'docking' into dock-windows 2026-10-24 03:13:34 +00:00
aiongg 1ccdad9512 docking: Floating::with_id for layouts built in code; debug builds warn about rebuilt layouts
Floating::new, single and stack draw a fresh id on each call, so a layout
built anew each frame opened a new OS window each frame. with_id gives such
a layout the same windows every frame. Debug builds log a warning once when
three frames running replace every native window with new ones holding the
same panels.
2026-10-24 03:09:14 +00:00
aiongg cb352b39ff docking: all four drop zones of a group share one depth
Each side zone reaches zone_depth into the body, or a quarter of the
body's smaller side when that is less. A tall narrow group's top and
bottom zones are no deeper than its left and right ones.
2026-10-24 03:06:11 +00:00
aiongg 99d8fe537e docking: a dragged divider shrinks the groups beyond it in turn
A divider dragged past the minimum of the group it shrinks moves on to
the next group along the axis, and so on until every group on that side
is at its minimum. The line follows same-axis splits up the tree and
ends at a split across the axis or beside a dock. Groups touching the
divider on the other side grow, up to their maximums, as before.

Stacked panels and the groups of a dock column cascade the same way.
2026-10-24 03:05:32 +00:00
aiongg b892ec92e2 docking: native window bar buttons win over the resize bands, corners are 4 pt Ls
The bands along a native window's edges leave out the bar's buttons, which
sit 4 pt in from the window's edge. Each corner is an L, 4 pt deep and 12 pt
along both edges. macOS windows are not resizable by AppKit, whose resize
areas reach over the ×; the bands resize them by InnerSize and OuterPosition,
since winit has no BeginResize there.
2026-10-24 03:05:03 +00:00
aiongg 0073927bf4 Merge pull request #260 from aiongg/keymap-batch
keymap batch: craft-keymap, keyboard layouts, the Keyboard Shortcuts dialog
2026-10-23 22:59:20 -04:00
aiongg 558f8ce2fc Merge upstream main into keymap-batch 2026-10-24 02:42:28 +00:00
aiongg 53837472d6 Merge pull request #259 from aiongg/i18n-batch
i18n batch: isolation, region, sizes, folding and sorting, ICU4X numbers, number parsing, craft-fonts-build
2026-10-23 22:42:02 -04:00
aiongg 2c6b3b5392 hayro-interpret: compute the largest 32-bit Type 0 sample in 64 bits (#257)
PdfCraft ledger hayro-interpret (31), its overflow part: a Type 0 function
with /BitsPerSample 32 computed 2_u32.pow(32), which overflows (a panic with
overflow checks on). The maximum is now ((1u64 << bps) - 1) as f32. The flat
sample array that (31) also brings is a performance change and is not part of
this commit. Test: function::type0::tests::thirty_two_bit_samples_do_not_overflow.

PdfCraft's other reader limits are already covered here: ASCII85 output is
bounded by the decode limit (#253), object-stream indexes are parsed once with
checked offsets, and direct objects nest at most 64 levels (PdfCraft: 128).
2026-10-23 22:32:25 -04:00
aiongg 332a4456dd Merge #186: keymap: Keyboard Shortcuts dialog, named shortcut sets and the shortcut editor
# Conflicts:
#	crates/keymap/src/lib.rs
2026-10-24 02:29:57 +00:00
aiongg f0379def18 Merge #205: keymap: read presses by the keyboard layout 2026-10-24 02:29:52 +00:00
aiongg 4d646b3cbd Merge #164: Add craft-keymap: shared keyboard bindings and shortcut-set import 2026-10-24 02:29:52 +00:00
aiongg ec65b95a65 Merge #213: Add craft-fonts-build: embed craft-fonts faces from an app's build.rs
# Conflicts:
#	Cargo.lock
2026-10-24 02:26:24 +00:00
aiongg 02eb391d39 Merge #202: i18n: parse_number for typed and pasted numbers
# Conflicts:
#	crates/i18n/README.md
2026-10-24 02:26:12 +00:00
aiongg a8b8fbd5a8 i18n: the RTL unit test sets its number format, as the region now decides digits 2026-10-24 02:26:04 +00:00
aiongg 5f4c39ea94 i18n: a region-formatted count is a left-to-right isolate in RTL wordings; trn_plain has no marks 2026-10-24 02:26:04 +00:00
aiongg aaf9f29e4f Merge #210: i18n: numbers for a region on ICU4X, locale digits in counts and sizes
# Conflicts:
#	Cargo.lock
#	crates/i18n/Cargo.toml
#	crates/i18n/README.md
#	crates/i18n/src/lib.rs
2026-10-24 02:25:57 +00:00
aiongg fa78cb52a5 Merge #206: craft-i18n: search folding and locale sorting
# Conflicts:
#	crates/i18n/Cargo.toml
#	crates/i18n/src/lib.rs
2026-10-24 02:25:27 +00:00
aiongg 7cb4a73b3c i18n: file sizes and measures fill {n} as a left-to-right isolate 2026-10-24 02:20:40 +00:00
aiongg c465dd3f47 Merge #204: i18n: file sizes and measures with translatable unit names
# Conflicts:
#	crates/i18n/README.md
#	crates/i18n/src/lib.rs
2026-10-24 02:20:40 +00:00
aiongg 1faeabfead Merge #203: i18n: formatting region apart from the interface language
# Conflicts:
#	Cargo.lock
#	crates/i18n/README.md
#	crates/i18n/src/lib.rs
2026-10-24 02:20:33 +00:00
aiongg 85148fd99c Merge #201: i18n: isolate inserted values in fmt and trn 2026-10-24 02:18:41 +00:00
aiongg 9f75d3dc19 pdf: keep a CID font's /W2 table past an out-of-range first CID; vendor hayro-cmap from PdfCraft (#254)
* pdf: keep a CID font's /W2 table past an out-of-range first CID; vendor hayro-cmap from PdfCraft

- hayro-interpret: a /W2 run whose first CID is past 65535 is skipped, as in
  /W. A run starting at 4294967295 overflowed the CID counter and discarded
  the whole table. Unit test in font::cid.
- hayro-cmap 0.1.0 is vendored from PdfCraft a2ec27b47 with its malformed-CMap
  patch (PdfCraft #3177): bad bfchar/bfrange entries, an unresolvable usecmap
  and an unparseable tail are skipped instead of failing the whole CMap. The
  crate's tests come with it. Wired up like the other vendored Hayro crates
  (workspace exclude, patch entry, SOURCE.json, backend test script); NOTICE,
  ATTRIBUTION.md and vendor/README.craft-reader.md record the source.

* hayro-syntax: refuse an xref-stream subsection that runs past object number u32::MAX

The object number was start + i in unchecked u32: a subsection starting near
u32::MAX overflowed (a panic in debug builds, a wrong object number in
release). Covered in xref::tests::xref_stream_entries_need_backing_bytes.

* hayro-cmap: a binary usecmap counts against the nesting limit; /W2 checks the CID first

- hayro-cmap: a binary CMap's usecmap passed its own depth to the nested
  parse, so a self-referencing binary CMap recursed until the stack
  overflowed. It now counts like a text usecmap. Test:
  self_referencing_binary_usecmap_stops_at_the_nesting_limit.
- hayro-interpret: the /W2 first-CID check runs before the run's metrics
  are read, so an incomplete run past CID 65535 no longer discards the
  rest of the table.

* hayro-syntax: refuse xref-stream object numbers past i32::MAX

ObjectIdentifier stores an i32; a number between i32::MAX and u32::MAX
was cast to a negative object number.
2026-10-23 22:17:04 -04:00
aiongg 7fe95cf81e Merge upstream main into i18n-isolation 2026-10-24 02:09:12 +00:00
aiongg 9c5ebb782e Revert "craft-ui: update egui to 0.37 (#199)" (#251)
This reverts commit 3832c47ef6.
2026-10-23 22:08:41 -04:00
Dylan M. Taylor d6b3fb9671 security: bound vendored hayro ASCII85 output by the stream decode limit (#253)
* security: bound ASCII85 output by the stream decode limit (CodeRabbit)

* fix(ascii85): truncate terminal partial groups to decode limit
2026-10-23 21:54:26 -04:00
aiongg 32e4f5a764 Merge upstream main into i18n-isolation 2026-10-24 01:08:02 +00:00
aiongg 5354479ce3 i18n: scripts, direction and regional Han per language tag (#200)
* i18n: scripts, direction and regional Han per language tag

scripts(tag) lists the ISO 15924 scripts a language's interface text is
written in, direction(tag) follows the main script, and han(tag) gives
the regional Han forms (SC, TC, HK, JP, KR) for picking a CJK face.
I18n::rtl uses direction.

* i18n: non_exhaustive Script and Han; regions that imply a script

pa-PK, uz-AF and az-IR are written in Arabic and sd-IN in Devanagari, as
CLDR's likely subtags give them. A script subtag still wins.

* i18n: han and catalog matching follow region-implied scripts

han(zh-US), zh-AU and the other regions CLDR writes in Traditional
characters give Traditional, and pa-PK picks a pa-arab catalog, never
Gurmukhi pa, as pa-Arab-PK does.

* i18n: Hani and yue-Hant pick Han forms by region; usual scripts for kk, ky, tg, ku, ms, ug

* i18n: base_direction of a paragraph from its first strong character
2026-10-23 21:07:32 -04:00
aiongg 1546cef8d9 docking: Escape in a native window that doesn't own a drag cancels it, whichever window owns it 2026-10-24 00:33:17 +00:00
aiongg 93b7b34f2f Merge upstream main into i18n-isolation 2026-10-24 00:15:07 +00:00
aiongg 599cc8cf95 Merge upstream main into i18n-scripts 2026-10-24 00:14:23 +00:00
aionggandDavis Brief 3832c47ef6 craft-ui: update egui to 0.37 (#199)
* craft-ui: match guard for a stack's hit test (clippy 1.95 collapsible_match)

* Update egui to 0.37

egui 0.37 replaces WidgetType with accesskit's Role and renames a few
methods. Mapped per egui's own table (WidgetType docs): Checkbox is
CheckBox, SelectableLabel is Button, Other is Unknown; UiBuilder::id and
Ui::id are scope_id; Id::new is Id::unique (the same hash). No behaviour
change.

egui's test harness now panics on a glyph no installed font has, and its
bundled fonts dropped U+22EE, so the docking fixture's group header draws
an ellipsis instead of a vertical ellipsis.

* craft-ui: README says egui 0.37

---------

Co-authored-by: Davis Brief <davisbrief@gmail.com>
2026-10-23 20:02:10 -04:00
aiongg 0008f89212 Merge branch 'docking' into dock-windows
Native windows draw a frame's drop zones through the destination window's
painter, and the bar-docking test aims inside the 40 pt right band.
2026-10-24 00:00:43 +00:00
aiongg dd50095dbb Merge upstream main into i18n-scripts
# Conflicts:
#	crates/i18n/README.md
2026-10-23 23:58:43 +00:00
aiongg e6c76f5151 docking: drop zones are 40 pt bands below the tab strip, all outlined while dragging
A frame's side zones reach DockStyle::zone_depth (40 pt) into the body below
the tab strip, or a third of a smaller body, so a frame keeps its center.
drop_zone, zone_shape and resolve_drop take the depth. In the Frame style a
drag over a frame outlines every zone a drop there would change something in
and fills the one under the pointer, without the outline of the resulting rect.
2026-10-23 23:57:43 +00:00
skylar taylor-barrick bfb116ccaf Merge pull request #247 from benandez/i18n-lazy-parse
i18n: parse each locale lazily on first lookup
2026-10-23 17:00:26 -06:00
Martin BallandClaude Opus 5.5 f7cc8a7df1 i18n: row-problem log and README name precedence (review)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 22:11:30 +01:00
Dylan M. Taylor 1d041f5c03 Merge pull request #249 from dylanmtaylor/ci/sonar-main-not-cancelled
ci(sonar): stop cancelling main-branch runs so coverage is published
2026-10-23 16:59:06 -04:00
Dylan M. Taylor 562aa90af5 ci(sonar): don't cancel superseded runs on main, so coverage is published 2026-10-23 16:51:10 -04:00
aiongg f0ad6c1e1d media: QuickTime v2 sound entries refuse channel counts and lpcm bit depths past 16 bits (#246)
From DeckCraft 6873a25.
2026-10-23 16:14:41 -04:00
Martin BallandClaude Opus 5.5 4ecda6fa8c i18n: parse each locale lazily on first lookup
I18n::new keeps the embedded text and parses nothing; a locale's rows
are parsed on the first lookup that reaches it (also as a fallback) and
its bad rows logged with log::warn!. new returns only the locale-level
problems. check_all parses every locale and returns all problems.
name() scans for the language.name row instead of parsing the locale.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 21:11:48 +01:00
aiongg f97c84d273 media: fixes from FilmCraft's copy (NAL widths, RBSP stop bits) (#245)
* media: reject NAL length prefix widths outside 1 to 4

length_prefixed_nals returns BitError::InvalidNalLengthSize for any other
width before scanning, empty data included. A width of 5 or more was
accepted and shifted bytes out of the length; a zero width returned Eof
only for non-empty data. Width 3 still splits, since
(lengthSizeMinusOne & 3) + 1 can be 3.

From filmcraft#2953.

* media: find the RBSP stop bit once per BitReader

BitReader::new records the position of the last set bit, and
more_rbsp_data compares against it instead of scanning back over the
data's zero suffix on every call (once per macroblock in a slice
parser). FilmCraft caches it in a Cell on first use; computing it in
new keeps BitReader Sync.

From filmcraft#2880.

* media: test the order CodecPrivate stripped headers are restored in

Header-stripping encodings with private-data scope prepend their bytes in
list order, so the last one listed ends up first. Empty prefixes and
frame-only scopes leave CodecPrivate as it is.

From filmcraft#2911.
2026-10-23 15:52:41 -04:00
aiongg 7474826f6f media: craft-media review fixes (frame budget, PCM chunks, spec names) (#196)
* media: look up the track of each traf in a hash map

* media: bound Matroska indexing by a file-wide frame budget

Every indexed frame claims its stored bytes and at least one, so fixed-size
laces of empty frames cannot describe more frames than the file has bytes.
The frame count across tracks is capped at 2^26, the TrackEntry count at
2^16, and blocks find their track through a hash map.

* media: keep the spec spellings of Colour, ColourSpace and colourPrimaries

* media: PCM chunks stay bounded in MOV and MP4

The writer ends a PCM chunk at 1 MiB or half a second, and returns an
error past 2^32 - 1 samples in a track instead of clamping the stsz count.
The reader splits a PCM chunk above 16 MiB into several samples, so files
from writers without chunk limits read whole past 4 GiB. A sparse output
lets the tests write past 4 GiB, which also exercises the writer's co64
path.

* media: clamp max_lace_frames to 256 and round BlockDuration

* media: level-1 Matroska elements read at most the file's length in all

SeekHead entries pointing at nested elements made each one read the rest
of the file.

* media: set_sample_entry rejects a codec change

* media: the mux oracle compares stream counts before streams

* ci: media checkout does not persist credentials

* media: README lists the renames from FilmCraft and the output that differs on valid input

* media: rustfmt

* media: the stream count comparison leaves out timecode streams

* media: PCM chunks end at 1 MiB only, as ffmpeg's do

ffmpeg's PCM chunks run past half a second, so a duration limit split
remuxed chunks the source kept whole.

* media: frames and samples indexed scale with the file's length

Matroska indexes at most one frame per 8 bytes of file and ISO BMFF at most
one sample per 4 bytes, beyond the first 2^20 of each, so the sample tables
stay within about ten times the file's size. Empty fixed-size laces and
one-byte constant-size samples could make them 40 to 76 times its size.

* media: clamp the frame and sample allowances
2026-10-23 15:42:51 -04:00
aiongg 46a49971c7 docking: format 2026-10-23 18:06:20 +00:00
aiongg 909410258b docking: document native window placement, moves and mixed scale factors 2026-10-23 18:06:10 +00:00