Commit Graph
1863 Commits
Author SHA1 Message Date
Dominik Strebel c15e260794 fix(render): an emphasis tint recolours the fill behind a picture's and an object preview's transparent pixels 2026-10-24 16:48:24 +02:00
NetterSilverandClaude Haiku 5.5 744c01f66f Match style as a whole attribute name in HTML paste
Found while testing crates/engine/src/cmd/richclip.rs:230-242 (attr, used by tag_style)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 14:35:42 +00:00
NetterSilverandClaude Haiku 5.5 35f240e453 Return BadParams for overflowing start in review.spellingChange
Found while testing crates/engine/src/cmd/review.rs:424 (spelling_change)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 13:53:26 +00:00
KataccandClaude Opus 5.5 8bc0afaff5 Test the Language dialog's default with nothing selected
With no text or shape selected, Review › Language must apply to the
whole presentation without choosing it, and Selected text must be
disabled. The existing test still covers switching to Whole
presentation while text is selected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:55 +03:00
KataccandClaude Opus 5.5 66e369de26 Doc comments for the language functions
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:55 +03:00
KataccandClaude Opus 5.5 291725c78e format.languageAll: also mark each text body's own list style
A layout placeholder's a:lstStyle can carry lang/noProof, and
ed::format_all only touched runs and end marks, so such a placeholder
kept its old language. Existing list style levels of shape, table cell
and notes bodies now get the edit too; bodies without one get none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:55 +03:00
KataccandClaude Opus 5.5 507fdc3767 Contributors: credit Katacc by GitHub profile name
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:53 +03:00
KataccandClaude Opus 5.5 2d3997d2e3 Review: proofing language for the whole presentation
Review › Language gets "Apply to: Selected text / Whole presentation".
The new format.languageAll command sets lang/noProof on every run in
the deck (slides, groups, table cells, notes, masters, layouts) and on
the master and default text styles, so new text inherits it. It needs
no selection and is one undo step; format.language is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 16:31:35 +03:00
dotCooCoo c207d6eb0f Tests: the Notes-button test clicks where the button is laid out, so it passes without Inter
status::tests::a_long_language_name_leaves_the_notes_button_clickable
clicked x 150 for the gap before the status bar's controls and x 200 for
the Notes button. Those positions hold for Inter. With a craft-fonts
checkout that has no fonts/latin-manifest.txt, the interface text is set
in BIZ UDPGothic. Labels set in BIZ UDPGothic are wider than in Inter,
so the Notes button starts at x 149. The first click then toggled the
notes pane and the second toggled it back.

The status bar's Notes and Comments buttons now report widget info with
their names. The test reads the Notes button's rect, clicks midway
between x 132 and its left edge, and then clicks its center.
2026-10-24 06:25:07 -07:00
dotCooCoo e89c824c6d Text: a Columns dialog sets the number of columns and the spacing between them
Home > Columns offered 1, 2 or 3 columns, always 18 pt apart, and Format
Shape > Text Box had the same three buttons. The spacing could not be
seen or changed, and picking a number reset it.

Home > Columns > More Columns... and a Columns... button in Format Shape
> Text Box now open a Columns dialog with Number (1 to 16) and Spacing in
inches, filled in from the text box. OK applies both in one undo step.
A Spacing left as shown keeps the text box's exact value.

format.columns with no fields opens the dialog. A key left out keeps the
text box's own value instead of resetting it to 1 column or 0 pt, and a
count that is not a whole number from 1 to 16, or a spacing that is not
a number, is an error. Before, an out-of-range count was clamped, a
count that was not a whole number meant 1 column, and a spacing that
was not a number meant 0 pt.
2026-10-24 05:57:36 -07:00
aiongg 38d2ade2b7 Merge pull request #1260 from aiongg/r1-batch1
Integration batch 1: 35 contributor PRs (charts, shapes, slides, text editing, dialogs, outline files)
2026-10-24 08:38:28 -04:00
Dominik Strebel a8f1573fba fix(pptx): an object saved as its preview picture keeps the fallback picture's fill 2026-10-24 14:29:30 +02:00
NetterSilverandClaude Haiku 5.5 53eda1e8df Reject multiple leading '#' in Rgba::from_hex
Found while testing crates/color/src/lib.rs:37

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 14:21:11 +02:00
Dominik StrebelandClaude Opus 5.5 aece097096 Render: a picture's fill shows behind its transparent pixels
PowerPoint draws a picture's own fill (p:pic/p:spPr) behind the picture, so
it shows through its transparent pixels: a synthetic deck with one
half-transparent PNG three times (no fill, an orange fill, a yellow fill
with a blue outline), exported as PDF, shows the orange and yellow boxes
behind the image. DeckCraft drew the outline but never the fill.

