livePaint.strokeEdge wrote the paint and weight into an edge's topmost
stroke even when that stroke was hidden. An edge whose hidden top stroke
sat over a drawn one kept drawing its old paint, and since the edge
scopes now match the paint an edge draws, a samePaint or connected
stroke reached such edges and changed nothing on screen. The command now
paints the topmost stroke that is shown, and adds a stroke above the
others when every stroke is hidden or there is none. The "nothing
changes" check reads the same stroke.
The doc comments of the scopes and of the press record describe the
drawn stroke paint, and the engine names Paint through its parent module
instead of in the import list. Live Paint Selection's comment on a
triple-click states that the tool takes no action on it.
New tests cover the edge the tool matches on a multi-click over a hidden
or fully transparent edge, the connected edge scope through transparent
and hidden edges, and painting the shown stroke.
When Gap Options cut an edge in two, each piece took the old edge's
stroke rows unchanged: both arrowheads, the dash phase of the edge's
start, and a brush or width profile spread over the whole edge. Each
piece now takes those rows fitted to its part of the old edge, as Make
fits a source path's rows to the edges cut from it.
File › Open's Import PDF dialog gets Import PDF pages as links. With it on,
each page picked opens as a placed document linked to that page of the
file, on an artboard of its Crop To box and a layer named after the page,
in place of editable art. The Links panel lists each page, and Embed makes
a page editable.
document.open takes the matching linkPages param. It is refused for a
file that is not a PDF or a PDF-compatible .ai, for bytes without a path,
with a password and with textAs: outlines. The pages share one copy of
the file, and the document opens in CMYK when most of its pages do.
Save asks for a name, as for other partly read PDFs.
Perspective Grid Options gets the two Automatic Plane Positioning
checkboxes, Anchor Point of Perspective Artwork and Intersection of
Gridlines. With the Perspective Selection tool, Shift held over an
anchor point of art in perspective, or over a gridline intersection,
with no button down, moves the active plane through that point and
hides the other planes. A plane made active then passes through the
same point. The plane goes back to its place once an object is drawn
on it or attached to it, when the grid hides or no plane is active,
when the file is opened again, and with Escape.
- perspective.plane.infer {at?, tolerance?, clear?} positions, reads
and clears the held point, which is view state, not an undo step.
- perspective.widget.options takes anchorPoint and gridlineIntersection,
both on by default and kept with the preferences.
- perspective.plane.move moves a held plane from where it is held.
The PDF/X-1a case of tagged_tiffs_keep_their_icc_profile also exports a
16-bit gray TIFF with a gray profile, kept as it is, resampled and
compressed with JPEG, and checks each written file with the PDF/X-1a
check as well as its image color space.
A CMYK TIFF with two or more samples past its inks and its ExtraSamples
values, or with no ExtraSamples tag, which the decoder gives no color
type, now opens opaque when none of those values names an alpha. It
failed to open before; one that names an alpha already read with it.
The four panel tests that export into a folder made it under the system
temporary folder and removed it at the end, so a failing assertion left
the files behind. They now use vectorcraft_testkit::TempDir, which
removes the folder when the test ends or panics.
The 64-sample limit is now checked against the file's SamplesPerPixel
before anything is decoded. It was checked against the samples the
decoder gives, which is five for any CMYK file whose first ExtraSamples
value is alpha, so a small file with 65,535 samples a pixel was read and
the decoder took a row of every sample (1 GiB for a 16-bit file 8,192
pixels wide) before reading its data.
- The row the decoder reads each strip or tile into, when the file has
more samples a pixel than it gives, counts in the allowance.
- Files whose samples aren't unsigned integers are refused from their
tags; no reader takes them.
- The same checks run before CMYK inks and plates are decoded.
- The copy that puts a planar file's samples pixel by pixel is allocated
once, at its length, so the reader holds no more than it counts.
The Links panel menu gets Sort by Size beside Sort by Name, Kind and
Status, and links.list takes sort: "size". A row's size is the file size
Link Info shows: the file's size now, else the size the document keeps
of it. Rows without a size (embedded images, a missing file whose size
is not kept) come last, and equal sizes go by name. The size is read
only when sorting by it, and under automation read roots a file outside
them is not read.
Every catalog with Sort by Status gets a Sort by Size row; the Ukrainian
Sort by Status row, which read "Sort by:", now says "Sort by Status".
The tagged TIFF test now compares the decoded image data with the source
for a 16-bit RGB TIFF whose high and low sample bytes differ: big-endian
16-bit samples at PDF 1.7, and the samples reduced to 8 bits at PDF 1.4.
A byte-swapped or truncated stream no longer passes.
A closed key that winds the other way is reversed keeping its start anchor.
Its dash offset was computed as if the reversed path ran back from position
0 instead of from the end of the subpath, so the dashes shifted by the
subpath length modulo the pattern period. The offset now uses the full
length in that case, and the dash test covers a closed key 40 long with a
7.5 period.
The WebP chunk walk added the chunk length to the offset without a
checked add, so a length near u32::MAX overflowed on 32-bit targets
(wasm32) with overflow checks on. It now reads the chunk through the
same checked slice helper as the PNG, JPEG and TIFF readers.
Create Sub-folders and Open Location after Export are check items that set
the settings the panel shares with Export for Screens, and the panel's
Export follows them. Create Sub-folders is checked as the dialog opens on
it: on for a document without export settings, and on for remembered
folders per row, format or item, which the panel's Export now uses too.
Format Settings... opens Export for Screens on the Assets tab showing the
first row's format settings.
assets.settings.set takes openLocation (kept in document.exportSettings,
not in presets), refuses a subfolders or openLocation value that is not
true, false or null, and with subfolders false given alone also ends a
remembered folder per format or item. Export for Screens reads remembered
empty folders as none, as an export does.
This reverts commit bada8e1710. #7638 merged with its gate failing: besides six unformatted
files, render and trace don't compile against craft-libs e2dc681 (u64::from(usize) in
render/src/paint.rs, a private craft-libs function, and a call with one argument too many in
trace/src/opaque.rs), so main's CI fails. The tree is that of 0adbdce6cb, whose CI passed.
The Live Paint Bucket's connected and samePaint scopes kept their own
copies of the face flood and the edge walk. They read an edge's stored
stroke paint, so an edge that is fully transparent or whose stroke is
hidden stopped a face flood and matched as stroked. The face flood also
required outlines within 0.0001 pt of an edge, which a curved face that
the planar map refits can miss.
The engine now calls the shared flood_faces and connected_edges that
Live Paint Selection uses (#7342), and compares edges by lp_stroke_paint,
the paint of the topmost stroke that draws. The tool records that same
paint as the match for a double-click or triple-click on an edge. The
params text and docs/mcp.md describe the drawn stroke paint.
The depth check and the prepass read each element's declarations through
a cascade that keeps a copy of them per element, so one 100 kB style
sheet rule on 16,000 groups still took 1.5 GB before the SVG was refused.
The SVG and each SVG image it shows are now measured before that cascade
runs. Copies nested past the depth cap, and loops of <use> references,
are found as too deep: an SVG is refused with the depth error, and an SVG
image is left out with the depth warning, as before.
Effect › SVG Filters and Apply SVG Filter list 14 default filters in
every document, before the document's own. The set, the names and the
values are VectorCraft's own, written with SVG 1.1 filter primitives
(crates/effects/src/svg_filter/defaults.rs).
A document holds none of the defaults until one is applied or edited
there. svgFilter.apply with a default's name copies it into the document
in the same undo step, and svgFilter.define with replace naming a default
adds the edited copy under that name. The copy is listed in the default's
place. svgFilter.delete refuses a default the document holds no copy of,
and deleting the copy lists the default again.
svgFilter.list also returns the defaults. svgFilter.apply takes index and
item to put the filter in the place of an applied SVG filter, which the
dialog's OK uses when it is opened for an applied effect; an index that
is not an applied SVG filter, null included, is an error.
A visible, unlocked Live Paint face or edge whose own opacity is 0 draws
nothing, as Expand and the edge stroke check already treat it, but the
Shape Builder still took it as an input. It now leaves such faces and
edges out; hidden and locked parts keep their current handling.
Type > Smart Punctuation... now opens its own dialog in place of the
generic parameter form. It has the seven replacement options, Replace In
(Selected Text Only or Entire Document) and Report Results, which lists
how many of each chosen replacement were made after OK. The dialog opens
on the options confirmed last.
- type.smartPunctuation takes fiLigatures, flLigatures, spaces and
fractions, all off by default, so existing calls behave as before.
- Ligatures write U+FB00 to U+FB04, longest match first. Expert
Fractions writes the one-character fractions Unicode encodes, and
skips one with a digit, a slash or a decimal point next to it, across
a change of style too. Either is written only where the run's font
has a glyph for it.
- Smart Spaces keeps one space after a period, across runs. An inline
graphic separates the text on either side of it.
- The reply adds a replaced object with a count per kind. Nothing to
replace still records no undo step.
Docs: docs/mcp.md, docs/type-parity.md.
When a Type 2 CIDFont or a Type 42 descendant of a composite font has no FontMatrix, the
font a cshow procedure sees as current now takes the identity as its default, as glyph
measuring and drawing do, instead of the 1/1000 default of other fonts.
A CMYK or grayscale TIFF with extra samples is now read only when its
decoded samples, the copy that puts a planar file's samples pixel by
pixel and the RGBA pixels together fit the decoding allowance; the
check counted the decoded samples alone, so a small compressed file
could make the reader hold about twice the allowance plus the RGBA
image.
- The decoder may decode no more than the counted samples, and reads no
strip or tile of more compressed bytes than the file holds.
- A pixel of more than 64 samples is not read (VectorCraft's own limit).
Where a tabbed line with glyphs stepping back stops reading at its break limit on a soft
hyphen that ends the text, it now ends there without a hyphen, as a line that reads to the
end of the text does.
The PDF/X-1a case of tagged_tiffs_keep_their_icc_profile also exports a
gray JPEG with a gray profile, kept as it is, resampled and compressed
with JPEG, and checks that it is written in DeviceGray without the
profile. The comments on decoded_image, recode and the test say that
PDF/X-1a allows no ICC-based color spaces.
main's Live Paint Selection double-click (#7342) replaced the tool's
catch-all pointer arm with an explicit DoubleClick arm, so the
TripleClick kind this branch adds left the match non-exhaustive. The
tool now takes no action on TripleClick: the third click's press and
release already select what a click selects, as before the merge.
The merge also took main's import list in the engine's Live Paint
commands, which no longer named Paint while this branch's Merge code
still uses it; Paint is imported again.
usvg copies the element a <use> shows, and every copy gets its own copy of
the declarations its style attribute and matching style sheet rules give
it. A chain of <use>s that doubles at each level made usvg build those
copies before the import's object limit was checked: a 101 kB file whose
rectangle has a 100 kB style took 4.7 GB at 14 levels, and one 100 kB
style sheet rule on 16,000 groups took 1.5 GB without any <use>. A plain
chain stopped at usvg's own 1,000,000-node limit with a parse error.
The import now measures, before usvg reads the SVG, how many elements it
expands to and how many bytes of style values those elements copy, each
element measured once and each <use> counted as one addition. References
follow usvg's rules: first element of an id, href before xlink:href, and
the self and back references usvg leaves out. An SVG past 999,999
elements (500,000 on the web) is refused as too large, a loop of <use>
references usvg would copy without end is refused too, and one past 64 MB
of copied style values is refused with the new SvgError::StylesTooLarge.
SVG images count toward the same 64 MB as the SVG showing them, an image
past either limit refuses the whole import, and an image that doesn't
decode does not count.
Measuring an instance of a symbol with 9-slice guides looked its map up
through Document::symbol_slice_map, which scanned the symbol list and
measured the art box again in new quick boxes, and NineSliceMap::place
and most_placed made new quick boxes of their own. Each of those boxes
built the symbol name index over the whole list on its first lookup, so
every 9-slice instance measured read every symbol once or more. Picking
an object inside a 9-slice instance's art with Direct Selection did the
same for each object of the art that holds a symbol instance.
- SymbolBoxes cuts the guides through the art box it has measured
(SymbolBoxes::slice_map), and places and counts the art with itself as
the boxes, in the mode quick boxes use. Art with no 9-slice map is
moved by the instance's transform without looking the map up again.
- Document::symbol_slice_map, place_symbol_art,
place_symbol_art_unclipped and edited_nine_slice use one set of quick
boxes for each call.
- symbol_part_at and symbol_part_outline keep one set of quick boxes
for the instance's art.
The new tests count the symbols read. Measuring 200 instances of a
symbol with guides and 200 of a symbol with guides holding it, among
2,002 symbols, read 1,205,204 symbols before; now each set of boxes
reads the list once. Picking in a 9-slice instance whose art holds 20
instances read 84,042 symbols among 2,001; now it reads the list at
most twice.