70 Commits
Author SHA1 Message Date
bflatastic a7bc9c5301 Merge #6620: M5: comments keep their formatting and appearance through XFDF and FDF (comment.import-fdf-xfdf, comment.export-fdf-xfdf)
# Conflicts:
#	crates/xfdf/src/xfdf.rs
2026-11-09 08:21:11 +07:00
mtlcl410 6062cd6a44 M5: Replace Text keeps its replacement on the group's primary, the caret (comment.replace-text) (#5689) 2026-11-09 08:38:25 +08:00
mtlcl410andClaude Opus 5.5 79b7a79d97 M5: comment imports leave field values alone and paste keeps the appearance budget for what import reads (comment.import-fdf-xfdf, comment.export-fdf-xfdf)
- Appearance export checks a stream's size in the encoding it is written in
  (printable data as text, not as hexadecimal).
- Copy no longer writes a redaction mark's appearance, which import never
  reads, so it does not use up the budget the other comments share.
- Rich text: a namespace declaration inside another attribute's value is not
  a declaration, a '>' in a value does not end the start tag, and a prefixed
  root keeps the default namespace its unprefixed descendants inherit.
- import_comments never applies the file's field values, whatever the
  placement arguments (a non-finite offset used to fall through to them).
- The repair-log line for skipped appearances escapes control characters and
  cuts each description to 200 characters.
- Tests for the shared budget through the export loop, a near-limit appearance
  that round-trips, and the six-comment summary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 02:59:47 +08:00
mtlcl410andClaude Opus 5.5 9bd278a9b3 M5: comment imports are all or nothing and appearance export stops where import does (comment.import-fdf-xfdf, comment.export-fdf-xfdf)
- import and import_comments work on a copy, kept only on success.
- XFDF export shares the 64 MiB appearance budget import reads over all
  comments; import refuses a normal appearance of several states (XFDF has
  no /AS to select one, ISO 32000-2 §12.5.5).
- FDF import nulls a page or page tree an appearance reaches (/Type resolved).
- Rich text: an inherited default namespace other than XFDF's is declared,
  and a namespace declaration with spaces around `=` is recognised.
- A redaction mark's /Rect grows to hold its quads, so the outline shows.
- The repair log gets one line per import (first five, then a count), and
  no longer claims the comment is drawn.
- Tests: the sixty-form chain, and the redaction outline is stroked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 02:12:23 +08:00
mtlcl410andClaude Opus 5.5 97373fba4e M5: imported appearances arrive whole or are said, and redaction marks are always drawn (comment.import-fdf-xfdf, comment.export-fdf-xfdf)
- XFDF export: the finished appearance XML is checked against the import limit;
  a page whose /Type is a reference stays out; stream data with a carriage
  return goes out as hex (XML 1.0 §2.11 end-of-line handling); where /AS selects
  one of several states, the selected stream is written.
- XFDF import: dash arrays of any length come back; consecutive <br/> keep the
  blank line in /Contents; rich text written as text on a comment with no
  /Contents comes back as /RC; namespace prefixes rich text inherits are declared
  on it; appearances share one budget over the import (now tested through it).
- Redaction marks: the file's /AP and a /BE (none in ISO 32000-2 Table 195) are
  dropped and the mark is drawn by PdfCraft; one with an area it cannot draw is
  refused rather than placed invisible.
- FDF import: /P is not copied (the page is /Page, §12.7.8.3.4 Table 254); a
  comment nested past 256 levels refuses the file instead of nulling part of its
  appearance (a chain of 60 forms comes back whole).
- Engine: appearances an import left out go to the repair log for Import and
  Paste comments.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-09 01:22:12 +08:00
mtlcl410andClaude Opus 5.5 56b3738089 M5: FDF carries a stamp's appearance only, and the intent goes out as intent and IT (comment.export-fdf-xfdf, comment.import-fdf-xfdf)
FDF export now leaves /AP out of every comment but a stamp, as XFDF
3.0 gives <appearance> to stamps only: a text box, square or line
carries its formatting entries (/DA, /DS, /RC, /Q, /Rotate, /BS, /RD)
and is drawn where it is imported. FDF import still keeps any /AP the
file carries.