Old equation objects use this: an OLE object (p:oleObj, Equation.3) has a
fallback picture whose spPr gives it a coloured box behind the equation's
transparent metafile. The reader took only the picture's image as the
object's preview and dropped its fill and line.

- The shape-fill loop moves into Renderer::fill_geometry; a picture and an
  embedded object's preview paint their own explicit fill with it before
  the image (a style fill alone still draws nothing, as before).
- An embedded object without a fill or line of its own takes them from
  its fallback picture's spPr; its frame keeps its own position.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-24 14:07:43 +02:00
dotCooCoo 79c1d578be Control server: a peer refused as busy still reads why, and two tests no longer race
When every connection slot was taken, the accepting thread wrote the busy
reply and dropped the socket. A peer that had already written a line saw a
reset instead of the reason. The busy path now closes the same way a
rejected line does: it sends the FIN and drains the socket for at most
250 ms, or the write timeout when that is shorter.

The drain set its read timeout on the writing handle and read through a
clone of the socket. On Windows, a read timeout set on one handle of a
try_clone pair can fail to apply to reads through the other. On Windows 11
a rejected peer that stayed connected then kept its slot until the idle
timeout (10 minutes by default) instead of the write timeout. The timeout
is now set on the handle that reads.

Two tests failed intermittently. a_pipelined_peer_still_reads_why_its_line_was_rejected
connected 12 peers through 2 slots, and a slot comes back only after the
thread serving the previous peer ends; each peer now has a slot of its own.
blocked_ui_times_out_and_full_queue_is_busy relied on a 50 ms sleep to
order two requests from two connections; it now accepts either order.
2026-10-24 04:59:06 -07:00
dotCooCoo 44d5a0e7b9 Tests: UI tests that render with wgpu take turns, so the Windows test run no longer crashes
Harness::render creates a wgpu device on its first call, and egui_kittest
prefers a CPU adapter. When cargo test runs several of these tests on
parallel threads, the deckcraft-ui-egui test binary can exit with
0xc0000005 (STATUS_ACCESS_VIOLATION), so cargo xtask ci stops at its test
step on Windows without cargo-nextest.

