* security(anim): index slides and shapes once, share paragraph targets and motion paths
Custom-show resolution, timeline target lookup and by-paragraph builds scaled with the product
of two document-controlled counts, and paragraph expansion deep-copied the parsed motion path
into every effect.
- show_order / custom_indices resolve slide ids through one id->index map.
- Timeline::with indexes shapes once (same first-wins order as Slide::shape) for animation
targets and base colours, and records each animated shape's colour with a set.
- Paragraph targets are worked out once per shape and shared across its animations.
- Effects share their EffectSpec (and so the motion path) by Rc instead of cloning it.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* fix(anim): use Arc for EffectSpec to satisfy Sync and early return on empty animations
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
A pattern fill imported with a preset (prstClr) or system (sysClr) color
turned that color black on any change in the gallery or either color
menu, because the color parameter fell back to #000000 for those bases.
Color parameters now carry them as {"preset": name} and
{"system": name, "last": "#RRGGBB"}, with their transforms, and the
engine reads both forms.
A pattern swatch with keyboard focus now gets the same outline as a
hovered or selected one.
Format Shape's Fill section showed the solid-fill Color button with a
gradient, a picture or no fill, and picking a color there replaced the
fill with a solid one. With a gradient it also showed a Transparency
slider that did not change the fill.
The Color button now shows only when the Fill options show Solid fill
or Automatic, and the Transparency slider shows for a solid, automatic
or picture fill. A fill that follows the group or the slide background
shows as Automatic and has no Transparency slider. With a picture fill
the slider starts at the picture's transparency instead of 0%.
Format Shape's Pattern fill set 25 % in accent 1 on background 1 and
offered no way to change it, and Format Background listed 10 of the 54
presets by their XML names. Both panes now show the same editor: a
gallery of the 54 DrawingML presets drawn in the fill's own colors,
each named in words, and Foreground and Background color menus.
With a pattern fill, Format Shape no longer shows the solid-fill Color
button, which replaced the pattern with a solid fill, or the
Transparency slider, which did not change a pattern. The renderer
exports the preset list and tiles for the gallery to draw.
The guard put back the remembered point type after a panic even when the
command had made another document active, so the type of a shape in the
first document applied to a shape with the same id in the second. The
guard now puts it back only when the document from before is still active,
and forgets it otherwise.
A command that panicked after changing the point type Edit Points remembers
left the new type in place, since the guard put back only the document and
selection. The guard now puts the remembered type back too. Shape ids repeat
across documents, so a change of active document forgets the remembered
type.
The segment menu in Edit Points offered only Straight Segment and Curved
Segment. It now also has Add Point, which adds a point where the right
click was, Delete Segment, which removes the segment from a closed outline
so that the outline opens there (grayed out on an open outline), and Open
Path, which opens the outline at the segment's start point (Close Path on
an open outline).
`shape.deleteSegment` does the deletion for the CLI and MCP.
The place on a segment that a click picks was found only in steps of 1/32
of the segment, so Add Point and Ctrl-click could add the point as far
as 1/64 of a straight segment's length from the pointer. It is now narrowed
down after that first pass.
Adding or deleting a point now forgets a point type remembered for handle
drags, as opening and closing the outline already did. `shape.addPoint` on
the first point of an open outline no longer splits the closing edge of
another outline later in the same path.
Undo restored the outline but kept the point type that a handle drag with
Shift, Ctrl or Alt, or a Point Type choice, had set, so the next drag
without a modifier applied the undone type again. Each undo step now keeps
the point type remembered with the document it restores, and Undo and Redo
put it back, including a Straight or Corner choice that the handles alone
do not show. A command that fails leaves the remembered type as it was, and
the type applies only to the shape it was chosen on.
The Animation Pane row in ui-parity.md said the pane cannot preview from
the selected effect, but its button reads Play From and starts there
(animpane_tests). gaps.md, file-format-parity.md and the parity checklist
said .potx and .ppsx are saved with the .pptx content type, but
deckcraft_pptx::export_as writes the template and slide-show content
types, as a test in crates/pptx/tests/it/roundtrip.rs checks. The
gaps.md entry now covers only the macro-enabled variants. The checklist
row stays partial, and cargo xtask parity leaves the summary unchanged.
The zoom slider's number and range were the natural log of the zoom, so
a screen reader read 0 at 100% and set the zoom in log units. The slider
now runs from 10 to 400 percent on a log scale, and its number is the
percentage its text shows. Reading View reports itself as selected when
the view is Reading View, as the other view buttons do.
Esc during a vertex or handle drag in Edit Points used to leave Edit
Points while the drag went on: the point kept following the pointer and
the release added an undo step. Esc now ends the drag and puts the shape
back as it was at the press, with no undo step, and Edit Points stays on.
Esc without a drag still leaves Edit Points.
A handle drag in Edit Points ignored the modifier keys: the point kept
the type it had. In PowerPoint, Shift, Ctrl or Alt held during the drag
sets the point's type.
Shift held while dragging a point's handle now makes it a smooth point.
Ctrl (Cmd on the Mac) makes it a straight point, and Alt (Option) makes
it a corner point. The handle drag passes that type to shape.moveHandle,
and the point keeps it for the next drag without a modifier, as after
Smooth Point, Straight Point or Corner Point in the right-click menu.
The status bar's Fit, Zoom In, Zoom Out, Slide Show, Reading View, Slide
Sorter and Normal buttons and the language name reported no widget info,
the zoom percentage reported only its own text as a label, and the zoom
slider had no name, so a screen reader announced the buttons and the
language without a name. The slide counter and the status message were
painted text with no accessibility node, so a screen reader could not
read them.
Each icon button now reports its tooltip as its name, and the four view
buttons also report whether their view is the one shown. The zoom
percentage is the "Zoom level" button with the percentage as its value,
and the slider is "Zoom" with the percentage as its text value. The
language name is the "Language" button with the language as its value.
The slide counter and the status message are labels with the text they
show.
With several text boxes selected, the dialog shows the first one's
values. OK sent both Number and Spacing, so changing one of them also
gave every box the first box's value of the other. OK now sends only
the fields that differ from what the dialog showed, and with neither
changed it closes without an edit.
The accepting thread drained each connection it refused as busy for up
to 250 ms before accepting the next, so refused peers that stayed
connected without writing delayed every connection after them. Each
drain now runs on a thread of its own, up to 16 at once; past that, a
refused connection gets the busy reply and is closed without a drain.
connection_limit_refuses_then_frees_slot now uses a 30 s idle timeout:
its first client sends nothing, and under load the 300 ms timeout
closed it before the third client connected.
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.
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.
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.
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.
* 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
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.