XFDF export writes a comment's /IT under both spellings XFDF files
use, `intent` and `IT`, and import reads either, so a typewriter or
callout text box from a file that writes `IT` keeps its intent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 20:06:39 +08:00
mtlcl410andClaude Opus 5.5 6ae0527883 M5: an exported appearance leaves the source page out (comment.export-fdf-xfdf)
A page or page tree reached from a comment's appearance is written as
NULL in <appearance>, as FDF export already nulls source /Page and
/Pages dictionaries, so the XFDF never carries the document's pages.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 17:46:31 +08:00
mtlcl410andClaude Opus 5.5 a90502f2c9 M5: comments keep their formatting and appearance through XFDF and FDF (comment.import-fdf-xfdf, comment.export-fdf-xfdf)
XFDF export and import carry each comment's formatting as XFDF 3.0
(ISO 19444-1) names it: contents-richtext (/RC), defaultstyle (/DS),
width/style/dashes (/BS, or an older /Border), cloudy style and
intensity (/BE), rotation, justification (/Q), fringe (/RD) on every
type, leaderLength/leaderExtend/leader-offset and the caption
attributes of lines, the caret symbol and redaction overlay text.

A stamp's appearance travels as <appearance>: base 64 of the
DICT/STREAM/ARRAY/NAME/INT/FIXED/BOOL/STRING/NULL XML other tools
write, with stream data in DATA as XFDF 3.0 "Stream encoding" gives it.
Copy and paste carries every comment's appearance. Import keeps an
appearance it can read (never on a redaction mark), records an
unreadable one in Report::skipped and draws the comment instead; it is
bounded at 16 MiB per appearance, 64 MiB per import, 64 levels and
100,000 values.

FDF export keeps /AP with the forms and images it draws (ISO 32000-2
§12.7.8.3.4); FDF import copies those streams into the document, once
when shared, only for comments that land on a page, and no longer
nulls values past 16 levels (a gradient stamp's shading functions sit
deeper).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyCHD1R3rywQBPCHXZA
2026-11-08 17:43:00 +08:00
42bc4f117d M5: copy and paste comments between documents, select several, finish connected lines from the menu (#3484)
Comments copy and paste, within and between documents. ⌘C with comments selected (and no text
selected) copies them, each with its replies, as XFDF: into the app's clipboard (every tab and
window) and as text onto the system clipboard. ⌘V, Edit ▸ Paste comments or the page's context
menu pastes them onto the current page at their own positions, as new comments under names of
their own, so nothing is replaced and pasting twice gives two sets; the copies are selected.
XFDF with comments from the system clipboard pastes too, so comments travel between processes.

pdfcraft_xfdf::export_xfdf_comments writes a selection with its replies; import_comments takes
a target page and a name prefix and imports copies (the usual import still replaces same names).
Engine: Edit::PasteComments { xfdf, page } (one undo step, comment permission) and
Session::export_comments. Tools: comments_copy (read-only) and comments_paste.

Several comments select at once: ⌘-click (Ctrl on Windows and Linux) or ⇧-click adds one or
takes it out, on the page and in the Comments panel; the one clicked last has the handles.
Delete removes them all as one step, a drag moves them together, the context menu copies them.

Connected lines, polygons and clouds finish from the right-click menu's Complete (with Undo last
point and Cancel drawing), as other editors do, besides Enter and a double-click.

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-05 16:41:45 +01:00
c3c36f77cf M5: a comment's text, border or line, and fill each at an opacity of its own (#4542)
* A comment's text, border or line, and fill each at an opacity of its own

Comment Properties showed one opacity for a whole comment, so a text box's
see-through background took its text and border with it, and a rectangle
marking an area on a plan couldn't have an opaque line over a faint fill.
Now a text box, typewriter text or callout has a Text, Border and Fill
opacity, a rectangle, oval, polygon or cloud a Line and Fill opacity (a part
not drawn is greyed); everything else keeps one Opacity.

The line's stays /CA, the fill's is /ca (PDF 2.0's opacity for what is
filled) and the text's /PCTextOpacity, each only where it differs from the
one it would follow, and the appearance draws them with /GS0 (strokes at the
line's, fills at the fill's) and /GS1 for the text, so every viewer shows
them. The quick bar's Opacity and StyleAnnotation's set the whole comment's.

