Commit Graph
4844 Commits
Author SHA1 Message Date
jonathanwxh-cell f9d37c089f fix(render): use unfiltered inline image byte length before EI heuristic (#3107) 2026-10-19 17:33:48 +08:00
mtlcl410andClaude Opus 5.5 bae6981959 fix(render): the device decides whether a knockout group's image clears its rectangle (#2971)
Review on #2974: the interpreter decided with a full-resolution decode
(`decoded_raster(None)`) before the renderer decoded at its draw size, a
second decode of every downscaled image under another cache key; and an
image a preview skips for its size still cleared what was under it.
`Device::knockout_image` now lets the renderer decide, with the same
eligibility and decode size as `draw_image` (shared `image_draw_size`), so
the draw reuses that decode and a skipped image clears nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 16:34:34 +08:00
mtlcl410andClaude Opus 5.5 3fff309dd3 M3: a link followed in full screen cancels the click's pending page turn (#1459)
Review on #2070: a click on the page schedules a turn after the
double-click time, and a link clicked before then jumped and then the page
still moved on. Following a link now drops the pending turn.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 16:21:20 +08:00
mtlcl410andClaude Opus 5.5 a6b2ad7fb5 fix(render): resolved JP2 palette colours keep 8 bits whatever the index precision (#3179)
Review on #3184: with no /BitsPerComponent the decoded image took the
codestream's precision, which for a palette image is that of the indices.
The resolved colours are decoded to 8 bits, so a 1-bit index rescaled them to
0 or 255 per channel ((64, 128, 192) became (0, 255, 255)). When the palette
is applied the samples are now reported as 8-bit; an image without a palette,
or one whose raw indices are kept for an /Indexed space, keeps its precision.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 16:10:17 +08:00
mtlcl410andClaude Opus 5.5 3df8a6386d fix(render): a knockout clear follows a shading's /BBox and skips images that don't decode (#2971)
Review on #2974. In the erase pass `set_paint` returned no clip, so a
shading fill cleared its whole path while the redraw is clipped to the
shading's /BBox (ISO 32000-2 Table 77): red outside the box stayed erased.
It now returns the shading's clip there too. And an unmasked image cleared
its placement before decoding, so an image that doesn't decode (over
MAX_IMAGE_PIXELS, damaged data) erased the group's earlier artwork and drew
nothing; the clear now happens only when the image decodes, asked only in a
knockout group (Device::in_knockout_group). The stencil case in the test now
also checks that the stencil draws.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 16:03:57 +08:00
LabDennis 62cde99aef M5: reveal sidebar comments at the current zoom (#3418) 2026-10-19 10:02:56 +02:00
mtlcl410andClaude Opus 5.5 14e17ece3b M3: in full screen a double-click selects a word, and full screen selects the Select tool (#1459)
Review on #2070 (CodeRabbit):
- A click turned the page on its release, so a double-click's second click,
  meant to select a word as the PR promises, landed on the next page. The
  turn now waits out egui's double-click time, and is dropped when a
  selection appears or full screen is left; a double-click on blank page
  area still turns once.
- Entering full screen from another tool left it on, and clicks only turn
  pages with Select while the quick tools are hidden. Full screen now selects
  Select and gives the earlier tool back on leaving, as Space's temporary
  Hand tool does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 15:56:30 +08:00
mtlcl410andClaude Opus 5.5 771129594c test(render): the non-separable blend modes keep their colour over an empty page too (#2970)
Hue, Saturation, Color and Luminosity blended with the white paper the
same way; the fix covers them, and the test now checks them over an
empty part of the page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:39:51 +08:00
mtlcl410andClaude Opus 5.5 8836088551 fix(render): blend modes over an empty part of the page keep their colour (#2970)
Since #1557 the page background was painted inside the page
transparency group, as its initial backdrop, so that a Multiply
highlight under reading colours blends with the dark background. With
document colours that made every object blend with the white paper:
a green /BM /Screen fill over an empty part of the page came out
white, and Difference or Exclusion magenta. Only Normal, Multiply,
Darken and HardLight, for which blending with white gives back the
source colour, looked right. 0.8.0 was correct.

The page's objects composite with an initially transparent backdrop
and the page group is then put on the paper (ISO 32000-2, page group).
Vendored hayro patch (18) now paints the background inside the group
only under reading colours, where #1548 needs it, and outside it
otherwise, as before #1557.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:39:50 +08:00
mtlcl410andClaude Opus 5.5 82023e2ffe fix(render): the one-cell tiling renderer starts outside any knockout group (#2971)
After rebasing onto main: #3356's one-cell pattern renderer (merged) builds
a Renderer without the knockout fields this PR adds. Like the tiled cell's
renderer, a pattern cell is painted as its own artwork, so it starts with
no knockout group open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 15:38:36 +08:00
mtlcl410andClaude Opus 5.5 2a93b3152c test: the knockout fixture's nested form declares its real /Length (#2971)
Review follow-up on #2974: the nested group's checks no longer depend on the
parser repairing a short /Length.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 15:37:30 +08:00
mtlcl410andClaude Opus 5.5 2627384757 fix(render): images and nested groups knock out in a knockout group too (#2971)
An image or a nested group is drawn into a layer of its own, which
covers the whole canvas (transparent where nothing was drawn), so it
can't be composited with Compose::Copy. What is under its shape is
now cleared first and the layer then composites over it:

- an unmasked image's shape is its placement rectangle: the
  interpreter hands it to the device (`Device::knockout_shape`), which
  clears it with a transparent Copy fill;
- a nested group's shape is the union of its elements' shapes: the
  interpreter draws its content once in the device's erase mode
  (`knockout_erase_wanted`, `begin_knockout_erase`,
  `end_knockout_erase`), where every paint clears under its shape and
  nothing is layered or drawn as an image, and then draws the group,
  always in a layer of its own (drawn straight onto the knockout
  group, its own elements knocked each other out).

A masked image's shape is its mask; it composites as before, which
matches MuPDF where the mask is opaque or transparent.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:37:30 +08:00
mtlcl410andClaude Opus 5.5 d2bcda45fd fix(render): knockout transparency groups knock out (#2971)
In a knockout group (/K true) each element composites with the group's
initial backdrop, not with the elements drawn before it (ISO 32000-2,
knockout groups). The renderer read /K (hayro-interpret patch 28) but
drew such a group like any other, so overlapping semi-transparent
shapes in it blended with each other.

hayro-interpret patch (39) tells the device a group is a knockout
group (`Device::set_knockout`, default no-op). hayro patch (19) then
draws that group's fills, strokes, glyph outlines and shadings with
Compose::Copy, which vello_cpu weights by coverage, so each replaces
what the group drew under its shape. Images and nested groups are
drawn into a group layer of their own and still composite normally:
copying a whole layer would erase everything outside it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:36:46 +08:00
mtlcl410andClaude Opus 5.5 312a97d21c fix(render): restore the test's closing brace lost when rebasing onto main (#3179)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 15:33:25 +08:00
mtlcl410andClaude Opus 5.5 857fef3b1a fix(render): say that an unresolvable /ColorSpace also gets the JP2 palette (#3179)
Review follow-up: num_components is unset both when the dictionary has no
/ColorSpace and when it has one that does not resolve. In the second case
the JP2 header's colours are the only ones available, so applying the
palette is intended; the comment and vendor/README.md now say so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:32:53 +08:00
mtlcl410andClaude Opus 5.5 e1aeb00be9 fix(render): apply the JP2 palette of a JPX image with no /ColorSpace (#3179)
hayro-syntax decoded every JPX image with resolve_palette_indices off. That
is right when the image dictionary gives a /ColorSpace (an /Indexed space
needs the raw indices), but with no /ColorSpace the colours come from the
JP2 header (ISO 32000-2 §7.4.9) and nothing applied its palette: the
indices were drawn as a gray image. The palette is now resolved exactly
when the dictionary has no /ColorSpace.

Two unit tests decode a 4x2 palette JP2 written for the test: without a
colour space it is red/blue RGB, with /Indexed the raw indices stay.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:32:47 +08:00
jonathanwxh-cell b4545befe8 Merge upstream/main 2026-10-19 15:21:16 +08:00
jonathanwxh-cell 493b92bdea Merge upstream/main 2026-10-19 15:21:11 +08:00
jonathanwxh-cell 52dd6b1e40 Merge upstream/main 2026-10-19 15:21:06 +08:00
jonathanwxh-cell 0725deed33 Merge upstream/main 2026-10-19 15:21:00 +08:00
mtlcl410andClaude Opus 5.5 42e63703d9 M12: full screen in two-page view fits the spread it shows (#379)
Review on #2070: fit_zoom fitted the document's largest page in every
two-page display, so a smaller spread stayed small in full screen. While
presenting, one spread at a time, it now fits the spread shown, the cover
page on its own included; in the window, and while scrolling, the zoom stays
one for the document. The spread arithmetic is one helper, shared with
step_page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 15:02:23 +08:00
mtlcl410andClaude Opus 5.5 3ed0dff807 M12: full screen survives a reload and starts after the document's own initial view (#379)
Review follow-ups on #2070.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 15:02:22 +08:00
mtlcl410andClaude Fable 5.1 1e2e7cc79f M3: full screen shows one fitted page at a time, as Acrobat's Full Screen Mode (#1459)
Full screen is the page on black and nothing else: one page (or one spread,
when two-page view was on, #1353) fitted to the screen, from the current
page; a click, Space, Enter, the arrows and Page Up/Down turn pages, a
shift-click and Backspace go back; Esc brings the display from before
back at the page reached. The quick tools are not drawn in full screen.

Transitions, auto-advance, loop and the cursor hiding stay planned.

Refs #379.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RUNQSPVXx3dDBabRZHAnjz
2026-10-19 15:02:20 +08:00
Chaturanga ManchanayakeandClaude Opus 5.5 5397a4af8b Document the new-file OS open test
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 12:27:59 +05:30
43550c448d M2: a JP2 image in a colour space the decoder refuses is drawn by its component count (#3306) (#3363)
* M2: a JP2 image in a colour space the decoder refuses is drawn by its component count (#3306)

The veraPDF fixture's JPX header names CIEJab (enumerated colour space 19),
which hayro-jpeg2000 refuses, so the image failed and the page drew blank.
When the decoder refuses the image and its colr boxes name such a space, it is
decoded again from a copy naming greyscale, sRGB or CMYK by component count,
as MuPDF and Poppler draw it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

* M2: copy the JP2 stream only when a colour enum needs replacing (#3306)

Review follow-up on #3363: a stream the decoder refused for another reason was
copied for nothing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

* Renumber the JP2 colour-space patch (21): #3378 takes hayro-syntax (20)

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>
2026-10-19 02:50:58 -04:00
cbbeb61650 fix(parse): accept spaces between stream and its line break (#3378)
* fix(parse): accept spaces between stream and its line break

Microsoft Reporting Services writes `stream \r\n`, a space before the line break.
hayro-syntax and pdfcraft-cos took the stream data to start at the space, so the
content stream failed to inflate: the page rendered blank (white, or black with
inverted colours) and an edited save corrupted the stream. Spaces and tabs are now
skipped, but only when a line break follows.

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

* Number the stream end-of-line patch (20), as vendor/README does

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

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
2026-10-19 02:50:21 -04:00
mtlcl410andClaude Opus 5.5 b955c2eefb M2: a tiling pattern drawn once shows its cell at full scale (#3349) (#3356)
* M2: a tiling pattern drawn once shows its cell at full scale (#3349)

PowerPoint writes a picture fill as a tiling pattern with /XStep 2147480100.
Fitting that step into the 3000 px cell pixmap shrank the picture below a
pixel. When what is painted can only show the first cell, the cell's /BBox is
drawn at full scale with a transparent border and padded instead of tiled.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

* M2: a tiling cell whose scale isn't finite keeps the old path (#3349)

Review follow-up on #3356: a /BBox 1e-40 wide passes the zero-area check and
gives an infinite cell scale, which would send non-finite geometry to the cell
renderer.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

* M2: a stroke's miter counts in the one-cell check (#3349)

Review follow-up on #3356: shows_one_cell took the line width as a stroke's
reach; a miter join reaches half the width times the miter limit. The reach
formula patch (9) uses is now one function, stroke_reach, used by both.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

* M2: a skewed stroke's reach uses the transform's largest stretch (#3349)

Review on #3356: under a skew, a direction between the axes stretches
further than either axis, so the larger axis stretch could place a miter
tip short of the next cell when it reached it, and the one-cell path left
that cell unpainted. The reach now uses the spectral norm.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:50:09 -04:00
TomCatTandClaude Opus 5.5 4d42b48d20 fix(sign): offer only certificates that may sign documents from the Windows store (#3365)
A CAC puts its encryption, logon and signing certificates in the store
under the same name, so the digital ID list showed several identical
entries and only one of them makes a signature that validates. Grey out
the ones whose key usage or extended key usage doesn't allow document
signing, with the reason, the same way an ID without a usable key is
already treated.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:49:57 -04:00
mtlcl410andClaude Opus 5.5 2f21f920a0 fix(windows): name the single-instance socket by the session id, so a launch without SESSIONNAME finds its session's window (#3338) (#3340)
* fix(app): a launch without SESSIONNAME hands its files to the console session's window (#3338)

Task Scheduler, services and some remote shells start PdfCraft without
SESSIONNAME, so the launch looked for instance.sock while the window opened
from Explorer listens on instance-Console.sock, and a second window opened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

* fix(windows): name the single-instance socket by the session id, not SESSIONNAME (#3338)

Review on #3340 (earlvanze): falling back to the console's socket when
SESSIONNAME is unset could hand a file from a Remote Desktop session to a
console window of the same user in another session. The socket is now named
by the session id in the process token (winsafe, no unsafe): a launch from
Task Scheduler runs in the user's session and finds its window, and
different sessions never share a socket. SESSIONNAME names it only if the id
can't be read.

Tested with a real scheduled task: on main the task's launch (no
SESSIONNAME, session 1) opened a second window; with this change the file
went to the running window in session 1.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 02:49:46 -04:00
6733e073ef Keep long menus usable in short windows (#3374)
* M14: keep long menus usable in short windows

* Menus: scroll each top-level menu once, from its caller, so View's list isn't nested in a second scroll area

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-19 02:49:34 -04:00
7d9adcb8f1 fix(preflight): identify PDF standards by XML namespace (#3364)
* fix(preflight): identify standards by XML namespace

* fix(preflight): bound XMP attribute parsing work

* fix(preflight): cap XMP during stream decoding

* Preflight: read the PDF/A and PDF/UA identification by its usual prefix when the XMP can't be parsed as XML

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-19 02:48:40 -04:00
Earl Co 236ce9a064 Clear image pixels intersected by redaction marks (#3368) 2026-10-19 02:48:29 -04:00
Earl Co 66f1085688 Keep document scroll position across viewer modes (#3362) 2026-10-19 02:48:18 -04:00
MarekSpodBiedry 9d23505dd7 Clamp the zoom-anchor scroll to the content so zooming out no longer jolts the page (#3266) (#3350) 2026-10-19 02:48:06 -04:00
Earl Co 6e61b50503 Fix clock-dependent form properties test (#3367) 2026-10-19 02:47:55 -04:00
Chaturanga ManchanayakeandClaude Opus 5.5 4242e7ed50 Test bringing the window forward for a new file while it is still preparing
Review follow-up: the earlier assertion reopened the same path, which takes
the existing-tab shortcut. This one hands the running app a new file with
preparation held, checks Minimized(false) and Focus are sent before release,
and checks the new file is the selected tab once it is prepared.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 12:12:57 +05:30
manchitmrandClaude Opus 5.5 38e5c4bb5b Bring the window forward when the running app is handed files
Opening a PDF from Finder (or Open With, or a Dock drop) while PdfCraft was
already running added the tab but left the window where it was: behind
Finder, minimized, or full screen on another Space, so nothing seemed to
happen. The same applies to files handed over by another launch on Windows
and Linux, which arrive through the same OsEvent::Open path.

After opening the files, un-minimize the window and focus it, which on
macOS activates the app and orders the window front (switching to its
full-screen Space).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 12:11:09 +05:30
Earl Co a62986b5b4 fix: honor single-page redaction selection 2026-10-19 08:00:54 +02:00
Eric Kaden 8f0557d2bc M12: an XFA script that fails partway keeps what it changed before the error 2026-10-19 01:13:09 -04:00
jonathanwxh-cell ec34fc2c2d fix(ui): pin session clock in prepare button-label test to prevent ModDate second-boundary flake 2026-10-19 12:54:45 +08:00
Eric Kaden 93544ef1bf M12: the XFA notice bar starts its first layout note as a sentence
Layout notes are lowercase clauses joined with semicolons, and the bar
put the first right after the layout's own sentence ('11 fields. the
form's usage rights...'). The first note now starts with a capital.
2026-10-19 00:32:52 -04:00
Eric Kaden 097c452c84 M12: a date its data picture can't hold stays ISO in the data
A two-digit year reads back as 1950 to 2049, so 2050 written as 50 came
back as 1950. A date is now written in the data picture only when it
reads back from it unchanged.
2026-10-19 00:26:05 -04:00
mtlcl410andClaude Opus 5.5 49fa11942f M10: glyph names with lowercase hex digits map to nothing (#3170)
Review on #3239: the Adobe Glyph List Specification's `uni` and `u` forms
take uppercase hexadecimal digits only (section 2), and its examples map
`uni20ac` to an empty string. glyph_name_to_text accepted lowercase too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 12:22:00 +08:00
Eric Kaden 38d3a6c843 M12: each XFA date field uses its own data picture, and only a whole-date one
The template field behind a SOM path is now found by its number, as the
form numbers same-named siblings and repeated instances; the live form's
value refresh uses the same lookup. A data picture without a year, month
and day (date{YYYYMM}) keeps ISO dates in the data, since it can't hold
the date the field shows.
2026-10-19 00:18:03 -04:00
jonathanwxh-cell d16c94a703 M12: follow rewritten figure stream in engine regression 2026-10-19 12:12:12 +08:00
Eric Kaden c392d93ba6 M12: laying out a dynamic XFA form takes off the usage rights it voids
The layout revision replaces the placeholder pages and adds the fields,
so usage rights (/Perms /UR3) signed over the form as published no
longer match it, and a viewer may then open the form with every field
locked. write_form now takes them off with the helper strip already
needed, and the layout report says so.
2026-10-19 00:06:32 -04:00
Eric Kaden 93f90ef760 M12: XFA dates are written and read in the field's data picture
A field's data picture (<bind><picture>, such as date{YYYYMMDD}) is how
its value is written in the XFA data, but PdfCraft always wrote dates
there as ISO (2026-10-18) and read them back as ISO, so a form that keeps
its dates as 20261018 got a different format from PdfCraft than from
other viewers, and data those viewers wrote was shown as stored.

The parser keeps <bind><picture> as Field::data_picture. A typed date is
still read in the field's own pattern and turned into ISO; it is then
written in the data picture when the field has one. Reading goes the
other way, on layout and when values are taken from the data of a form
laid out before. A value that doesn't match its data picture is read as
ISO, so data written by earlier versions still reads. The date-letters
rule for XFA picture clauses moves to one helper (date_letters) that the
layout's date_pattern now uses too.
2026-10-18 23:46:43 -04:00
jonathanwxh-cell e3d095f632 M12: isolate decorative edits of shared content streams 2026-10-19 11:45:29 +08:00
jonathanwxh-cell e22d7066c0 M2: integrate current main into PR #3116 and add raster clip-only test 2026-10-19 09:23:19 +08:00
mtlcl410andClaude Opus 5.5 0de546587d fix(windows): present Direct3D 12 through a composition visual, so resizing doesn't stretch (#2738)
While the window was being resized, Windows stretched the window's swap
chain, still at the old size, to the new one: the text shimmered and the
left panel's width bounced for as long as the drag lasted. A DirectComposition
visual's last frame is shown at its own size instead. WGPU_DX12_PRESENTATION_SYSTEM
still overrides it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Gv2WwdgjmBz33GWkwgNn3Q
2026-10-19 09:09:01 +08:00