Repository navigation
M6: check boxes, radio buttons and push buttons without an appearance are drawn, and comb fields show their cells (ISO 32000-2 Table 192, 12.7.5) - #4368
Conversation
… are drawn, and comb fields show their cells (ISO 32000-2 Table 192, 12.7.5) A form that leaves its appearances to the viewer had its text and choice fields drawn for display (storytold#3475), but not its buttons. Now, also for display only, without changing the file: - Check boxes and radio buttons with no normal appearance for their state show their /MK background and border (Table 192), and when on, the /MK /CA caption as a standard-14 ZapfDingbats character (12.7.5.2.3), 4 or l by default, in the /DA colour, auto-sized for 0 Tf. - Push buttons with none show their /MK background, their /BS border (beveled per Table 168) and their centred caption. - Comb fields with a border colour draw the MaxLen - 1 lines between their positions (Table 228), up to 500 cells. This also applies to the appearances PdfCraft saves for comb fields. - A combo box drawn for display shows a drop-down button on screen, with its text kept clear of it. Saved appearances and Print as Image leave it out (with_printed_field_appearances, printed_display_bytes). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
The on-screen drop-down button for combo boxes drawn display-only, the narrowed text area beside it, and the Print as Image copy without it (with_printed_field_appearances, printed_display_bytes) are removed. Open PR storytold#3567 draws the arrow for every combo box in the page view. Check boxes, radio buttons, push buttons and comb lines are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
|
No actionable comments were generated in the recent review.
|
| Layer / File(s) | Summary |
|---|---|
Generate comb and button appearances crates/forms/src/appearance.rs, crates/forms/src/author.rs, crates/forms/src/tests.rs, crates/forms/README.md, parity/acrobat-features.toml |
Comb appearances draw border-colored dividers for 2–500 cells when the border dimensions are valid. Button fallback appearances draw frames and, where applicable, symbols or captions. Tests cover appearance settings, existing appearances, malformed settings, and comb limits. |
Integrate fallback appearances into display copies crates/forms/src/lib.rs, crates/engine/src/tests.rs, parity/acrobat-features.toml |
The cache generates missing button appearances for display copies, stores them under named normal-appearance states, and updates /AS. Rendering tests check button and comb output and verify that saving leaves widgets without generated appearances. |
Priority:
Estimated code review effort: 3 (Moderate) | ~20 minutes
Change: Bug fix · Severity of issue fixed: Medium
Suggested reviewers: echelon
Merge Risk: 
Minimal · up to dd1a8
-
The reviewed display-only appearance changes are mergeable after normal checks.
Security architecture risk: 
Low · up to dd1a8
-
Generated appearances remain separate from the saved document, and the inspected rendering paths introduce no additional file, network, or action-execution privileges. Remaining uncertainty concerns resource limits for unusually large inputs and confirmation against the full prior version.
Retained concerns
No architecture-level concerns identified.Security review details
-
Security Blast Radius
- inferred — The inspected exposure is document-controlled widget data reaching appearance generation and downstream rendering. Any resource impact would affect the rendering consumer; no additional tenant, credential, service, or environment authority was identified in this call chain.
Security Findings and Attack Paths
- inferred — A document can newly cause a missing push-button appearance to render its caption or document-owned icon. The inspected path emits rendering operators and resources, not document actions or external I/O. No authority-escalation attack path was established from this added reachability.
Trust Boundaries and Controls
- observed — Generated appearances belong to a derived document overlay. Existing source objects remain separate from AP and AS updates, and persistent saving uses a different document root from display serialization.
Resilience and Maintainability Implications
- observed — The appearance cache stores derived streams against tracked input-object identities and invalidates reuse when those identities change. Its mutable-reference API requires exclusive access rather than exposing unsynchronized shared mutation.
-
Pre-merge checks: 
5
-
Full details: Description check
-
Explanation
The description is complete and follows the repository template. It explains the behavior change, verification commands and results, tests, safety checks, provenance, security, parity updates, scope limitations, and reviewer focus areas.
Full details: Linked Issues check
-
Explanation
The changes satisfy the coding requirements in
#4367.with_field_appearances_cachedadds display-copy handling for missing checkbox and radio-button state appearances and missing push-button appearances.button_state_showndraws/MK /BG,/MK /BC, and the on-state ZapfDingbats caption with/DAcolor and sizing.push_button_showndraws the frame and centered/MK /CAcaption.comb_dividersdraws the boundedMaxLen - 1dividers in the border color and width. The tests cover these cases, malformed input, saved-file preservation, and generated comb appearances.
Full details: Out of Scope Changes check
-
Explanation
The changes stay within
#4367. The added tests, README and parity updates document and verify the requested display-only button behavior and comb dividers. The crate-visiblebutton_appearancechange supports the existing icon path. The PR leaves combo-box arrow work to#3567and does not add unrelated product behavior.
Full details: Docstring Coverage
-
Explanation
Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 21 functions across 5 files. (2 skipped: 2 unsupported.)
-
Finishing Touches: 💡 1
-
🧪 Generate unit tests (beta)
-
- Create a new PR
🛠️ Fix failing CI checks: 💡
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
Comment @coderabbitai help to get the list of available commands.
…K caption (ISO 32000-2 Table 224) (#4454) * M6: with NeedAppearances, check boxes and radio buttons draw their /MK caption (ISO 32000-2 Table 224) A form that sets /NeedAppearances asks the viewer to construct the appearances of its widgets (ISO 32000-2 Table 224; deprecated in PDF 2.0). The display copy already redraws text and choice fields for it, but check boxes and radio buttons kept the file's own appearance streams, so a box whose /MK /CA is ZapfDingbats 4 (a check mark) showed the filled square its /AP carried. With /NeedAppearances, every check box and radio button that has an /MK is now drawn in its current state through button_state_shown (merged in #4368): /MK /BG and /BC, and when on the /MK /CA ZapfDingbats character (Table 192) in the /DA colour, sized to the box. A widget without /MK keeps its own appearance, and without /NeedAppearances nothing changes. A radio button with no /AS now takes its state from /V when /V names its own on state. Display and print only: the file is saved as it was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC * chore(forms): wrap button_state_shown's doc comment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com>
…K caption (ISO 32000-2 Table 224) (storytold#4454) * M6: with NeedAppearances, check boxes and radio buttons draw their /MK caption (ISO 32000-2 Table 224) A form that sets /NeedAppearances asks the viewer to construct the appearances of its widgets (ISO 32000-2 Table 224; deprecated in PDF 2.0). The display copy already redraws text and choice fields for it, but check boxes and radio buttons kept the file's own appearance streams, so a box whose /MK /CA is ZapfDingbats 4 (a check mark) showed the filled square its /AP carried. With /NeedAppearances, every check box and radio button that has an /MK is now drawn in its current state through button_state_shown (merged in storytold#4368): /MK /BG and /BC, and when on the /MK /CA ZapfDingbats character (Table 192) in the /DA colour, sized to the box. A widget without /MK keeps its own appearance, and without /NeedAppearances nothing changes. A radio button with no /AS now takes its state from /V when /V names its own on state. Display and print only: the file is saved as it was. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC * chore(forms): wrap button_state_shown's doc comment Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Brandon Thomas <echelon@gmail.com> (cherry picked from commit 8708f35)
What this changes
Fixes #4367.
The need. A form can leave its appearances to the viewer, with
/NeedAppearancesor with widgets that have no/AP. #3475 draws text and choice fields in that case, for display only. Buttons were left out:The basis. ISO 32000-2:
BCandBGare the widget's border and background colours.CAis "the widget annotation's normal caption", and it "may be used with any type of button field, including check boxes … and radio buttons"./ASstate, and the example's on state draws(4) Tjin/ZaDb, the ZapfDingbats check mark (Annex D.6)./S /Bis a beveled border, "a simulated embossed rectangle".The change (
pdfcraft_forms::with_field_appearances,appearance.rs)/AS; else a check box's/V; else Off), or none at all, are drawn into the display copy (button_state_shown):/MK /BGbackground and the/MK /BCborder, through the existingframe(/BSwidth and style);/MK /CAin the standard-14 ZapfDingbats font, so no font program is needed and it renders on wasm;4(check mark) for a check box andl(dot) for a radio button;/DAcolour, at the/DAsize, or at 80% of the room inside the border for0 Tf.push_button_shown): the sameframe, so/BS /W 2 /S /Bis a 2 pt beveled border, and the caption centred through the existingbutton_caption. A button with an icon (/MK /I) is drawn by PdfCraft's ownbutton_appearance.MaxLen - 1lines between their positions (comb_dividers), in the border's colour and/BSwidth, inside the border. Above 500 cells nothing is drawn; that many lines would be a solid block./APin the file, except the comb lines in appearances PdfCraft generates itself.How you verified it
cargo fmt --all -- --check-D warningson the crates I changed:-p pdfcraft-forms -p pdfcraft-engine -j 2 --all-targets -- -D warningscleanpdfcraft-forms153 passed, 0 failed;pdfcraft-engine351 passed, 0 failed, 4 ignoredcargo check --workspace --all-targets,cargo xtask layers,cargo xtask assets,cargo xtask parity: all clean (37 crates, no layering violations; assets ok)Tests (synthetic fixtures)
check_boxes_without_an_appearance_show_their_caption_symbol:/CA4, l, 8 and H in black, blue, red and black, each with its border; a/DAsize is kept; the font is the standard-14 ZapfDingbats.button_states_without_an_appearance:l;/CA(an integer),/DA(nan Tf,1 x rg),/BC,/BGand a negative/BS /Wgive the default symbol and no border, without a panic;push_buttons_without_an_appearance_show_their_caption_and_frame: grey background, 2 pt border, the light and dark bevel, the caption at its/DAsize.comb_fields_show_their_cells:/MaxLen 2^40gives no lines and no trouble;/MK /BC, no lines either.buttons_and_combs_left_to_the_viewer_are_displayed(engine, pixels):print_raster::rasterize) shows the cross and the button too;/APon any of the widgets.pdfcraft-cli render, now shows I–L, O and D as described there.Mutants. Each of these makes a test fail:
/APnot drawn (forms tests, and the engine pixel test);/MK /CAignored;4;/DAcolour ignored.Never-crash
unwrap/expect/panic!/unreachable!/todo!outside testsu8::try_from, and only if ZapfDingbats has a glyph there./DAsizes are capped at 300 byparse_da, the automatic size is clamped to 1–300, and a NaN or negative/BS /Wis 0. Comb lines need a finite, positive border width and are capped at 500 cells, so a huge/MaxLenallocates nothing.unsafeProvenance
ATTRIBUTION.tomlentrySecurity
Parity and reach
view.render-annotation-appearancesandform.field-appearance-displaynotes say which buttons are drawn display-only.form.fill-textnotes the comb cells. Existing text is kept.page_render, the CLIrendercommand, image exports and Print as Image. Vector printing still uses the file's own appearances, as before.Anything a reviewer should look at first
How each choice was decided. The standard decides where it speaks. Where it is silent, the majority of five other conforming viewers decides, as observed on the synthetic fixture of the issue. Where they split, the first of them (viewer A) decides.
/MK /CAsymbol of an on check boxCAthe normal caption of any button field, and §12.7.5.2.3's example draws(4)in ZapfDingbats. Only 3 of 5 viewers draw it (viewer A shows the border only), and the standard wins./MK /BCborder and/MK /BGbackground of buttons without/APBG,BC,CA) and Table 168 (/S /B); 5 of 5 viewers agree0 Tf(80% of the room inside the border)/DAcolour/DAsets the colour of the field's variable text; the 3 viewers that draw the symbol agree/CA:4for check boxes,lfor radio buttons4(§12.7.5.2.3's example). Forlthe standard is silent and the fixture has no case without/CA, so it is PdfCraft's existing default for radio buttons (the dot).MaxLenpositions but doesn't say to draw them; 4 of 5 viewers draw the lines, viewer A includedSaved comb appearances change. The comb lines are in the shared text-field drawing code, so a comb field with a border colour that PdfCraft fills or authors now saves the lines in its
/APtoo. Comb fields without/MK /BCare unchanged. No existing test asserted the old look; the new test covers the saved appearance.Overlap with open PRs.
check_markandcheck_box_states(the mark colour of PdfCraft's own check boxes). This PR doesn't touch either. It draws display-only symbols as ZapfDingbats text and reads the/DAcolour with the existingparse_da.frame. This PR only callsframe. A round XFA check button drawn display-only would pick that frame up.TextBoxnearauto_text_size_by. The comb change here is one line insidefield_appearance_drawn, plus helpers afterborder_width.Check box state. A widget is redrawn when it has no
/AP /N, or when/Nis a state dictionary without its on state./NeedAppearancesalone doesn't redraw check boxes, radio buttons or push buttons that have appearances, so a file's own symbols are kept.🤖 Generated with Claude Code
https://claude.ai/code/session_0175FWj4xFhMhSH3UpMU8DSC
Summary by CodeRabbit