Engine: Style::{fill_opacity, text_opacity}, Edit::PartOpacity,
annot::{set_part_opacity, appearance::part_opacity}, Props::{fill_opacity,
text_opacity}. Make Properties Default and the settings carry the parts.
Headless: comment_add / comment_edit fill_opacity, text_opacity; comment_list
reports opacity, fill_opacity, text_opacity. Four labels in every catalog
(AI-assisted translations from English, noted in ATTRIBUTION.toml).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Review: the text's opacity slider shows what the text is drawn at; comment_list skips replies' properties; ui-parity's change record

A text box without fill and border whose text kept an opacity of its own showed the border's
in its Text opacity slider; it now shows the text's, and a change sets the whole comment's.
The opacity sliders are named by their labels. comment_list reads a comment's properties only
for comments, not for every reply.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rebase: comment_list tells replies by is_reply, as main now threads them

main threads replies by their /IRT reference (#4061); the opacity fields skip a reply the
same way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Review: a text-only text box made default gives the tool its text's opacity

With neither a border nor a fill, a text box's text is the whole comment:
Comment Properties shows its drawn opacity (the text's own, when set), and a
change there sets the whole comment's. Make Properties Default, and the
context menu's Make Current Properties Default, stored /CA instead, so a
text box whose text was at 50 % gave the tool 100 %. The default is now the
text's drawn opacity in that case.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rebase: the part opacities in main's annot layout (Style's fields, the text box drawing's parts, set_part_opacity exported)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Rebase: main's new comment test builds a Style with the part opacities

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
Co-authored-by: FredApps <153173854+FredApps@users.noreply.github.com>
2026-11-05 14:39:36 +01:00
FredApps e19f964690 Handle the current fallible FDF export API in the round-trip regression 2026-10-30 09:10:25 +01:00
FredApps b07a012cd7 Reconcile button export values with current form authoring modules
Preserve caption editing and current form/Prepare module boundaries. Carry export-only appearance preservation, validation and data round-trip tests to their current paths, and retain current attribution metadata. Hosted CI must validate this refreshed head.
2026-10-30 08:56:21 +01:00
Dylan M. Taylor f76dbb9e8c deps: bump tar, zip, roxmltree, rustls-webpki and symphonia to their latest versions (#5381)
- `zip`: 9.1.0 → 9.1.3

Requirement `roxmltree` 0.20 → 0.21: `ParsingOptions` gained `entity_resolver` (initializers take `..Default::default()`, i.e. none, as before) and is no longer `Copy` (two functions build it with a closure, the pattern merge.rs already used).
2026-10-29 22:21:27 -04:00
oracola91 40c22e3ea5 Export Data as CSV keeps formula-like cells as text, like the merge report (#2524)
Export Data (CSV) wrote field names and values as they are, so a value
from a received form that starts with = or @ (or + or - when it is not a
number) runs as a formula when the CSV is opened in a spreadsheet.

It now uses the rule merge_csv got in #4101, moved unchanged into
runs_as_formula, so the merge report's output is the same. Import Data
takes the added ' off again, so Export Data then Import Data gives back
every value unchanged.
2026-10-28 17:39:06 -04:00
Dylan M. Taylor 81c63c037a Group annotation, form and document operation parameters 2026-10-27 23:25:39 +00:00
Dylan M. Taylor 92bc2f9acd Refactor xfdf for strict Clippy checks 2026-10-27 23:12:52 +00:00
aiongg f022ef0671 style: cargo fmt on moved files 2026-10-27 00:34:32 +00:00
aiongg 6ab1820bae refactor(xfdf): split lib.rs into common, xfdf, fdf
New modules: common.rs, xfdf.rs, fdf.rs.
2026-10-26 22:18:50 +00:00
7609d21488 fix(xfdf): an empty field in imported XFDF clears the field, as FDF and XML do (#4483)
* fix(xfdf): an empty field in imported XFDF clears the field, as FDF and XML do

* fix(xfdf): a field holding only value-richtext is not cleared on import

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 10:01:38 -04:00
Marco Arnulfo d9270bf16a fix(xfdf): an imported FDF comment's pop-up is placed on the page, not copied in as a direct dictionary (#4493) 2026-10-25 10:00:10 -04:00
NetterSilverandClaude Haiku 5.5 82f0b6f8a0 Reject non-finite numbers in XFDF coordinate lists on import (#4449)
Found while testing crates/xfdf/src/lib.rs:274-276 (csv) used by annot_from_xml at :924-928

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-24 10:30:38 -04:00
b174b12b0e Reject non-hex characters in XFDF colour parsing (#4145)
Found while testing crates/xfdf/src/lib.rs:236-243 (parse_hex)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-23 10:20:14 -04:00
aiongg 8adf8e2d3b fix(xfdf): read an indirect /F when deciding a comment is locked against import 2026-10-22 18:02:33 +00:00
aiongg b1196c5cbe fix(xfdf): bound what an FDF import copies out of repeated references
The FDF field walker and the comment copier followed every reference again
each time it appeared, so a field tree or comment whose kids or properties
repeat one reference level after level expanded a small file into millions
of rows or values before the depth limit stopped it. Both now skip a
reference back to an object they are inside of, and share one budget per
import of values and text; past it the import is refused.
2026-10-22 17:57:53 +00:00
aiongg 93436d41b0 fix(xfdf): escape paired line-ending names in exported XFDF
The head and tail attributes were written from the annotation's /LE names
without XML escaping, so a name holding a quote or angle bracket could add
attributes or elements, including field values, to the exported file.
2026-10-22 17:57:38 +00:00
aiongg 256097023c fix(xfdf): use an imported redaction mark's /Rect only when it is four finite numbers
The /Rect fallback dropped non-numbers before checking the length, so a
malformed /Rect such as [0 0 /Bad 100 100] read as a valid rectangle and
gave the mark quads. The array itself must now hold exactly four finite
numbers.
2026-10-22 13:27:52 -04:00
aiongg 63f7932d06 fix(xfdf): fall back to the /Rect when an imported redaction mark has a zero-area quad
A quad whose corners all lie on one line (or on one point) encloses
nothing, yet such /QuadPoints counted as drawable, replaced the mark's
/Rect and left an imported redaction that covers nothing. Any quad without
area now makes the mark's quads unusable, so its /Rect is used instead.
2026-10-22 13:27:52 -04:00
aiongg 8a8dab6c00 fix(xfdf): keep merged spreadsheet cells from starting a formula
Merge Data Files into Spreadsheet writes field names and values from other
people's files as CSV cells, escaping only the delimiters. A cell starting
with =, +, - or @ is evaluated as a formula when the CSV is opened in a
spreadsheet program. Such cells, after any leading whitespace, are now
written with a leading apostrophe; finite numbers such as -12.5 are left
as they are.
2026-10-22 13:27:52 -04:00
aiongg d266222339 fix(xfdf): draw every imported redaction mark's review outline, opaque
A redaction mark's outline is drawn from its /QuadPoints, but applying the
mark falls back to its /Rect when it has none. An imported mark with only a
/Rect, or with quads the outline can't draw, therefore had no visible
outline while still removing content when applied, and an imported opacity
of 0 hid the outline too. Imported marks now get quads from their /Rect
when their own are unusable (or none, so they remove nothing), and their
/CA and /ca are dropped.
2026-10-22 13:27:52 -04:00
aiongg f0e3880c35 fix(xfdf): never let a same-named imported comment replace a form widget
Comment import replaces an existing annotation with the same /NM in place.
The check for annotations it must keep covered locked comments and
redaction marks but not widgets or field dictionaries, so an imported
comment could overwrite a field's widget object, setting its value and
validation entries without the form value setter while the AcroForm field
list still pointed at it. Widgets and field dictionaries are now kept, and
the imported comment is added beside them under no name.
2026-10-22 13:27:52 -04:00
aiongg a2c46a9298 Merge r2 track t06: annotations-comments
# Conflicts:
#	crates/automation/tests/automation.rs
#	crates/render/src/raster.rs
2026-10-22 02:19:23 +00:00
Unhumanje d335ff375d fix(xfdf): a field name full of periods no longer overflows the stack on export
The XFDF export nested one <field> element per period-separated part of a field's full name. A /T can hold periods of its own, so a name can have far more parts than the field tree has levels. Past 64 levels the import refuses the file the export wrote, and around 100,000 parts the recursive write overflows the main thread's stack and aborts the process.

The export now nests at most as many levels as the import reads back. The parts past the last level stay in the deepest element's name, and the import joins them back into the same full name.
2026-10-21 11:17:56 +02:00
NetterSilverandClaude Haiku 5.5 12c66f7113 Keep zero annotation flags through XFDF export/import
Found while testing crates/xfdf/src/lib.rs:313-317 (xfdf_annots) and :~1010 (annot_from_xml, `unwrap_or("print")`)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-20 19:44:42 +02:00
ec0a965074 M5.6: preserve nested annotation values in FDF exports (#1971)
* M5.6: preserve nested annotation values in FDF exports

Copy and renumber retained object graphs without expanding aliases or following
indirect cycles recursively. Refuse excessive work and propagate export errors
before the destination is written. Cover saved geometry, colour and borders,
shared graphs, streams, stale references and refusal through automation tools.

Co-Authored-By: Codex <noreply@openai.com>

* Bound FDF annotation copying before allocation

Keep selected aliases shared, budget retained keys and values before copying, and add direct-payload and alias-count regressions. Retain copied-graph limits and document source-memory scope.

* M5.6: bound FDF cache-eviction discovery and field values

Extend the concurrent annotation-budget correction while retaining its direct-payload and alias regressions. Record annotation positions instead of resolved bodies so cache eviction cannot pin repeated parsed copies; borrow direct values and budget retained entries before cloning. Count every emitted multi-select field value before allocating its output array.

Observed pre-fix allocation-cap and field-limit failures, then fixed tests passed. Final validation: 549 scoped XFDF/engine/automation tests passed, three existing ignored; strict all-targets Clippy, WASM, fmt, layers, assets, parity and diff checks passed.

AI assistance: OpenAI Codex for @MMexicann.

* M5.6: record bounded FDF export regression evidence

Record comment cache-eviction discovery and emitted-field-value budget regressions without changing feature scores or status. Describe copied-graph limits and existing source-parser limits precisely. Final 549 scoped tests, strict Clippy, WASM, fmt, layers, assets and parity passed.

AI assistance: OpenAI Codex for @MMexicann.

* M5.6: align FDF progress with budgeted discovery

Document lazy annotation positions, cache-eviction coverage and copied-graph limits while retaining the original nested-value progress entry and all upstream notes. Estimates unchanged.

AI assistance: OpenAI Codex for @MMexicann.

* M5.6: describe FDF discovery and copied-graph limits

Align exchange documentation with the tested lazy-position discovery implementation and its copied-graph limits. Source parsing/page discovery keep existing limits.

AI assistance: OpenAI Codex for @MMexicann.

* M5.6: align milestone notes with FDF discovery limits

Retain upstream milestone history and describe the tested discovery/copy budgets without increasing estimates or claiming a total source-memory bound.

AI assistance: OpenAI Codex for @MMexicann.

* M5.6: keep nested page links out of FDF exports

Preserve graph aliases and existing budgets; exclude direct and indirect Page/Pages type names. Add saved-PDF regression and bounded type-resolution controls. Both pre-fix failures observed; 46 scoped tests, strict Clippy, WASM and formatting passed.

* M5.6: document bounded nested page exclusion

Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.

* M5.6: record nested page-reference regression evidence

Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.

* M5.6: retain FDF limits in milestone evidence

Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.

* M5.6: cite nested page-reference exclusion tests

Address maintainer feedback on the existing PR. Preserve upstream work and document the tested scope and remaining validation limits.

* M5.6: respect generations while identifying page references

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* XFDF: document stale Type preservation regression

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M5.6: record generation-aware page exclusion evidence

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M5.6: propagate FDF export errors in usage example

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

* M5.6: consolidate roadmap change and target fields

Address maintainer feedback on the existing PR. Preserve upstream work and document tested scope and validation limits.

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: skylar taylor-barrick <hi@skylar.cc>
2026-10-19 12:21:37 -06:00
NetterSilverandClaude Haiku 5.5 666648349b Drop U+FFFE and U+FFFF from XFDF/XML form-data export (#3330)
Found while testing crates/xfdf/src/lib.rs:192-209 (esc), used by export_xfdf (:445) and export_data XML (:594-612)

Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
2026-10-18 17:06:07 -04:00
aiongg 7a52541347 Merge track r1-forms (fredapps-r1)
ROADMAP.md, docs/roadmap.md: keep both sides' progress-log lines and revision rows, once each
2026-10-16 14:12:24 +00:00
aiongg bf240b612c Integration: #2688 drop the formula-cell and TSV-export sentences from the xfdf README and form.data-xml-csv-txt notes 2026-10-16 14:04:02 +00:00
aiongg 24b5060c1f Merge PR #2688: M6: distinguish CSV header tabs from TSV delimiters
ROADMAP.md: next's file; the PR's progress line and revision row added once; status-line edit dropped.
docs/roadmap.md: next's file; the PR's revision row and M6 milestone sentence added once; status-line edit dropped.
crates/xfdf/README.md: all three paragraphs kept (#1917, #2686, this PR).
crates/xfdf/src/tests.rs: #2686's test and this PR's two tests all kept.
parity/acrobat-features.toml: form.data-xml-csv-txt keeps every evidence entry and note.
2026-10-16 14:03:59 +00:00
aiongg 834495382d Merge PR #2686: M6: preserve complete plain XML form values
ROADMAP.md: next's file; the PR's progress line and revision row added once; status-line edit dropped.
docs/roadmap.md: next's file; the PR's revision row and M6 milestone sentence added once; status-line edit dropped.
crates/xfdf/README.md: both paragraphs kept (#1917 export whitespace, this PR's plain XML import text).
parity/acrobat-features.toml: form.data-xml-csv-txt keeps both evidence entries and both notes.
2026-10-16 14:03:31 +00:00
aiongg 5406355729 Integration: #2681 make the self-reply assertion able to fail 2026-10-16 14:02:13 +00:00
Mex c30fce5d3e M6: distinguish CSV header tabs from TSV delimiters 2026-10-15 23:13:27 +02:00
Mex 14c3d951e7 M6: preserve complete plain XML form values 2026-10-15 23:04:14 +02:00
Muhammad Saad c9956bf77f Replace Text: give the caret its own /NM (#2666)
add_text_replacement built the StrikeOut and the Caret from one Meta, and
add_annotation stamps /NM from meta.id, so the pair shared a single name. XFDF
names a reply by the /NM of what it replies to, so the exporter wrote the
caret's inreplyto as the caret's own name. Importing that file found a comment
replying to itself, and the Replace Text comment did not arrive: the reporter's
second document listed none. FDF was unaffected because it keeps the pair by
object structure rather than by name.

Take a second Meta for the caret. The ids stay supplied by the caller, as the
rest of the crate does so edits remain deterministic, and the one production
caller already has a generator and calls it twice. /IRT still points at the
strikeout, so the group still moves, lists and deletes as one.

Tests: the annotation test now asserts the two carry different names and that
the caret's /IRT resolves to the strikeout's. A new XFDF test exports a Replace
Text pair and imports it into another document, asserting both comments arrive
with their thread intact; it fails if the two are given one id again.
2026-10-16 00:34:21 +04:00
Mex f1177bb287 M6: refresh XML whitespace fix and record parity evidence 2026-10-15 22:01:42 +02:00
Codex 403323f425 Merge main and address button export-value review follow-up 2026-10-15 16:22:36 +02:00
e62d3db31b M6: keep AcroForm XML field tags within the NCName grammar (#1588)
Constrain the existing normalization to XML1.0 name characters while preserving
valid tags and original PDF names through xfdf:original. Verify Unicode names,
prefixes and normalization collisions with saved-PDF round trips.

Co-authored-by: MMexicann <MMexicann@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:03:00 -04:00
53b9bc1059 M6: preserve carriage returns in form CSV exports (#1563)
* M6: preserve carriage returns in exported form CSV

Quote CR in names and values so reimport cannot discard a trailing CR as a
record terminator. Verify eleven combinations through saved-PDF round trips.

Co-Authored-By: Codex <noreply@openai.com>

* Keep main's ROADMAP status line

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: MMexicann <MMexicann@users.noreply.github.com>
Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 04:02:35 -04:00
57c8de09ab M6: preserve XFDF field text around XML comments (#1647)
Join the text nodes in each field value so XML comments and processing instructions do not truncate imported text. Cover data extraction and form import through PDF save/reopen.

Co-authored-by: storybored379 <storybored379@users.noreply.github.com>
Co-authored-by: OpenAI Codex <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:47:41 -04:00
FredApps fc14719dff feat(forms): edit checkbox and radio export values (#231) 2026-10-13 19:18:41 +02:00
MMexicannandCodex b85d519993 M6: preserve whitespace in XML and XFDF attributes
Encode tabs and line feeds as character references so XML normalization cannot change field names, comment identities or metadata. Add failing-before-fix saved-PDF round-trip regressions.

Co-Authored-By: Codex <noreply@openai.com>
2026-10-13 14:16:44 +00:00