The 16 tests that call render now hold one mutex for their whole run
(crate::gpu_lock::gpu_lock, as in photocraft's testkit), so only one of
them runs at a time.
2026-10-24 04:05:13 -07:00
oracola91 920925abae PDF export keeps only the links the slide show opens
A denylist can't keep up with OS protocol handlers: ms-msdt:, ms-word:
with a share path, ldap: and file:///%5C%5Chost/share still went into
exported PDFs. PDF export now writes a URL link only when safe_url
allows it, the check the slide show already uses on a click: http,
https and mailto. Links between slides are unchanged, and any other
link's text stays on the page without the link.

safe_url moves from deckcraft-anim to deckcraft-model, which both
crates use; deckcraft_anim::safe_url stays as a re-export. Local file:
and relative links are left out for now, as asked in review.
2026-10-24 13:31:06 +03:00
oracola91 274b626007 Test: every link of the unsafe-link test sits on the slide
The last links started below the 540 pt slide. They were still
exported, as zero-height annotations at the page edge, so the test
worked, but only because of that. With all 16 links on the slide the
test no longer depends on how off-page links are handled.
2026-10-24 13:27:00 +03:00
oracola91 afb52aeef3 PDF export also drops search: and search-ms: links
Windows Search's search: and search-ms: links can name a folder on
another machine through crumb=location:, and opening one connects to
that host and sends the user's NTLM credentials. They are now left out
of the PDF like the other network-share links, and the test covers both.
2026-10-24 13:27:00 +03:00
oracola91 8c4907a626 PDF export also drops smb: links
An smb://host/share link is a path to another machine too: opening it
connects to that host (macOS and Linux file managers open these links).
It is now left out of the PDF like the other network-share links, and
the test covers it.
2026-10-24 13:27:00 +03:00
oracola91 8fd1c1716f PDF export drops javascript:, vbscript:, data: and network-share links
A slide hyperlink from an untrusted deck became a PDF link whatever it
pointed at. Script and data links, and links to another machine (UNC
\\host\share, //host/share, file://host/...), are now left out of the
PDF; the text stays. On Windows, opening a network path sends the
user's NTLM credentials to that host.

Web, mail, local file: and relative links are kept. The scheme is read
the way a browser reads it: control characters dropped, leading spaces
trimmed, any case. The slide show already refuses these links
(safe_url), and cadcraft's PDF export drops script and data links.
2026-10-24 13:27:00 +03:00
NetterSilverandClaude Haiku 5.5 fb778030c9 Reject invalid shape ids in ids instead of using the selection
Found while testing crates/engine/src/cmd/mod.rs:ids_param / targets (~line 335-350)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 10:13:35 +00:00
Dylan M. Taylor 7be391a1be fix(pptx): harden import resource budgets, deduplication, and lookup caching (#1283)
* fix(pptx): harden import resource budgets, deduplication, and lookup caching

- Chart sidecars (Finding 2): Enforce an import-wide retained byte budget
  and cache captured sidecars by chart part to prevent memory amplification.
- Content types cache (Finding 6): Cache parsed [Content_Types].xml defaults
  and overrides in Package.ct_cache.
- Text run splitting and font lengths (Finding 8): Bound typeface attribute
  lengths and cap paragraph runs to prevent multiplication on text splitting.
- Inner namespace decls (Finding 15): Use HashSet/HashMap indexing and cap
  inner declarations to 1,000.
- Slide and notes deduplication (Finding 16): Deduplicate slide paths and
  cache parsed notes slide bodies by target.
- Diagram media caching (Finding 22): Cache diagram media payloads in
  imp.media_by_part.
- Master slide deduplication (Finding 28): Deduplicate master paths before
  loading.
- Layout target deduplication (Finding 30): Deduplicate layout targets
  across master slides.
- Chart value axis indexing (Finding 32): Index valAx by axId using a HashMap.
- ChartEx series output budget (Finding 34): Charge series point vectors
  against an aggregate output budget and cap series count.
- ChartEx point allocation bounds (Finding 36): Allocate point vectors
  only to actual point span bounded by budget rather than declared ptCount.
- SmartArt recursion depth (Finding 38): Limit SmartArt recursion depth to 8.

* fix(pptx): address review feedback on sidecar cache, series budget, and inner decls

* fix(pptx): preserve cached sidecar bytes and non-empty category fallback
2026-10-24 06:01:30 -04:00
dotCooCoo e8910cb253 Paste: a table, bullet or slide from another deck keeps its own pictures and sounds
Copy listed the media of pictures, media clips, 3-D models and shape
fills only, and Paste rewrote the ids of pictures, media clips, opaque
previews and shape fills only. Picture fills in table cells and table
backgrounds, picture-filled text runs and picture bullets were left off
the clipboard. In another deck they pointed at a missing picture, or at
that deck's own picture when it used the same media id. A copied slide
lost its transition and animation sounds in the same way.

Paste Special > Picture gave clashing media fresh ids but drew the
shapes with the old ids, so a clashing id drew the open deck's picture.
Review > Compare > Accept Revision of a compared deck's slide copied the
same partial set, and missed the slide background as well.

Copy, Paste, Paste Special > Picture and Accept Revision now find and
rewrite media ids with the media_refs walkers that slide.reuse uses.
2026-10-24 02:48:19 -07:00
aiongg 528af4e503 Integration: a rejected positional revision is not turned into a deletion when a slide is inserted before it 2026-10-24 09:40:33 +00:00
aiongg 202255cbbb Integration: restore chart.rs CRLF line endings 2026-10-24 09:39:13 +00:00
aiongg 44b33a2f57 Integration: a subnormal chart data range gives a finite nice scale 2026-10-24 09:38:51 +00:00
aiongg 56b15df0ab Integration: a huge RTF left indent no longer overflows when the outline level is derived 2026-10-24 09:38:19 +00:00
NetterSilverandClaude Haiku 5.5 ef6819b6fd Reject '+' sign in OPC target percent-decoding
Found while testing crates/pptx/src/opc.rs:263-277 (percent_decode, used by resolve)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 09:31:47 +00:00
aiongg a453292729 Merge main into the integration batch 2026-10-24 09:20:03 +00:00
aiongg 910b03f4a1 Integration: the GIF play/pause click works only while the pointer is awake and the button is shown 2026-10-24 09:19:46 +00:00
aiongg e679fa500a Integration: right-clicking a control handle in Edit Points keeps the picked point and its menu 2026-10-24 09:17:30 +00:00
aiongg 027075d352 Integration: a rejected positional revision stays rejected after a slide is inserted or deleted in the open deck 2026-10-24 09:16:08 +00:00
Dylan M. Taylor f86928d0d5 perf(pptx): index export lookups and deduplicate relationship parts (#1281)
- Row 31: Use HashMap for comment author lookup in author_slot
- Row 37: Index preserved parts by ID before resolving graphic frame relationships
- Row 10: Index kept chart parts by normalized path and avoid duplicate payload scans
- Row 39: Update existing relationship parts instead of appending duplicates in PackageOut
2026-10-24 05:16:07 -04:00
aiongg 2bbfe46d3e Integration: slides with two visible pictures get no layout ideas 2026-10-24 09:14:11 +00:00
aiongg 9dcb7bab03 Integration: the automatic-date test reads the clock before and after the command so a tick of the second cannot fail it 2026-10-24 09:13:29 +00:00
aiongg 75bec53e08 Integration: RTF import drops NUL units and masks \u to 16 bits so the surrogate marker cannot be forged 2026-10-24 09:11:34 +00:00
Dylan M. Taylor c55a9f771e security(metafile): harden EMF+ parsing, clipping complexity, and memory accounting (#1280)
* fix(metafile): harden EMF+ parsing, clipping complexity, and memory accounting

- Row 72: Use checked tail slicing in comment header offset calculations
- Row 78: Break FillRects and DrawRects loops early when canvas is full
- Row 75: Pre-check dimensions in decode_compressed before RGBA pixel allocation
- Row 85: Account for EMF+ object table image/path memory against MAX_BYTES
- Row 42: Replace O(N^2) prefix copying in wrap_line with linear measurement
- Row 43 & 54: Share immutable clip regions Arc across placed items and charge canvas regions
- Row 48: Bound text transformation scale and glyph curve geometry in Picture::place and draw_text
- Row 52 & 68: Impose work budget bounds on Sutherland-Hodgman polygon clipping and bitmap masking

* fix(metafile): collapse nested if statement per clippy
2026-10-24 05:06:04 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 63a2e099a6 refactor(hevc): split slicedec functions (S3776)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 08:48:55 +00:00
Dylan M. Taylor c955407373 security(engine): check regular file and size bound on read, preserve permissions and symlinks on save (#1265)
* security(engine): check regular file and size bound on read, preserve permissions and symlinks on save

* style: format recovery.rs write_atomic
2026-10-24 04:45:48 -04:00
Dylan M. TaylorandClaude Sonnet 5.5 54962c6389 refactor: explicit imports for table modules (SonarCloud S2208) (#1262)
* refactor: replace wildcard table imports with explicit names (SonarCloud S2208)

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

* style: rustfmt

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

---------

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:43:36 -04:00
Dylan M. Taylor 6189fa8bf6 perf(engine): bound HTML entity semicolon scan window and formatting stack search (#1267) 2026-10-24 04:41:43 -04:00
SusieeTheFemboyandGLM-5.3 238b34be00 Media: a video with an unsupported codec says only its audio plays (#1237)
insert.video answered playable=true with no warning for a clip whose video
codec has no decoder (a VP8 + Vorbis WebM, say): its audio track plays, but
the slide shows an unexplained black box, which reads as "black with no
audio". The insert now warns that the video can't be played yet and only
the audio plays.

The missing audio itself is not reproducible: through the real insert +
play path the Vorbis track of a VP8 WebM decodes and sounds, on main and on
0.10.0 (the reporter's build). A regression test drives that whole path, on
a new synthesised clip-vp8.webm fixture.

Co-Authored-By: GLM-5.3 <noreply@z.ai>
2026-10-24 10:41:30 +02:00
Dylan M. Taylor 713f605566 perf(chart): optimize axis plotted extent scan and cache non-bar error bar stats (#1266) 2026-10-24 04:41:23 -04:00
Dylan M. Taylor 9641817a15 security: clamp alpha_num bullet expansion and sanitize filename logging (#1264) 2026-10-24 04:40:29 -04:00
Dylan M. Taylor 1e097e3edd security: use exclusive temporary directories for macOS cert import and media fixtures (#1263) 2026-10-24 04:40:26 -04:00
dotCooCoo 9888d7c90e Tables: dragging across cells selects a range of cells
While the caret is in a table cell, a drag into another cell of the
table now selects the cells between them. The range takes in every
merged cell it touches, and the canvas shades the selected cells.
Moving back into the first cell returns to a text selection there.
Shift+arrow moves the cell the range was extended to, and the cell it
started from stays.

With a range selected, run and paragraph formatting apply to those
cells only. Delete clears their text and keeps the cells and the table,
and Copy and Cut take their text, with a tab between cells and a line
per row. Shading, Borders, Cell Margins and Align take in the merged
cells the range touches. A press in the table starts again in the cell
under the pointer.
2026-10-24 01:29:58 -07:00
Dylan M. TaylorandClaude Sonnet 5.5 d94790d97a refactor: replace redundant closures with method paths (SonarCloud S1612) (#1261)
Skipped where the receiver type is generic or not evident without a compiler (wrapping_neg, total_cmp, exists, to_vec, as_ref, split_first, Option::into_inner).

Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-24 04:27:07 -04:00
dotCooCoo 05f2a84400 Text: text.insert reports the caret where AutoCorrect leaves it
text.insert returned the caret from before AutoCorrect ran. After a
typed space started a list, it reported (0, 2) for `* ` while the caret
was at (0, 0) in the emptied paragraph, and after `(c) ` it reported
(0, 4) for the two-character `© `. It now reports the caret from the
selection after AutoCorrect.
2026-10-24 00:44:36 -07:00
aiongg 9c31b567da Integration: #978 media-controls test turns presenter view off so its embedded window does not cover the bar 2026-10-24 07:28:17 +00:00