Commit Graph
6448 Commits
Author SHA1 Message Date
FredApps 346d803080 Merge pull request #7203 from christianlappin/fix/7050-macos-save-xattrs
Fix macOS saves for PDFs with extended attributes
2026-11-14 17:13:09 +01:00
358e33a307 M7: replacing a line keeps the source font for the words it can show (#2378, re-lands #2955) (#6842)
* M7: replacing a line keeps the source font for the words it can show (#2378) (#2955)

* Fit #2955's line edit to #4514's /ActualText spaces

Since #4514, source_show wraps a run whose spaces the subset lacks in a
/Span /ActualText BDC ... EMC, so the moves standing in for those spaces
read back. #2955's two-font /PCEdLine path writes its source runs through
source_show, so they now carry that span too. Three of its tests were
written against the operator stream from before that:

- replacing_a_mixed_font_line_again_replaces_its_sequence counted BMC and
  EMC as the /PCEdLine sequences alone. It now also counts each edit's
  own /ActualText spans (BDC, and EMC = sequences + spans), so a sequence
  that nests or survives a re-edit still fails it.
- a_leading_space_does_not_make_a_source_font_run looked for the leading
  move right after the Tf; it now sits inside the run's span.
- a_row_replaced_inside_a_shared_sequence_starts_in_its_own_font put its
  second row before the first EMC, which is now the span's: the row was
  read as part of the span's text. It now goes before the EMC that closes
  /PCEdLine, the case the test describes. A paragraph rewrite drops an
  /ActualText span with its line (the span's BDC and EMC are among the
  line's operators), so it never leaves a row inside one.

The code needs no change: re-editing drops the spans inside a /PCEdLine
sequence with it (BDC/EMC are in the dropped set), and a span's merged
run keeps the sequence it is in, so the line still reads back as one.
Also drops the same_font import lines.rs no longer uses.

* Tests: fit #2955's three line-edit tests to #4514's /ActualText spans

* Tests: the replaced sequence's check allows the new text's own /ActualText span

---------

Co-authored-by: mtlcl410 <2368091+mtlcl410@users.noreply.github.com>
Co-authored-by: FredApps <FredApps@users.noreply.github.com>
2026-11-14 13:25:27 +01:00
FredApps dd6c625274 Merge pull request #4417 from FredApps/fix/sonar-fonts-quality-gate
fix(ci): use pinned fonts for Sonar coverage
2026-11-14 12:16:14 +01:00
Dylan M. Taylor e98dc1712c Merge pull request #7261 from storytold/craftlibs-deep-cutover
Move remaining file formats and codecs to craft-libs (#778)
2026-11-13 23:29:36 -05:00
Dylan M. Taylor b7ffe8732f xtask, export: update attribution, parity evidence, and RTF test for craft-libs cutover 2026-11-14 04:29:32 +00:00
Dylan M. Taylor bd2120909a cos: retain pdfcraft-crypt and pdfcraft-filters in dev-dependencies 2026-11-14 04:10:43 +00:00
Dylan M. Taylor 937c3fc7e1 print: initialize driver_settings on craft-print Job 2026-11-14 04:10:10 +00:00
Dylan M. Taylor ed18238d74 crypt, filters, cos, export, xfdf: migrate to craft-pdf, craft-rtf, craft-csv 2026-11-14 04:02:21 +00:00
Dylan M. Taylor 524d9f6b64 prc: remove crates/prc and cut over to craft-prc (#778) 2026-11-14 03:44:47 +00:00
Dylan M. Taylor 9475e50cf1 Merge pull request #7260 from storytold/feat/pdfcraft-craftlibs
export: migrate zip writer to craft-zip (#778)
2026-11-13 22:12:33 -05:00
Dylan M. Taylor 93a5e1545a export: migrate zip writer to craft-zip (#778) 2026-11-14 00:06:39 +00:00
FredApps e2c90c33cb sonarcloud: use the craft-fonts commit the gate and the release use 2026-11-13 20:53:28 +01:00
FredApps 616c71492d Merge branch 'main' into fix/sonar-fonts-quality-gate 2026-11-13 20:43:14 +01:00
FredApps 0f22627bff Merge pull request #7144 from FredApps/port-2081
Link JavaScript actions and app.openDoc (port of #2081)
2026-11-13 19:47:48 +01:00
FredApps 0aed40d670 Merge branch 'main' into port-2081 2026-11-13 19:45:32 +01:00
FredApps c83c9ddb90 Merge pull request #7202 from Ethunxxx/fix/recent-reveal-test-race
test(ui): run the Home recent Reveal test inline so its toast check can't race
2026-11-13 19:45:11 +01:00
FredApps 2a639868dd Merge branch 'main' into port-2081 2026-11-13 18:59:56 +01:00
FredApps 1771844b84 fix(link-js): address the review on the #2081 port
- A link that fails puts the realm's timers back as they were before its
  own script ran, and turns no layer: timers it set are dropped, timers it
  cleared come back (timers::save/restore in Realm::run_job).
- In a read-only document a link's requests still apply when its field
  changes can't; the outcome carries the read-only error.
- app.openDoc during a calculation (calculateNow) is noted on the console
  and not queued, as for a field script running on its own.
- Link script streams are decoded once per stream, whatever their source
  length, and /Filter [] reads as the raw source.
- The web build sets the view's zoom, page and highlight before a link
  script runs, as the desktop does.
2026-11-13 18:48:33 +01:00
FredApps 8034990072 Merge pull request #7141 from FredApps/fix-openssl-ia32cap
fix(startup): an OPENSSL_ia32cap naming a missing CPU feature no longer stops PdfCraft (#2916)
2026-11-13 17:31:17 +01:00
FredApps ec31c55763 fix(ocr): main builds on Windows again: the executable check is its own function per platform (#7222)
Since Rust 1.100, clippy's needless_bool refused program_is_executable on Windows: with the
#[cfg(unix)] block gone it read if ... { return false; } true, and the Windows gate failed on
every main commit since 13 Nov 09:38. The check is now one expression with the platform part
in has_execute_permission; behaviour is unchanged on every platform.
2026-11-13 16:28:29 +01:00
FredApps e6730be289 test: scope CPU override regressions to supported platforms 2026-11-13 14:08:57 +01:00
FredApps fd4d60ff4a CI: use the shared git-sources check (#7042)
ci.yml ran its own copy of the git-sources job; it now calls
craft-common-actions git-sources.yml, under the same full-ci label rule.
2026-11-13 14:04:39 +01:00
Dylan M. Taylor 785e7e510c fix(forms): finding the first character a simple font cannot hold encodes the whole string once, then each distinct character once (#7047) 2026-11-13 12:23:58 +01:00
Dylan M. Taylor b167422b2e fix(sign): every signature's VRI entry shares the store's evidence arrays instead of copying them (#7038) 2026-11-13 12:22:54 +01:00
Dylan M. Taylor b0607f5cd3 fix(optimize): a destination name given by reference is copied once however many dictionaries name it (#7035)
* fix(optimize): a destination name given by reference is copied once however many dictionaries name it

* fix(optimize): aliases of one destination-name object are copied once
2026-11-13 12:21:26 +01:00
Christian Lappin 11a7f02cc0 Fix Finder association attribute sizing on macOS 2026-11-13 05:58:15 -05:00
Christian Lappin d6579c2bef Fix macOS extended attribute sizing during save 2026-11-13 05:58:15 -05:00
Richard Buschbeck 7f754fc9fd test(ui): run the Home recent Reveal test inline so its toast check can't race
home_recent_context_menu_reveals_the_target_without_opening_or_removing_it
never set run_inline, so reveal_path checked the missing file on a
pdfcraft-reveal worker thread while the test waited a fixed three frames
before asserting the "The file no longer exists" toast. On a loaded runner
the worker can report after those frames and the assertion fails. Set
run_inline, as the reveal unit test in tab_context.rs already does.
2026-11-13 11:40:55 +01:00
FredApps 0c15e3de71 Merge pull request #7115 from jonathanwxh-cell/fix/measure-compound-number-formats
fix(measure): read compound and fractional measurement number formats (ISO 32000-2 12.9.2)
2026-11-13 10:38:39 +01:00
FredApps 623c53f887 Merge pull request #7073 from mtlcl410/fix/test-moddate-second-boundary
fix(tests): saves compared byte for byte don't fail when the clock crosses a second between them
2026-11-13 10:37:57 +01:00
FredApps eb2a2eddac Merge pull request #7056 from mtlcl410/perf/form-edit-reads-fields-once
M7: a form edit reads the document's fields once (form.fill-text)
2026-11-13 10:37:09 +01:00
FredApps a080e1ff27 Merge pull request #7053 from mtlcl410/fix/lone-sign-token
fix(hayro-syntax): a lone sign in a dictionary or array is unreadable, not a panic
2026-11-13 10:32:49 +01:00
FredApps 6d2c006f02 Merge pull request #7051 from mtlcl410/fix/js-session-test-worker-cap
fix(js): each unit-test thread counts its own document script workers
2026-11-13 10:29:31 +01:00
asadosteaksnlandasadosteaksnl 175992b5a2 fix(ui): Recognize Text's settings scroll in a short window, its buttons stay in reach (#6599) (#6760)
* fix(ui): Recognize Text's settings scroll in a short window, its buttons stay in reach (#6599)

On a small screen or at a large display scale the dialog was taller than the window: it was
centred with its title and its Cancel / Recognize text row off the screen, and nothing scrolled.

The four settings groups (Pages, Settings, Skip, Output folder) now sit in a vertical scroll area
capped to the window's height, as Preferences does (#3557). The title, the engine notice and the
button row stay outside it, so they are always on screen; when the settings fit, nothing changes.

The test opens the dialog in 400 to 700 pt windows and checks the title and both buttons are on
screen, and that the last group scrolls in between the title and the buttons while they stay put.
Without the fix it fails at 400 pt with the title at y = -267.

* contributors: credit asadosteaksnl as Kas

* fix(ui): Recognize Text's settings scroll in as little as 40 pt, so its buttons fit the smallest window (#6599)

A 120 pt floor still pushed the dialog off a window shorter than about 340 pt: at 173 pt (the
smallest window, 520 pt, at the largest interface size, 300%) the title sat at y = -32. The test
now checks 173, 208 and 260 pt windows too, as the Preferences layout test does.

* test(ui): the short-window Recognize Text test clicks Cancel and checks a 640 pt wide window (#6599)

Cancel being on screen isn't proof it can be clicked: the test now clicks it at every height and checks the dialog closes. The window is 640 pt across, a 1280-pixel screen at 200%, and every control is checked to fit across as well as down.

* test(ui): the Recognize Text title stays put while the settings scroll (#6599)

* Revert "contributors: credit asadosteaksnl as Kas"

This reverts commit 52470f66a7.

* docs(ui): document the Recognize Text dialog's body (#6599)

* test(ui): the Recognize Text test also covers tall windows where nothing scrolls (#6599)

The dialog is about 935 pt tall, so it scrolls up to a 900 pt window; at 1100 pt everything fits. Both now run, so the test also pins the case where the settings fit and the layout is unchanged.

---------

Co-authored-by: asadosteaksnl <353856209+asadosteaksnl@users.noreply.github.com>
2026-11-13 02:42:37 +01:00
FredApps 330cde8035 Merge pull request #5559 from vangel76/feat/recent-reveal-5452
Reveal recent files in the system file manager from Home (#5452)
2026-11-13 02:19:00 +01:00
mtlcl410andClaude Opus 5.5 85d4257523 Merge upstream/main into fix/js-session-test-worker-cap
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyGTPYerQyLLrnydVDA
2026-11-13 04:35:23 +08:00
mtlcl410andClaude Opus 5.5 cd1d7160b0 Merge upstream/main into perf/form-edit-reads-fields-once
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Pq7HyGTPYerQyLLrnydVDA
2026-11-13 04:24:08 +08:00
FredApps ad153f5ded test(ui): the link test's openDoc path is absolute on Windows too 2026-11-12 21:22:55 +01:00
FredApps feec1853c0 Merge main into port-2081
Main now has page actions, timers and layers (#6985) and shared text
allowances for inspection (#6015). Conflicts:
- render/inspect/annotations.rs: main's collect_link (which notes
  JavaScript even when the link isn't listed) takes this branch's link
  script budget and its once-only warning; push_link is gone.
- automation form_tools.rs, js tests.rs, docs/acroform-script-workflows.md:
  both sides added at the same place; both kept.
Adapted to main: the link runner's Job gets `timer: None`, and, as a
button's script does, the document's layers and the fields as page
actions and timers show them (live_state).
2026-11-12 20:53:37 +01:00
FredApps be9fe433cc Merge pull request #6985 from FredApps/port-4751
feat: LaTeX animate playback — page actions, timers, getOCGs, view-only overrides (port of #4751)
2026-11-12 20:30:31 +01:00
FredApps 5a53828c70 fix(startup): detect aws-lc's CPU features at start, as before 2026-11-12 19:39:12 +01:00
FredApps d0ab739f30 style: wrap the dropped-OPENSSL_ia32cap log line for rustfmt 2026-11-12 19:35:17 +01:00
FredApps bffa2d58c0 fix(scripts): a batch the redaction checks refuse discards its script globals
After the edit ran, a batch can still fail the redaction checks: a
deleted marked page alongside added pages, or text still shown under a
mark. Both returned without discard_edit_callbacks, so globals (and now
timers) the batch's field scripts left stayed in the document's realm
while the document rolled back. Every other refusal after the edit
already discards them.

Test: a_batch_a_redaction_check_refuses_discards_callback_globals. A
keystroke script sets a global, and a batch that sets the field and
deletes the marked page while adding one is refused. Without the fix the
global is still there ("number" for "undefined").
2026-11-12 19:27:38 +01:00
FredApps f52c6d8555 fix(startup): an OPENSSL_ia32cap naming a missing CPU feature no longer stops PdfCraft (#2916) 2026-11-12 18:53:52 +01:00
FredApps 522fa442f5 Merge main into port-4751
vendor/README.md conflicted: main took hayro-interpret patch 104 (RGB
colours in isolated DeviceCMYK groups). This branch's viewer overrides
become patches 105 (annotation_overrides) and 106 (appearance_overrides)
in the README, in vendor/hayro-interpret/src/interpret/mod.rs, in the
raster test and in docs/acroform-script-workflows.md.
2026-11-12 18:15:19 +01:00
120c62fb82 Auto-tag Apply tags headings by size and weight (#7062) (#7069)
* feat(a11y): auto-tag Apply tags headings by size and weight

Apply now chooses H1-H6 or P per text object instead of P for all.
The body style is the half-point size showing the most characters (bold
when most of those are bold). A short object (at most 3 lines, 200
characters, with a letter) is a heading when it is 1.15x the body, or
bold at 0.9x the body over a regular body in at most 2 lines. Heading
styles rank across the document, larger and bolder first, capped at H6,
and a level never skips past the one before it so heading-nesting
passes.

Size is Tf x Tm x CTM with q/Q tracked; bold is Metrics.bold. Text in
render mode 3 (an OCR layer) is not counted. Font metrics are measured
once per font object per document, at most 256 fonts.
AutoTagResult gains a headings count. Parity, gaps, roadmap and the
apply tool's note say headings are tagged.

Fixes #7062.

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

* fix(a11y): rank heading styles by map and skip clip-only text

Look up each heading style's rank in a map built once after sorting,
so ranking is linear in the number of text objects. Text in render
mode 7 (clip only) paints nothing, so it is excluded from heading
evidence like mode 3.

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

---------

Co-authored-by: KenM76 <KenM76>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 17:58:31 +01:00
490287fc9d prc: rebuild compressed tessellations whose normals are recalculated (#1297) (#7034)
* prc: rebuild compressed tessellations whose normals are recalculated

A TESS_3D_Compressed (WD 7.8.9.7) was read to its end but never rebuilt,
so prc-render drew nothing for it. Rebuild the form whose normals are
recalculated, with three edge statuses per triangle, into a Mesh grouped
by face and styled by each face's line attribute.

The walk (tess/compressed.rs) takes a seed, then one apex per triangle,
from a reference or the next point in the frame of the edge it continues
across (WD 7.8.9.2), with the WD 12.3 Length, Unitize and MakeOrthoRep
arithmetic bit for bit. Arrays that do not fit, or an edge shared by more
than two triangles, leave the tessellation Compressed. Every triangle,
style and face range is charged to the element allowance first.

Stored-normals meshes, the one-status-per-triangle form, the planar bend
check, the best-fit search and partial salvage are later PRs.

Adapted from pdfcer (MIT, same author) at 0a249a73.

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

* prc: charge rebuilt compressed meshes after they fit; model_render test

The rebuilt triangles, their styles and the face ranges are now charged
to the element allowance once the arrays fit and before the face ranges
are made. Arrays the walk cannot fit stay Compressed and spend nothing,
so they no longer fail the file over a face count they never use.

Tests:
- a_rebuilt_compressed_mesh_is_charged_its_triangles_and_faces pins the
  exact charge (4 triangles x 3 elements + 2 faces);
- arrays_that_do_not_fit_spend_no_triangles_or_faces;
- rebuilt_triangles_are_grouped_by_face_with_their_styles, a direct
  by_face test with out-of-order faces, empty faces and styles;
- model_render's a_compressed_prc_model_is_rebuilt_and_drawn, end to end
  from a PDF, cited in misc.3d-view; its hex fixture is the prc-render
  builder's output, kept so by the_automation_fixture_is_the_compressed_triangle.

The walk's working tables are documented as bounded by the triangle
count rather than charged. The module docs now say the arithmetic
matches the WD pseudocode as read and that the traversal rules are
inferred, not WD text.

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

* prc: charge compressed styles and face ranges before making them

A rebuilt compressed mesh's per-triangle styles were built before the
budget was charged, and also when the normals were stored and the mesh
was read past. The face attributes are now kept as read, and the styles
are built only for a rebuilt mesh, after the charge.

Each face range is a Range<usize>, two budget elements on 64-bit
targets, so it is charged at its size, not as one element.

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

* prc: bound the compressed rebuild walk by the allowance left

The walk's vertices, triangles, edge counts, edge log and stack were
allocated before anything was charged, and could hold several times the
decoded arrays. The walk now gets the elements the reader has left and
stops once its arrays, by length, would hold more; the tessellation then
stays compressed, as when its arrays do not fit the walk.

A face whose line attribute is 0 but whose behaviour is not now styles
its triangles, so the behaviour bits are kept.

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

* prc: say the rebuild walk is bounded by the allowance

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

* prc: cap the rebuild walk's first reservation by its limit

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

---------

Co-authored-by: KenM76 <KenM76>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 17:58:14 +01:00
72c607fc47 fix(render): an RGB colour in an isolated DeviceCMYK group blends in CMYK, as its ink (#7031)
* fix(render): an RGB colour in an isolated DeviceCMYK group blends in CMYK, as its ink

Part of #4887. An isolated DeviceCMYK group blended in CMYK only when every
colour in it had process tints (DeviceCMYK, DeviceGray); one RGB fill sent
the whole group back to RGB blending.

Vendored hayro-interpret patch (104): Color::ink_tints gives DeviceRGB,
CalRGB, Lab and three-component ICCBased colours the ink that draws back to
them through the bundled CMYK profile (new cmyk_inverse module: black
0.4*k0^2 + 0.6*k0^8 with k0 = 1 - max(r, g, b), matched to Acrobat on
synthetic pages; then cyan, magenta and yellow by at most 12 Newton steps
against the profile; one-entry per-thread cache). ICCBased CMYK still has no
tints.

Test an_rgb_colour_in_an_isolated_cmyk_group_blends_as_its_ink: 50% grey
under Difference with black within 10 levels of Acrobat's 137 112 106;
in-gamut colours draw as themselves; red within 8 of Acrobat's 238 32 37.
With the additive arms reverted the grey draws 93 97 96 and it fails.
#5228's control now uses an RGB image, which still has no tints.

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

* fix(render): an RGB colour with a non-finite component has no CMYK ink

`to_rgba` turns a non-finite component into some finite colour, so the
inverse could not see it and gave that colour's ink. `ink_from_srgb` now
declines such a colour and the group draws it as before.

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

---------

Co-authored-by: KenM76 <KenM76>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-12 17:57:26 +01:00
jonathanwxh-cell 4439794769 fix(measure): validate written Y factor and check /F and /D on last format only 2026-11-12 22:05:28 +08:00
jonathanwxh-cell c2355b0b0e fix(measure): nudge whole units by a step of the last unit; keep Y's own units and CYX
A whole-unit nudge measured in the larger unit could exceed a step of the last unit (1 km - 0.9 mm showed as 1 km 0 m). A compound Y in units other than X's was relabelled with X's unit and lost its CYX when written back.
2026-11-12 21:36:03 +08:00