Commit Graph
5180 Commits
Author SHA1 Message Date
Dylan M. Taylor 1c3285d8a3 Count progressive JPEG buffers in warm budget 2026-11-12 17:55:11 -05:00
Dylan M. Taylor 067fc97128 Use iterator for reduced mip accounting 2026-11-12 17:45:02 -05:00
Dylan M. Taylor eb4fdc3096 Merge latest upstream into parallel image decode 2026-11-12 17:42:28 -05:00
.CooCooandDylan M. Taylor 437c532511 Compose: count endnote, anchored object and cross-reference marks once per story (#2705)
* Compose: count endnote, anchored object and cross-reference marks once per story

Each paragraph of a story with endnotes, anchored objects or
cross-references counted the marks before it from the story start, so
composing the story read its text once per paragraph. The marks before
each paragraph are now counted in one pass when composition starts.

* Compose: test cross-reference mark counts past the first paragraph

The mark-count fixture now puts a cross-reference in every paragraph, so the
test checks nonzero cross-reference counts and that each paragraph shows its
own cross-reference's text.

---------

Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
2026-11-12 17:42:10 -05:00
Dylan M. Taylor 764b06526b Estimate reduced JPEG warm reservations 2026-11-12 17:41:55 -05:00
Dylan M. Taylor 33f0c21510 Estimate reduced JPEG cache and decode sizes 2026-11-12 17:40:51 -05:00
.CooCoo 0f792e1fe9 Compose: vertical justification moves an object kept within its column with its line (#2720)
* Text wrap: an object kept within its column moves with its line

Vertical justification treated an object positioned from its anchor and
kept within its column as fixed, so its wrap stopped Center, Bottom and
Justify where the object started, although the object moves down with
its anchor's line until it reaches the column's bottom. A line now moves
down at most the room above the object plus the distance the object can
move before the column stops it.

The story's object-mark positions are now collected once per composition
instead of once per frame that holds an anchored object.

* Compose: Justify keeps the room under an object held at the column's top

An object kept within its column and held at the column's top moves only
after its anchor's row has moved down far enough to bring it off the top.
Justify took that distance off a later line's room even when the anchor's
row moved less, so with the anchor in the first row, which stays in place,
the later line stopped that distance short of the object's wrap. A line now
moves its room plus how far the anchor's row moves past that distance.
2026-11-12 17:32:12 -05:00
Dylan M. Taylor f90cd8835d Merge latest upstream into parallel image decode 2026-11-12 17:28:47 -05:00
.CooCoo 67a5cb273e Tables: table commands are disabled with the caret in footnote text (#2706)
Footnote text is addressed as a cell, so with the insertion point in a
footnote the table commands (Insert Row, Delete Column, Merge Cells,
Table Options, Select Table, table styles) were enabled and then failed
with "no table 18446744073709551615". They are now disabled with "place
the insertion point in a table", as the cell commands already were. The
caret's footnote offset is no longer looked up in the main story either,
where it could land on a table's paragraph. table.get and the other
commands that take any selection report the same message instead of the
footnote address. A call that names a table still runs.
2026-11-12 17:27:13 -05:00
.CooCooandDylan M. Taylor 5fb75aaefc Properties: Text Frame section shows inset spacing and vertical justification (#2661)
* Properties: Text Frame section shows inset spacing and vertical justification

Properties › Text Frame now shows the frame's inset spacing under the
columns: Top and Bottom, a link that makes all four the same, then Left
and Right. A non-rectangular frame shows one Inset, the distance its text
keeps from the outline. Four buttons set Vertical Justification to Top,
Center, Bottom or Justify. Type on a path shows neither.

The section also shows with the Type tool in a frame. There it changes
the frame that shows the insertion point, or every frame that holds part
of the selected text, as Object › Text Frame Options does.

* Properties: one Inset for a non-rectangular frame keeps the other sides

The single Inset sets only the top inset, the one kept from the
outline. A rectangular frame that holds part of the same selected text
keeps its own sides.

* Properties: the one Inset field and the composer share the frame outline test

FrameOutline::of_item builds an item's outline with its corner options
applied. The composer uses it to keep the top inset from the outline,
and the Properties panel uses it to decide whether a frame shows one
Inset, so the two give the same answer for every frame.

* Text Frame Options: frames taken while typing stay with their document

OK is refused when another document became active after the dialog opened, so the saved frame ids do not change frames in that document.

* Properties: the inset link starts linked again after Revert

The link's state is kept per document state instead of per document, so
a frame with equal insets in the reverted document starts linked.

* Text Frame Options: frames taken while typing are refused after Revert

Revert keeps the document's id but replaces its state, so a new frame
can reuse a saved frame id. The dialog now ties the frames to the
document state, and OK is refused after Revert as it is in another
document.

* Properties: the one Inset of a non-rectangular frame sets all four sides

The composer bounds a shaped frame's text by its rectangle less all four
insets as well as by the outline, so a single Inset that changed only the
top left hidden sides in place: lowering a uniform 96 pt inset to 0 kept
text overset. When every frame the field changes is shaped, it now sets
all four sides. With a rectangular frame among them, only the top inset
changes and each frame keeps its other sides.

* Fix text frame dialog merge resolution

* Keep text frame preview targets fixed

* Fix target field key inference

* Tests: Text Frame Options show four sides for text through an oval and a rectangle

With the Type tool and text selected through an oval and a threaded
rectangle, with the oval as the caret's stored frame, the dialog shows
the four inset sides, a changed Top leaves the rectangle's other sides
as they were, and the link stays off while the rectangle's sides are
uneven.

* Properties: the inset link starts off when another frame has uneven sides

With selected text that runs through several frames, the link of Text
Frame > Inset Spacing started linked when the frame the section shows had
four equal insets, and a changed Top then set all four sides of every
frame. The link now starts linked only when every frame the field changes
has four equal insets. Its state is kept for that set of frames, so a link
turned on for one frame does not carry over to selected text that also
runs through a frame with uneven sides.

---------

Co-authored-by: Dylan M. Taylor <dylan@dylanmtaylor.com>
2026-11-12 17:27:08 -05:00
.CooCoo 66b8c8ba3e Object styles: checks and fixes for corners, strokes and the style dialog (#2721)
- Corner options use path order for a path with more than one subpath, so
  a second rectangle no longer takes the first one's corner order.
- IDML export writes EnableStrokeAndCornerOptions="false" for a style
  without corners, so it does not take corners from its based-on style on
  import.
- style.object.create and style.object.edit refuse a stroke gap tint
  outside 0 to 1 and a stroke type field that its kind does not take, as
  object.stroke does. An edit that changes nothing returns restyled: 0.
- New Object Style and Object Style Options read a bare number in the
  document's ruler unit, keep a Text Frame General measurement that was
  not edited at its exact value, and New Object Style refuses a name
  another style has.
- Clear Overrides in the Object Styles panel is enabled when any selected
  object differs from its style.
2026-11-12 17:25:39 -05:00
.CooCoo 6923c220ad Text wrap: Bottom and Center move a line down between a contour's arms (#2719)
A line set in the open middle of a U-shaped contour now goes down to the
contour's base. The clearance check tests the occupied parts of the
contour in the line's band, as line setting does, instead of its outer
extent across both arms.
2026-11-12 17:24:40 -05:00
.CooCoo c803ea80b1 Compose: vertical justification in a shaped frame tests lines to their baselines (#2708)
Center, Bottom and Justify tested every moved line except the last against
the frame's outline down to its descent, so an outline that narrows under an
earlier line held the text higher by that line's descent. Each moved line is
now tested from its top down to its baseline, and its descenders may cross
the outline, as the last line's already did. Above footnotes and in vertical
frames the descenders still stay inside.
2026-11-12 17:24:34 -05:00
.CooCoo 9595f3d62e Anchored text frames: test nested hosts in groups, footnotes and table cells (#2722)
Adds three tests for a text frame anchored inside another anchored text
frame: the outer frame as a member of an anchored group with a rotation
and a scale, the inner frame in a footnote of the outer frame, and the
inner frame in a table cell of the outer frame. Each checks the inner
frame's spread, transform and page.
2026-11-12 17:23:50 -05:00
Dylan M. Taylor 2794a60bf0 Account for image decode buffers in warm gate 2026-11-12 17:21:20 -05:00
Dylan M. Taylor a656db2be4 Merge upstream changes into parallel image decode 2026-11-12 17:19:59 -05:00
Dylan M. Taylor 448ac91e72 Merge pull request #2707 from dotCooCoo/fix/jpeg-screen-proxies
Images: decode JPEG screen proxies at a reduced size
2026-11-12 17:16:24 -05:00
Dylan M. Taylor 3149db327a Merge pull request #1834 from dotCooCoo/feat/duplicate-layer
Layers: Duplicate Layer copies a layer's settings and objects above it
2026-11-12 17:10:50 -05:00
Dylan M. Taylor 982dbc6c3c Merge main into parallel image decoding 2026-11-12 17:04:58 -05:00
Dylan M. Taylor 49764b0b37 Merge main into reduced JPEG proxy decoding 2026-11-12 17:03:41 -05:00
Dylan M. Taylor 30752d0130 Merge pull request #2709 from dotCooCoo/fix/opaque-image-premultiply
Render: placed images are premultiplied in their decoded buffer
2026-11-12 17:01:32 -05:00
Dylan M. Taylor 6bb9907de5 Use shared French duplicate layer translation 2026-11-12 16:54:46 -05:00
dotCooCoo 2b6fb6fa06 Images: count a decode's buffers at their peak before decoding in parallel
The gate that limits parallel decodes counted each image at its cached
size (4 bytes a pixel and a third more for the smaller levels). A decode
holds more than that while it converts the pixels: an 8-bit image keeps
its RGBA copy beside the decoded or the premultiplied pixels, 8 bytes a
pixel. Two 5,500 pixel square images passed the gate together and could
hold more than half the cache budget at once.

- decode_sizes returns the cached size and the peak size from one size
  read. The peak counts the samples as stored beside their converted
  copy (designcraft_images::decode_bytes_per_pixel): 8 bytes a pixel for
  8-bit color, 10 for 16-bit RGB, 12 for 16-bit CMYK TIFFs and 16-bit
  RGBA, 10 for 8-bit CMYKA TIFFs, 15 for 16-bit CMYKA TIFFs, 9 for
  PSDs. An EPS counts as its TIFF preview. PDF pages, SVGs and EPS
  files without a preview count 8.
- warm budgets the cache with the cached size and gates decodes with
  the peak size.
- Every warm call in the process shares one gate, so the canvas
  worker, thumbnails and exports together stay within half the budget
  while they decode. warm returns the most its own call had decoding.
- An EPS without a preview is sized at the larger of its drawn
  PostScript and its placeholder. The placeholder is clamped to 4000
  pixels on each side, so a 10,000 by 4,000 point EPS that is not drawn
  takes 4000 by 4000 pixels, not the 4000 by 1600 counted before.
2026-11-12 13:53:38 -08:00
Dylan M. Taylor e6ab0d263e Merge branch 'main' into feat/duplicate-layer 2026-11-12 16:43:33 -05:00
Dylan M. Taylor 5518b65320 Merge pull request #2658 from dotCooCoo/feat/vj-baseline-grid
Compose: vertical justification keeps grid-aligned lines on the baseline grid
2026-11-12 16:43:08 -05:00
Dylan M. Taylor 2b305c9c00 Merge branch 'feat/vj-baseline-grid' of github.com:dotCooCoo/designcraft into codex/integrate-2658b 2026-11-12 16:28:06 -05:00
Dylan M. Taylor 9847f972da Update recovery test for explicit write conflict 2026-11-12 16:27:52 -05:00
Dylan M. Taylor 076e653ac3 Merge remote-tracking branch 'upstream/main' into codex/integrate-2658b 2026-11-12 16:27:39 -05:00
Dylan M. Taylor 5931b17bb6 Translate duplicate layer in remaining locales 2026-11-12 16:22:26 -05:00
Dylan M. Taylor 520aeeefe1 Merge pull request #2652 from dotCooCoo/feat/text-frame-options-type-tool
Text: Text Frame Options open from the Type tool and change the frame holding the caret
2026-11-12 16:09:26 -05:00
dotCooCoo fb77a73d93 Compose: Center on the grid takes the fitting step nearest the middle in a shaped frame
When the grid step nearest the centered place puts the lines outside a frame that narrows and widens again, Center now tries the steps on both sides of it, nearest first, instead of only the steps above it.
2026-11-12 13:05:34 -08:00
dotCooCoo 946e3ea4c1 Compose: grid-aligned vertical justification takes only grid steps that fit a shaped frame
In a frame that narrows and widens again, Bottom, Center and Justify now
try lower grid steps until the lines fit the outline, and leave the lines
in place when none does, instead of taking the next lower step unchecked.
A grid whose step is too small to count across the column is now treated
as no grid when a line is placed, so the line keeps a finite baseline.

Tests cover a waist-shaped frame on a 40 pt grid, a tiny-step grid that
starts away from the line, and Justify with a wrapped paragraph under
All Lines and First Line Only.
2026-11-12 13:05:34 -08:00
Dylan M. Taylor 9fe0dd5197 Merge pull request #2666 from dotCooCoo/fix/recovery-off-interface-thread
Recovery: the timer writes recovery data on a background thread
2026-11-12 16:01:55 -05:00
Dylan M. Taylor fc5221060c Fix vertical justification test arguments 2026-11-12 15:59:29 -05:00
dotCooCoo 07d264fd23 Copy: bound the anchored-object walk through cells and notes
Copying a story gives the objects anchored in its table cells and
notes fresh ids down to 64 levels, as the table copy does. A copy whose
stories below that level hold anchored objects, tables or notes is
refused with the nested-too-deeply error instead of recursing without
limit.
2026-11-12 12:57:17 -08:00
dotCooCoo 55963c4918 Images: pick a reduced JPEG's scale by its long side
The JPEG decoder takes the smallest scale that meets either requested
side. A short side rounds up to the same size at several scales, so a
100 x 2 JPEG asked for at a half decoded at an eighth (13 x 1). The
long side alone now picks the scale, and a decode whose size differs
from the requested reduction is refused, which falls back to the full
decode.
2026-11-12 12:57:16 -08:00
Dylan M. Taylor f88e6711e0 Merge latest main into baseline grid justification PR 2026-11-12 15:54:56 -05:00
Dylan M. Taylor 7362fffbcf Merge pull request #2654 from dotCooCoo/fix/effect-damage-bounds
Canvas: moving an object with a drop shadow repaints only its area
2026-11-12 15:50:44 -05:00
Dylan M. Taylor bf9d27f9b3 Merge pull request #2667 from dotCooCoo/fix/bottom-aligned-text-wrap
Compose: vertical justification keeps text out of a wrap under it
2026-11-12 15:49:37 -05:00
dotCooCoo 6d8f26a6be Render: cull a scaled object by its scaled stroke and glow
Culling grew an object's box by its unscaled stroke and effect outset,
so a view or repaint patch that showed only the outer part of a scaled
object's stroke or hardened glow skipped the object. Culling now scales
both by the object's largest scale factor, as drawing does. The CMYK
ink-pass area grows each object, and each nested child, by its stroke
and effect outset under its full transform.
2026-11-12 12:48:49 -08:00
dotCooCoo b30d39fdec Layers: Duplicate Layer maps copies by the original's anchors and tables
object::renumber now gives a story copy's anchors and tables new ids.
Duplicate Layer keys each copied anchor by the original anchor's id,
so copied cross-references point at the copied paragraph, and pairs
copied tables with the originals in order, so objects anchored in
table cells keep their live captions. A copy that renumber reports
incomplete is refused with the nested-too-deeply error.
2026-11-12 12:48:41 -08:00
dotCooCoo ba4f45e522 Merge main into feat/text-frame-options-type-tool 2026-11-12 12:45:20 -08:00
Dylan M. Taylor 213f3b75a3 Report recovery writes owned by another session 2026-11-12 15:43:43 -05:00
Dylan M. Taylor 1f2900fb50 Merge main into baseline grid justification PR 2026-11-12 15:29:33 -05:00
Dylan M. Taylor 3ebeb2ac96 Merge pull request #2669 from dotCooCoo/feat/object-style-text-frame-options
Object styles: a style sets its frames' paragraph styles and Text Frame General Options
2026-11-12 15:25:59 -05:00
Dylan M. Taylor 6790d009fe Merge pull request #2651 from dotCooCoo/fix/placed-image-resolution
Place: images come in at the resolution stored in the file
2026-11-12 15:25:55 -05:00
dotCooCoo b0c9ce00aa Merge main into fix/opaque-image-premultiply 2026-11-12 12:25:31 -08:00
dotCooCoo 113319e3e1 Merge main into fix/jpeg-screen-proxies 2026-11-12 12:25:10 -08:00
dotCooCoo e05d943d23 Merge main into fix/bottom-aligned-text-wrap 2026-11-12 12:24:22 -08:00
dotCooCoo 8121bca1fe Merge main into fix/effect-damage-bounds 2026-11-12 12:24:21 -08:00