Merge upstream/main into fix/update-without-prev-is-refused

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
This commit is contained in:
mtlcl410andClaude Opus 5.5 committed 2026-11-08 20:50:01 +08:00
commit d6ffacbd19
134 files changed
+8929 -647

No files matched your search

+26 -14
View File
@@ -3226,8 +3226,8 @@ milestone = "M4"
status = "shipped"
commands = ["page.crop"]
tools = ["page_set_box"]
evidence = ["crates/ui-egui/tests/it/pageboxes.rs::the_crop_tool_crops_to_the_dragged_rectangle_then_returns_to_select"]
notes = "drag to crop; double-click opens Set Page Boxes"
evidence = ["crates/ui-egui/tests/it/pageboxes.rs::the_crop_tool_crops_to_the_dragged_rectangle_then_returns_to_select", "crates/ui-egui/tests/it/pageboxes.rs::quick_toolbar_crop_crops_the_page_and_undo_restores_it", "crates/ui-egui/tests/it/pageboxes.rs::quick_toolbar_crop_is_disabled_when_page_assembly_is_forbidden", "crates/ui-egui/tests/it/pageboxes.rs::quick_toolbar_crop_is_hidden_on_home_and_in_read_mode"]
notes = "drag to crop; double-click opens Set Page Boxes; Crop pages is also directly available in the document quick toolbar (#5330), using the existing command availability and assembly permission check. The quick toolbar is hidden on Home and in Read/full-screen modes; arbitrary toolbar customization remains outside this feature."
[[feature]]
id = "organize.remove-white-margins"
@@ -3322,8 +3322,8 @@ milestone = "M4"
status = "shipped"
commands = []
tools = ["bookmark_rename"]
evidence = ["crates/ui-egui/tests/it/bookmarks.rs::new_rename_reorder_indent_delete_and_undo", "crates/ui-egui/tests/it/bookmarks.rs::escape_cancels_a_rename", "crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/organize/src/tests.rs::bookmark_edits_keep_unknown_keys_and_touch_few_objects"]
notes = ""
evidence = ["crates/ui-egui/tests/it/bookmarks.rs::new_rename_reorder_indent_delete_and_undo", "crates/ui-egui/tests/it/bookmarks.rs::escape_cancels_a_rename", "crates/ui-egui/tests/it/bookmarks.rs::typing_replaces_the_title_when_the_editor_opens", "crates/ui-egui/tests/it/bookmarks.rs::a_rename_editor_keeps_the_users_caret_across_frames", "crates/organize/src/tests.rs::bookmarks_add_rename_move_delete", "crates/organize/src/tests.rs::bookmark_edits_keep_unknown_keys_and_touch_few_objects"]
notes = "The inline editor opens with the whole title selected, so typing replaces it at once (#5529); a caret the user moves afterwards is kept by later frames."
[[feature]]
id = "organize.bookmark-delete"
@@ -4613,9 +4613,9 @@ tier = "P0"
milestone = "M2"
status = "shipped"
commands = []
tools = []
evidence = ["crates/render/src/raster/tests.rs::widget_appearance_states", "crates/engine/src/tests.rs::validated_signatures_without_layers_keep_their_appearance", "crates/engine/src/tests.rs::real_layered_signatures_keep_their_original_appearance", "crates/engine/src/tests.rs::real_layered_signatures_round_trip_behind_a_user_password", "crates/engine/src/tests.rs::a_metadata_edit_keeps_the_original_signature_appearance", "crates/engine/src/tests.rs::saving_after_an_edit_keeps_the_baked_appearance", "crates/engine/src/tests.rs::chamfered_signature_borders_survive_trust_exports_printing_and_save", "crates/engine/src/tests.rs::mixed_signature_caption_details_survive_trust_exports_printing_and_save", "crates/engine/src/tests.rs::buttons_and_combs_left_to_the_viewer_are_displayed", "crates/forms/src/tests.rs::button_states_without_an_appearance"]
notes = "widgets retain their original artwork. Signature validation is a separate viewer page overlay; it is never written into document streams or included in image/text exports, vector printing or Print as Image. Saves retain signed appearance bytes. Generic in-place appearance rewriting is deferred: no supported producer template is positively identified, and caption text plus drawing uniqueness does not establish an icon role. Baked Not Verified captions remain unchanged; issue #79 is not fully resolved. Check boxes and radio buttons with no appearance for their state are shown (display-only) with their /MK border and background and, when on, the /MK /CA ZapfDingbats symbol in the /DA colour (a check or a dot by default); push buttons with none show their /MK frame and caption; files that carry their own appearances are not redrawn."
tools = ["page_render", "sign_list"]
evidence = ["crates/render/src/raster/tests.rs::widget_appearance_states", "crates/engine/src/tests.rs::validated_signatures_without_layers_keep_their_appearance", "crates/engine/src/tests.rs::real_layered_signatures_keep_their_original_appearance", "crates/engine/src/tests.rs::real_layered_signatures_round_trip_behind_a_user_password", "crates/engine/src/tests.rs::a_metadata_edit_keeps_the_original_signature_appearance", "crates/engine/src/tests.rs::saving_after_an_edit_keeps_the_baked_appearance", "crates/engine/src/tests.rs::chamfered_signature_borders_survive_trust_exports_printing_and_save", "crates/engine/src/tests.rs::mixed_signature_caption_details_survive_trust_exports_printing_and_save", "crates/engine/src/tests.rs::buttons_and_combs_left_to_the_viewer_are_displayed", "crates/forms/src/tests.rs::button_states_without_an_appearance", "crates/ui-egui/src/canvas/tests.rs::the_verdict_mark_takes_the_corner_nearest_its_anchor", "crates/ui-egui/src/canvas/tests.rs::the_verdict_mark_scales_with_the_widget_until_the_cap", "crates/ui-egui/src/canvas/tests.rs::the_verdict_mark_stays_inside_its_widget_at_every_finite_size", "crates/sign/src/status_layers.rs::has_status_layers_recognises_only_named_layer_layouts", "crates/sign/src/status_layers.rs::captions_in_other_scripts_use_a_face_made_for_them_or_english", "crates/sign/src/status_layers.rs::the_originals_are_untouched_and_the_widget_points_at_copies", "crates/sign/src/status_layers.rs::two_fields_sharing_a_layer_form_each_show_their_own_state", "crates/engine/src/tests.rs::named_layer_signatures_show_their_state_through_trust_save_and_reopen", "crates/engine/src/tests.rs::named_layer_signatures_round_trip_behind_a_user_password", "crates/engine/src/tests.rs::a_tampered_named_layer_signature_shows_the_invalid_state", "crates/engine/src/tests.rs::named_layer_states_reach_exports_and_both_print_modes", "crates/engine/src/tests.rs::caption_language_follows_the_session_captions", "crates/ui-egui/tests/it/status_layers.rs::named_layers_follow_trust_and_language_and_keep_the_badge", "crates/ui-egui/tests/it/status_layers.rs::a_badge_tip_stays_hidden_while_a_dialog_covers_the_page", "crates/ui-egui/tests/it/status_layers.rs::arabic_caption_keeps_logical_word_order_on_page_and_in_extracted_text", "crates/ui-egui/tests/it/status_layers.rs::an_edit_on_another_page_that_changes_the_verdict_redraws_the_signature", "crates/ui-egui/tests/it/status_layers.rs::a_file_opened_before_the_first_frame_is_drawn_in_the_interface_language", "crates/ui-egui/src/canvas/tests.rs::signature_badges_keep_every_verdict_the_appearance_shows", "crates/ui-egui/src/canvas/tests.rs::the_verdict_mark_turns_with_the_page_and_the_view", "crates/engine/src/tests.rs::cli_display_draws_signature_states_as_the_app_does_without_trust", "crates/render/src/text/tests.rs::actual_text_over_painted_paths_reads_where_they_are_painted", "crates/render/src/text/tests.rs::actual_text_over_paint_reads_only_where_it_shows", "crates/automation/tests/it/automation.rs::named_layer_verdicts_are_reported_and_rendered_through_tools", "crates/sign/src/status_layers.rs::shared_appearances_are_copied_once_however_many_widgets_draw_them"]
notes = "widgets retain their original artwork, except a signature widget whose /N draws, from its own resources, exactly one Form that holds and draws both n1 and n3 (the named-layer convention): there n1, n3 and n4 are redrawn for the signature's state, with the panel's Lucide icons (circle-check, triangle-alert, circle-x) and Signature valid, Validity unknown or Signature invalid in the interface language. The caption is in Helvetica when WinAnsi encodes the words; otherwise shaped in embedded Inter (Latin, Cyrillic, Greek), or in a craft-fonts face for Arabic, Japanese, Telugu, Thai and Devanagari when the build has one, drawn as filled outlines (the Arabic and Telugu faces are variable fonts, which can't be embedded); otherwise English, as Chinese always is. The redraw lives in the display copy only, built from copies made once per original and state, so a stream shared between fields never carries one verdict onto another and shared streams are not multiplied. The screen, the CLI's render (no trusted certificates), image and text exports (text extraction reads every caption, an outline one through its /ActualText at the outlines' visible box), Print as Image and vector printing show it; saves never do, so the signed bytes and the signature stay as they were. An edit that changes a verdict redraws every page, not only the edited one. Every signature, recognised or not and whatever its state, also gets a separate viewer overlay: the widget's outline and a mark at a quarter of its shorter side (48 screen points at most) in its bottom-right corner as it lies on the page, so the mark turns with the page's /Rotate and the view, keeps off the middle of the signer's artwork and clear of a named-layer caption across the top. It stays because a document's own layers can clip or cover the drawn state. A widget whose shorter side falls under 32 screen points (as fields do with the page zoomed out to fit) carries the verdict in its outline alone, and a widget whose rectangle the screen cannot place is not drawn at all. The overlay answers the pointer over the whole widget, as far as the page goes, except under a dialog, Fill & Sign or freehand drawing; it is never document content. Not covered: an /N drawing two qualifying layer forms (refused), a recognised appearance that turns itself against a rotated page (its mark may meet the caption), and overlays for fields whose first widget is not the visible one. Check boxes and radio buttons with no appearance for their state are shown (display-only) with their /MK border and background and, when on, the /MK /CA ZapfDingbats symbol in the /DA colour (a check or a dot by default); push buttons with none show their /MK frame and caption; files that carry their own appearances are not redrawn."
[[feature]]
id = "form.fill-text"
@@ -5826,6 +5826,18 @@ tools = ["redact_mark"]
evidence = ["crates/redact/src/patterns.rs::labelled_italian_international_slash_numbers_match_whole", "crates/automation/tests/it/automation.rs::redacting_italian_international_slash_numbers_through_tools", "crates/redact/src/patterns.rs::phone_numbers", "crates/redact/src/patterns.rs::slashed_and_labelled_unseparated_phone_numbers", "crates/redact/src/patterns.rs::credit_cards_need_a_valid_checksum", "crates/automation/tests/it/automation.rs::redacting_through_tools"]
notes = "phone (North American, E.164 with + country code, national with trunk 0, a slash after a trunk-0 area code; labelled Italian +39 geographic numbers with one slash after the area code match with their complete country code (#3205 follow-up), with or without one space after +39; international slash numbers without a phone label, or with country codes other than +39, remain unsupported; numbers without separators only after a phone label such as Tel. or cell.), e-mail, credit card (Luhn), SSN, dates (English US forms); text drawn in a font whose built-in encoding we hold no table for (Symbol, ZapfDingbats, MacExpert) has no Unicode mapping, so a pattern search cannot see it -- it is skipped rather than mis-decoded"
[[feature]]
id = "protect.redact-regex"
title = "Redact by caller-supplied regular expression"
area = "G"
tier = "P2"
milestone = "M8"
status = "shipped"
commands = []
tools = ["redact_mark"]
evidence = ["crates/redact/src/user_regex.rs::hostile_expressions_are_refused_or_stay_linear", "crates/redact/src/user_regex.rs::validators_filter_matches", "crates/automation/tests/it/automation.rs::redacting_with_a_caller_regex_through_tools"]
notes = "Headless only (redact_mark regex, optional validate luhn, mod97 or iban; issue #1886): no UI entry yet. Rust regex syntax, matched in linear time with no look-around or back-references; expression capped at 1024 bytes, compiled size and nesting capped, empty-matching expressions refused. Matches run on the page text as the pattern matchers see it (words and lines joined by one space), so a match cannot span a page break. Missing: a UI field, a mask for checksums that need more than the whole match (for example the French social security key), and a check against Acrobat's own custom-pattern syntax (not observed)."
[[feature]]
id = "protect.redact-pattern-locales"
title = "Pattern sets per locale"
@@ -5955,8 +5967,8 @@ milestone = "M8"
status = "shipped"
commands = ["redact.apply"]
tools = ["redact_apply"]
evidence = ["crates/redact/src/tests.rs::tags_lose_what_redaction_removed", "crates/redact/src/tests.rs::applied_redactions_drop_structure_tree_references_to_what_they_remove"]
notes = "marked content changed by redaction is found by comparing each MCID before and after; its elements lose Alt, ActualText and E, and references to now-empty marked content are dropped; object references (OBJR) to the comments and form fields redaction removes are dropped too (#2874); untouched tags stay"
evidence = ["crates/redact/src/tests.rs::tags_lose_what_redaction_removed", "crates/redact/src/tests.rs::applied_redactions_drop_structure_tree_references_to_what_they_remove", "crates/redact/src/tests.rs::redacted_paint_loses_the_actual_text_that_names_it", "crates/engine/src/tests.rs::a_word_drawn_as_outlines_is_redacted_with_its_name"]
notes = "marked content changed by redaction is found by comparing each MCID before and after; its elements lose Alt, ActualText and E, and references to now-empty marked content are dropped; object references (OBJR) to the comments and form fields redaction removes are dropped too (#2874); untouched tags stay. Inline marked content around anything redaction removed, changed or clipped (a path partly under a mark is removed, a shading clipped) loses its /ActualText, /Alt, /E and /T, so a word drawn as outlines and partly redacted leaves no name behind"
[[feature]]
id = "protect.redaction-verification"
@@ -6427,8 +6439,8 @@ milestone = "M9"
status = "shipped"
commands = ["sign.panel"]
tools = ["sign_list"]
evidence = ["crates/ui-egui/tests/it/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/sign/tests/it/pdf.rs::a_hidden_signature_field_is_listed_as_not_visible"]
notes = "sign_list reports a signature as visible only when its widget has a box and isn't Hidden or NoView, as form widgets are read, so a hidden field gets no badge on the page"
evidence = ["crates/ui-egui/tests/it/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/sign/tests/it/pdf.rs::a_hidden_signature_field_is_listed_as_not_visible", "crates/engine/src/tests.rs::named_layer_signatures_show_their_state_through_trust_save_and_reopen", "crates/ui-egui/tests/it/status_layers.rs::named_layers_follow_trust_and_language_and_keep_the_badge"]
notes = "sign_list reports a signature as visible only when its widget has a box and isn't Hidden or NoView, as form widgets are read, so a hidden field gets no badge on the page. The state also shows inside named-layer signature appearances (icon in n1 or n3, caption in n4; see form.field-appearance-display), in the same colours as the panel and badge."
[[feature]]
id = "sign.validation-banner"
@@ -6440,7 +6452,7 @@ status = "shipped"
commands = ["sign.panel"]
tools = []
evidence = ["crates/ui-egui/tests/it/signing.rs::drawing_a_signature_creating_an_id_signing_and_trusting", "crates/ui-egui/tests/it/signing.rs::certifying_without_a_visible_signature", "crates/ui-egui/src/canvas/tests.rs::signature_badges_keep_signed_visible_widgets_on_the_page"]
notes = "signed/valid, problems, invalid and certified bars; visible signed widgets also carry a separate viewer validation overlay. Trust and explicit validation invalidate view caches without editing document artwork; baked appearance captions remain unchanged."
notes = "signed/valid, problems, invalid and certified bars; visible signed widgets also carry a separate viewer validation overlay. Trust and explicit validation invalidate view caches without editing saved document artwork; recognised named-layer appearances are redrawn only in the display copy, exports and print paths."
[[feature]]
id = "sign.signature-properties"
@@ -7487,8 +7499,8 @@ milestone = "M11"
status = "partial"
commands = ["optimize.advanced"]
tools = ["doc_optimize"]
evidence = ["crates/automation/tests/it/optimize_content_boundaries.rs::fragment_merge_preserves_a_comment_across_content_pieces", "crates/ui-egui/tests/it/create.rs::the_pdf_optimizer_dialog_saves_an_optimized_copy", "crates/automation/tests/it/automation.rs::optimizing_through_tools", "crates/ui-egui/src/workflows/optimize_ui.rs::the_progress_card_shows_the_stage_and_cancels", "crates/engine/src/tests.rs::an_optimize_job_reports_its_stages_and_can_be_cancelled", "crates/optimize/tests/optimize.rs::images_and_forms_nothing_draws_are_dropped", "crates/automation/tests/it/automation.rs::a_deleted_image_is_not_kept_by_reduce_or_optimize", "crates/ui-egui/tests/it/create.rs::the_pdf_optimizer_dialog_picks_a_preset", "crates/automation/tests/it/automation.rs::a_page_printed_in_strips_gets_small_through_tools", "crates/optimize/tests/optimize.rs::the_mobile_preset_makes_a_printed_page_small"]
notes = "Settings menu with the Standard and Mobile presets (Custom once an option changes; doc_optimize preset), Images (with Merge image fragments: a page picture drawn as one-pixel strips, as some PDF printers write it, is put back together so it can be resampled), Discard Objects, Discard User Data, Clean Up (also drops images and forms the pages list but never draw, such as deleted images); runs in the background with a progress bar (per image) and Cancel; no Fonts or Transparency panels, no saved custom presets, no space audit"
evidence = ["crates/automation/tests/it/optimize_content_boundaries.rs::fragment_merge_preserves_a_comment_across_content_pieces", "crates/ui-egui/tests/it/create.rs::the_pdf_optimizer_dialog_saves_an_optimized_copy", "crates/automation/tests/it/automation.rs::optimizing_through_tools", "crates/automation/tests/it/automation.rs::optimizing_to_a_target_size", "crates/ui-egui/src/workflows/optimize_ui.rs::the_progress_card_shows_the_stage_and_cancels", "crates/engine/src/tests.rs::an_optimize_job_reports_its_stages_and_can_be_cancelled", "crates/optimize/tests/optimize.rs::images_and_forms_nothing_draws_are_dropped", "crates/automation/tests/it/automation.rs::a_deleted_image_is_not_kept_by_reduce_or_optimize", "crates/ui-egui/tests/it/create.rs::the_pdf_optimizer_dialog_picks_a_preset", "crates/automation/tests/it/automation.rs::a_page_printed_in_strips_gets_small_through_tools", "crates/optimize/tests/optimize.rs::the_mobile_preset_makes_a_printed_page_small"]
notes = "Settings menu with the Standard and Mobile presets (Custom once an option changes; doc_optimize preset), Images (with Merge image fragments: a page picture drawn as one-pixel strips, as some PDF printers write it, is put back together so it can be resampled), Discard Objects, Discard User Data, Clean Up (also drops images and forms the pages list but never draw, such as deleted images); runs in the background with a progress bar (per image) and Cancel; no Fonts or Transparency panels, no saved custom presets, no space audit; headless-only optional target_bytes retries up to 5 stronger image steps (an automation extension, not an Acrobat feature)"
[[feature]]
id = "optimize.downsample-images"