crates/forms/src/values.rs: the read imports take both listed_indices and
selected_options (list selection) and main's listing_fields_named (radio
fields sharing a name).
Main's DataOp::Value now replaces a multi-select list's value-group picks in the
packet and in the data copy, so the reset writes through it and the separate
DataOp::Reset (and Want::picks) is dropped. The reset keeps the PR's indexed
targets and its pass over fields without widgets, beside main's floating-field
pass (which the unshown pass leaves embedded fields to), and finish() lays out
again for either an owed relayout or a changed embedded value. Parity notes and
evidence take both sides.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
* M5: a comment whose colour is written [r g b null] is drawn, as CMYK with the null read as 0 (view.render-annotation-appearances)
ISO 32000-2 Table 166 /C (and /IC, Tables 178, 180, 181; /MK /BC and /BG,
Table 192) is an array of 0, 1, 3 or 4 numbers whose length picks the
colour space. A four-entry array with a non-number in it, such as
[1 0 0 null] (PDFBOX-2699), made the /C parser give up, so a shape
without an appearance stream was not drawn at all. PDFium, MuPDF and
Poppler all read such an array as CMYK with the non-number as 0.
- annot: a four-entry /C or /IC reads non-numbers as 0; other lengths
still need every entry to be a number.
- annot: the properties' fill uses the same parser (it read
[r g b null] as RGB before), and /C no longer drops a non-number
to make three numbers.
- forms: /MK /BC and /BG read a four-entry array the same way instead
of dropping the non-number and drawing RGB.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
* M5: comment properties report the stroke colour as drawn; a reference among four colour entries is not read as 0 (view.render-annotation-appearances)
props() reads a non-FreeText /C through the appearance parser, so a
[1 0 0 null] stroke reports CMYK cyan as drawn, and grey and CMYK
strokes report their converted colour. A reference among the four
entries of a /C array (ISO 32000-2 7.3.10) is left unreadable instead
of standing in as 0, so /C [1 0 0 6 0 R] is never drawn cyan.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
* M5: re-run CI (fill_sign Escape test depends on the clock's second, passes locally)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
* M5: the comment list reports a comment's colour as drawn (view.render-annotation-appearances)
summaries() accepted only a three-entry /C, so a Square with /C [1 0 0 null],
drawn cyan and reported cyan by props(), had no colour in the comment list;
grey and CMYK colours were dropped the same way. Non-FreeText comments now
read /C through drawn_color (the array itself followed when it is given by
reference), keeping the three-number fallback and the FreeText /DA handling.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
* M5: the render inspector lists a comment's colour as drawn (view.render-annotation-appearances)
The inspector accepted only a three-entry /C, with a referenced entry read
as 0, so a /C [1 0 0 null], a grey or a CMYK colour listed none, unlike the
comment list and the drawing. Non-FreeText comments now read /C by the
appearance builder's rule (one entry grey, four CMYK with a non-number as 0
and a reference unreadable, finite and clamped), with the three-number
fallback reading referenced entries.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyDBXygTf7jcqdsjcfn
---------
Co-authored-by: mtlcl410 <chuanlin@niar.org.tw>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Refs #2354. Thai typed into these tools is shaped and drawn from the Thai face through Add text's writer (now pdfcraft_fonts::shaped_text), searchable and copyable, instead of being written as ?????; a build without a Thai face refuses it with a message.
A widget's /AP /N that is neither a stream nor a state subdictionary with
a stream for /AS draws nothing (ISO 32000-2 12.5.5, Table 170), yet the
display copy treated any /N as the file's own appearance. Text, choice and
push-button widgets whose /N is null, a form XObject dictionary without its
stream data, or a subdictionary without /AS now get the drawn appearance a
widget without /N gets, and check boxes and radio buttons whose state entry
is not a stream are drawn from /MK. The test is the same one the renderer
uses to pick the stream.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
qualified_name reads each ancestor through Document::resolve, which follows an object that is
nothing but a reference to another, as document inspection does, so both name the kid the same.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
- fill: the first same-named field's read-only flag still applies when a later one draws the
choice, and no radio field of the name is written when any of them is read-only.
- enumerate: a nameless /Fields widget its parent already claimed is not read again as a nameless
field; one its parent's /Kids omits is still read on its own.
- walk: only kids whose /Subtype is /Widget replace a merged field's own widget.
- inspection: a kid whose /Parent is another field is named from that chain even under a direct
listing field, and widget annotations beside named kids are listed as a field of the parent's
name (ISO 32000-2 §12.7.4), as the form reader lists them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
A field dictionary that also carries a zero-area widget and lists widget
kids now has the kids as its buttons (ISO 32000-2 §12.7.4: field and
widget merge only for a single widget). Widget annotations listed beside
named kids, and nameless /Fields entries whose /Parent /Fields doesn't
list, are read as buttons of that parent's name.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
ISO 32000-2 §12.7.4.2: fields with the same fully qualified name have
the same value. Choosing a radio option by the name now writes the
choice as /V of a same-named twin that draws no button for it (its
buttons stay off), and of a field whose /Kids lists them without being
their /Parent, so it shares their name (issue15096.pdf's group, whose
/V was a stale Choice2). Exactly one button stays drawn on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
Adds the layout issue15096.pdf's last revision has: the two same-named
radio kids carry no /P (their page comes from /Annots), and both are
drawn on with /V that disagree (Off with /AS /Choice1, Choice2 with
/AS /Choice2). Choosing Choice1, Choice2 and Choice1 again by the name
leaves exactly the chosen button on after each save and reopen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
A field's fully qualified name is built from the partial names of the field
and its ancestors, and a child names its parent with /Parent (ISO 32000-2
§12.7.4.2, Table 226). A /Kids entry with /T whose /Parent does not name the
field listing it is now named up its own /Parent chain, in the form reader
and in document inspection, as PDFium and MuPDF name it: pdf.js's
issue15096.pdf lists its two radio fields as Group1, not Group1.Group1.
Fields with the same fully qualified name are one field (§12.7.4.2), so a
radio option that a later one of them draws is now chosen by the name: it is
written through the first field that draws it and the others turn off.
Before, only the first field's options were accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA