untranslated_report lists 167 status and error messages that no
complete-message catalog translates. zh-hans.tsv gains 114 @msg rows for
the ones no open pull request covers: 3D and Revolve limits, image export
and encoding errors, color profiles, color books and swatch exchange
files, binary DXF and DWG import, path operations, swatch, graphic style
and action set libraries, and zip, script and regular expression errors.
Placeholders, backticked names, command ids and listed values stay as the
English writes them.
The other 53 (composite fonts, SVG filters, read roots and graph design)
are left to #7211, #7378 and #7405. docs/localization-parity.md and
docs/target-app-parity.md give the new counts: 3,554 @msg rows, and 55
messages the report lists for zh-hans, all of them translated by open
pull requests.
A graph keeps paints for its series and labels, and character and
paragraph style names for its labels, which each redraw gives the
marks and labels. Copy did not follow them, so a graph pasted into
another document left those swatches and styles behind, and a paste
that renamed them left the graph pointing at the old names.
Copy now collects them and paste relinks them, as it does for type.
Paste without Formatting drops the labels' style names, so it still
leaves text styles behind.
The Danish catalog had 1,033 `@msg` rows and 47 `@msgplural` rows, and
Danish was not in COMPLETE_MESSAGES, so with the interface in Danish
script errors, plug-in manifest and permission errors, parameter
schema errors, 3D effect refusals, file-reader errors and data-set
messages showed in English.
- da.tsv gains the 602 `@msg` rows and the one `@msgplural` row that
the German, Czech, Spanish and French catalogs have and Danish
lacked. The `@msg` rows are one block with a header comment on
their conventions. Backticked names, command ids, double-quoted
values and bare true, false and null stay as the English writes
them.
- da joins COMPLETE_MESSAGES, so the message tests that iterate the
list check Danish too, and the untranslated report lists Danish's
missing messages. It lists the same set for Danish as for Czech,
Spanish and French.
- The registry comment, docs/development.md, the Danish row and
introduction of docs/localization-parity.md, and the interface
languages line of docs/target-app-parity.md list Danish among the
languages that translate messages.
The comment on the zigzag cases said the open zigzag grown by 1.5 leaves
stroker loops whose faces the distance test drops. With the turned branch's
distance test measuring points in the turned frame, or dropping no face at
all, the three zigzag cases still pass and only the plate case fails (201
contours instead of 101). The comment now says what the zigzag cases check:
one turn for the low path, none for the path stood on end, and the same
region from both. The plate comment says its narrow holes are dropped by
the distance test measured at points turned back into the plate's frame.
A drag of art across the document tabs ended whenever the source
document's revision changed. Since #7173, bringing a document with other
assigned color profiles to the front raises every open document's
revision so that each redraws in the new profiles, so holding art over
such a tab switched to it and then canceled the drag before the drop.
The drag now keeps the source document it left and ends only when that
document's content changes (DocState::same_content). A redraw keeps it,
and so does type measured again when the source comes back to the
front, which replaces the document without editing it.
A raster effect (Drop Shadow, Outer Glow, Gaussian Blur and the other
effects that paint pixels) on a symbol instance's topmost fill now draws
on each filled shape of the symbol's art, and one on its topmost stroke
draws on each stroked shape, after any geometry effects listed before
it. The same rules as for geometry effects apply: only a visible fill or
stroke with an opacity above 0 counts, a group's own fills and strokes
in the art take the effect, and an instance inside the art passes it on.
The canvas, Use Preview Bounds and the drawn bounds, SVG and PDF export
draw it, and Object > Expand Appearance is enabled for such an instance:
a shadow or glow becomes an image under the instance, and a blur,
feather or inner glow replaces it with the image, in one undo step.
Existing documents with a raster effect on a symbol instance's fill or
stroke draw differently: before, the effect drew nothing.
Character panel > Tsume, shown with Show East Asian Options, takes away a
percentage of the blank space on each side of a character's ink, inside
its own width, in horizontal type. The value is from 0 to 100, 0 by
default. 50 halves that space and 100 sets the ink against the
characters before and after it; the glyph keeps its shape. A character
without ink, such as a space, keeps its width, and a ligature or a
letter with its marks takes the value of its first character. The
font's pair kerning, tracking, manual kerning and Insert Aki are added
after it, and justification keeps it. Vertical type keeps its spacing.
- text.setFormat and text.setRangeStyle take `tsume`; a value that is
not a number or is outside 0 to 100 is refused, naming the key.
Character styles carry it, and a file holding a value outside the
range opens with the nearer end.
- The Character panel's Tsume field has 0, 25, 50, 75 and 100 in its
menu, and Reset Panel sets it to 0. Character Style Options shows it
in Advanced Character Formats.
- Live SVG text places each character Tsume moves, and type on a path
with Tsume is written as outlines.
Docs: docs/mcp.md (Tsume, Character Style Options fields),
docs/target-app-parity.md.
The centre-lines class gains a mixed-width body scene: one disc of radius
24 px with arms of 2, 3 and 5 px that start inside it, Stroke 6 px, and no
other ink. A test checks that the scene is one connected shape and that
both the anti-aliased and hard input trace as one fill and three strokes
that reach all three free ends.
docs/image-trace-quality.md's centre-lines section is measured again on
current main (24 scenes, two runs identical in every column but ms). The
new scene finds 100.0% of its arms with 99.3% / 98.3% of the disc filled;
mix now traces as 6+3 paths with 99.9% / 99.8% found and 7/7 ends, where
the earlier whole-blob rows showed 3+1, 57.3% and 6/7. All other rows
are unchanged except ms.
With Shadows on, Extrude & Bevel, Inflate, Rotate and Revolve built
every solid twice: once for the art and again for the shadow. The build
that draws a solid now also keeps the faces its shadow is cast from and
the projection they were built with, and the shadow is cast from them.
The art and the shadow are unchanged.
- three-d: the solid builder can keep the projected facets and the
view-space faces together (`Keep::Both`); `extrude_shadowed`,
`plane_shadowed`, `inflate_shadowed` and `revolve_shadowed` return
both, and `ShadowCaster::add_solid` adds the kept faces. Revolve's
sweep draws the surface and keeps the shadow's faces in one pass; a
shadow past its limits still gives the same error while the surface
draws.
- effects: the solids drawn hand their faces to the shadow. A stroke's
solid left out of the art is still built for the shadow alone, as
before.
Tests compare each solid and its shadow with the two built apart, to
the bit, and count the solids built for a shadowed object.
A paragraph whose characters differ in line metrics, in area type that is
not a rectangle or that wraps around an object, was broken line by line
with the Single-line Composer when the frame could not hold all of it.
The lines the frame holds are now composed with the whole paragraph: a
line the frame has no room for, and every line after it, is measured as
wide as the span of the last line set in the frame, less its indents.
Those lines overflow, or go on in the next threaded frame, which composes
them again at its own widths. A paragraph whose first line has no room,
and a search that passes its limits, still fall back to Single-line.
Docs: docs/mcp.md, docs/target-app-parity.md.
untranslated_report lists 167 messages under "messages, all 23 languages
checked". ru.tsv gains an @msg row for 114 of them, in one block at the end
of the file: image export and encoding errors, color profiles, color books
and swatch exchange files, binary DXF and DWG import, 3D and Revolve limits,
and script, zip, line and file errors. Placeholders, parameter names and
literal values stay as the English writes them.
The other 53 are left to the open pull requests that translate them
(composite fonts, SVG filters, read roots and graph design).
document.exportSelection run with no params or {} (a shortcut, or an
automation call) wrote the picked file straight away with each format's
defaults: a PDF used the default preset, so Save PDF's options, such as
writing long pages in points, could not be chosen. It now takes Export
As's route after the save panel: Save PDF without its Artboards
section, SVG Options without its artboards, the raster options, EPS
Options, DXF Options, Text Export Options with Selection Only on, or an
exporter plug-in's parameters. OK writes the selection alone, cropped
to it, with the chosen options. While a dialog is open the call returns
null, and OK returns what file.exportAs returns, without format or
bounds.
With a path or any option it still writes straight away.
- file.exportAs takes exportSelection: true and then writes the
document that document.exportSelection writes
(fileio::selection_doc), without artboard choices. The options
dialogs and the replace-file questions pass it on.
- Nothing selected stops before the save panel.
- SVG Options opened by Export Selection leaves the remembered Use
Artboards as it was.
- Exports through file.exportAs (Export As and the options dialogs)
apply Appearance of Black's rich black, as document.export does.
Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md.
Opening an .ai file now reads Insert Aki Left and Right from its text
document through the same cascade as the other character keys: the run,
its character style and the styles that one is based on, [Normal
Character Style], then the document's defaults. The values are read in
thousandths of an em. A negative value or one that is not a number opens
as 0, and a value past 1000 opens as 1000. How the text document stores
these values is VectorCraft's own rule.
An .ai save writes each run's nonzero values in the form that reader
reads, and no longer reports Insert Aki as left out of the editing data.
A legacy .ai text object has no Insert Aki: type with it that is written
as text now reports that the setting is left out. Type written as
outlines keeps the space.
A radial gradient whose color line runs past 0 or 1 can get a circle
with a negative radius once its stops are normalized to 0..1. Circles of
a negative radius are not drawn: only the side of the circle of radius 0
(the tip of the cone) where the radius is positive is painted
(https://learn.microsoft.com/en-us/typography/opentype/spec/colr, Radial
gradients). Before:
- As vector art, a padded gradient with a stop before 0 and its centers
apart was focused on the start circle's center instead of the tip, and
one with its centers together got stop offsets below 0.
- Drawn into an image (a glyph with a sweep gradient, a Porter-Duff
composite or a repeating gradient), any such gradient filled the glyph
with its first stop's color.
Both now recast the circles so neither radius is negative. With pad, the
stops on the side that is not drawn become one stop at the tip with the
color there; stops at the tip stay, so a sharp change of color there
keeps the color on the drawn side. With repeat and reflect, the circles
move by whole periods of the color line to the drawn side. When no
circle is drawn, nothing is painted.
The untranslated report listed 167 status and error messages that none
of the 23 complete-message catalogs translates. The Ukrainian catalog
now has an @msg row for 114 of them: the errors of the image encoders,
color profiles, swatch exchange files and color books, 3D and Revolve,
path operations, DXF import, the script engine and the parameter
checks. Placeholders, backticked names, accepted values and limits stay
as the English writes them. Open #7211, #7378 and #7405 translate the
other 53.
A gradient stop that loses its link to a spot swatch kept the process
plates it printed with that ink, so it carried a DeviceN mix with no
ink. Paint::map_links, which deleting a swatch, recoloring and color
adjustments go through, now clears a stop's plates whenever it leaves
the stop without a link, as GradientStop::set_color(color, None)
already does. Library gradients and library character styles linked
to a swatch the document lacks unlink their stops the same way.
Docs: docs/target-app-parity.md.
A clipping path inside art cut to another clipping object is written as
its fills and its strokes. Its text wrap options went with the fills, so
when the outer region left nothing of the fills, the strokes were written
without them. The strokes now keep them unless a fill object was written.
A symbol definition that had no room left for its group under the object
limit returned without restoring the writer's drawn-art depth. Asked for
from art drawn for an object (a stained instance's art), the depth then
dropped below zero on the way out, which panics in debug builds. That
path now restores it as the others do.
The untranslated report listed 167 status and error messages that no
complete-message catalog translated. pt-br.tsv now has an @msg row for
the 114 of them that no open pull request already translates: messages
of the 3D and Revolve effects, the image encoders, color profiles, swatch
exchange files, color books and DXF import. Placeholders, parameter names
and literal values stay as the English writes them.
The other 53 (composite font, SVG filter, read root and graph design
messages) are translated by open #7211, #7378 and #7405; adding them here
too would make bundled_catalogs_are_consistent fail on a duplicate row
once those merge.
With Smart Guides on, the Dimension tool's second point snapped onto the
construction guides through the first point (Smart Guides › Construction
Guides), so a click beside a segment straight below a first point that
was not on an anchor stayed on the vertical guide instead of landing on
the segment.
The second point now has no construction guides through a first point
that is not on an anchor. After a first point picked on an anchor, the
construction guides through it still apply. The second point still snaps
to anchors, centers and alignment lines, and with Snap to Perpendicular
or Snap to Tangent on it lands where the line from the first point meets
a segment square or grazes a curve.
Docs: docs/dimensions.md, docs/target-app-parity.md.
The continuous-tone check exempts a neutral or single-curve picture when
sixteen colors leave at most a fifth of the error of eight, but only
applied the exemption below the 0.1 ratio. Clean gray, sepia, single-hue
and duotone art of 10 to 16 evenly spaced levels lands above it, so it
was smoothed before tracing. The exemption now applies in both branches.
At 16 Colors, 12 sepia and 16 gray or sepia levels crossed by 1 px lines
keep every region the lines cut, and Automatic traces 16 clean sepia
levels in 9 colors instead of 4. Art in several unrelated colors is
unaffected.
Two faults in the editing data writer's text wrap handling:
- A clipping path inside art cut to an outer clipping object is written
as its fill and its stroke. The stroke's text wrap options were
dropped whenever the path had a fill, so when the outer object cut
the fill away entirely, the stroke was written without them and the
options were lost. The stroke now drops them only after the fill
writes an object.
- When a symbol definition had no room left under the object limit,
`define_symbol` returned without restoring the drawn-art counter it
had cleared. A live instance inside drawn art (a stained instance's
art) then left the counter at zero, and the art around it subtracted
from zero: a panic in a debug build. That path now restores the
counter as the other exits do.
The preset paragraphs say that the enhanced versions use the same Paths,
Corners and Noise, and that Corners 50 applies to the other eight
presets. The quality notes add the staircase and anchor rises in Line
Art, Outline, 3 Colors, Sketched Art and Silhouettes, and say which
figures were measured at the earlier values. The anchor-limit comments
name the same settings in both places.
path.setHandle checked for a no-op by running the handle edit on a copy
and comparing the whole anchor. On a smooth anchor the edit recomputes
the other handle, so when that handle was not exactly in line, or the
recomputed value rounded differently, a request for the handle's own
point realigned the other handle and recorded an undo step.
The check now compares the requested point with the handle itself, and
still lets independent turn a smooth anchor into a corner.
A clipping path with Roughen, Transform or another effect that reshapes
a path drew its own fill and stroke reshaped, but the canvas and raster
export still clipped the art by the plain path. SVG and PDF export bake
the effect into the path before writing the clip path, so the screen
and a saved SVG showed different art.
effects::clip_outline now applies the live geometry effects in the
clipping path before taking its region: the path's or compound path's
own effects, the effects of its fills and strokes (the region is then
the union of the paths they give, as an export bakes them), the effects
of a compound path's paths, of a group's visible members and of a
nested clip group's clipping path, shown or hidden, and a group's own
effects as an export evaluates them. Raster effects such as Gaussian
Blur leave the region as it is. The renderer, the engine commands that
measure a clip region (flatten, arrowheads, cutting) and the writers use
it; the writers receive the baked document, so their output for a path
with effects does not change.
The renderer measures a clip group by the region its clipping path's
effects give it, so a view or tile that shows only the moved part of
the clip still draws the clipped art, and it drops cached clip regions
that hold a plug-in effect when plug-ins change.
Two rules change in every export as well as on the canvas:
- When the clip group, or a group around it, has a geometry effect of
its own, the clipping path's effects apply first and its gradients
move with them. #7114 left the clipping path's effects live under the
group's effect, so they applied after it.
- Type used as a clipping path keeps its own effects when a group's
effect outlines it. #2073 and #2290 outlined it without them, to
match the plain clip the canvas drew.
At a Volume of 0 % no shape puffs, so the eye does not depend on the
other shapes. Each shape's membrane is now solved as its solid is taken,
and a caller that stops at the object's face limit solves none of the
shapes after it. With any volume every puff is still solved first, since
the highest one places the eye, and the solids are unchanged bit for bit.
The shadow no longer builds the solid of a fully transparent fill or
stroke: its puff still places the eye, and at 0 % volume it is not
solved either.
When a recovery copy fails because a folder on the way to the recovery
folder is a file or is missing, the error names that folder, not the
recovery folder. Replies to a client confined to read roots hid only
the recovery folder itself, so the full path of that ancestor stayed
visible. A reply now also hides each ancestor of a recovery folder that
it writes as a whole path. The check compares text only and does not
look anything up on disk.
Follows #7287.
With apply "opacity", Sort Objects compared each object's opacity with the
value it gets as a percentage, within 1e-6. An evenly stepped value can
differ from a mark's percentage by more than that while it rounds to the
same stored opacity: marks at 30%, 65% and 100% sorted by x with
distribute on keep their opacities, yet the 65% mark counted as changed.
The sort then made an undo step and replaced the opacity the graph stores
for the series (30%) with 65%.
The sort now compares each object's stored opacity with the opacity it is
given, as stored, both to skip a run that changes nothing and to pick the
marks whose opacity the graph keeps.
When a blend starts a key's path at another anchor or runs it the other
way, the steps already read that key's width profile and pen recordings
along the turned path. Its stroke gradient and dashes still followed the
key's own direction, so steps near that key showed them flipped or
shifted.
- A gradient along the path starts where the turned path starts and
runs backwards on a reversed one; a gradient across the path swaps
sides on a reversed one. Stops that reflect an even number of times
are left as they are.
- Dashes run backwards on a reversed path, and exact dashes start where
the turned path starts, when every subpath needs the same offset.
- Two gradients with different stop counts keep a step (two stops at
one offset) when they are resampled to common stops.
In a composite font the file carries (FMapType 2 or a CMap), cshow ran
its procedure once for each byte of the string, with that byte's width
in the composite font and the composite font still current. It now runs
once for each character the font maps, with the last byte of its code
and its width, and with the descendant that draws it current, at the
size the composite font sets it, while rootfont gives the composite
font (PLRM 3rd ed., cshow and rootfont).
While the procedure runs, showing the byte it was given in that
descendant shows the character the code maps to: a CMap's CID,
base-font code or glyph name. In a CIDFont any other string is a
rangecheck error.
On main, the untranslated report lists 167 status and error messages
under "messages, all 23 languages checked": no complete-message catalog
has a row for them, so the Japanese interface shows them in English.
- ja.tsv gains 114 @msg rows for the listed messages: image export and
encoding errors, color profiles, color books and swatch exchange
files, binary DXF and DWG import, 3D and Revolve limits, and script,
zip, line and file errors. The 53 listed messages that #7211, #7378
and #7405 translate are left out.
- It gains 10 @msg rows for messages other catalogs translate and
Japanese lacked: the Banner Hems and Grommets errors, a parameter
range and the failed recovery save. The three script and RTF parsing
errors that #7314 adds are left out.
Placeholders, parameter names, command ids and literal values stay as
the English writes them, and the rows follow the catalog's Japanese
message conventions.
Two intervals at the middle of a band joined whenever their crossings
came out at the same x, even when the two edges are not along one line
and only round to that x. A slanted edge whose crossings of the band all
round to the x of a separate contour's edge then let a line run across
the gap between the contours.
The crossings now carry the line they were found along. Intervals join
at an x only when both crossings are along one line (contours that meet
along an edge) or both lie exactly at that x.
After Select All in a frame of threaded text, Convert to Text skipped
the story's locked and hidden frames, even when `ids` named them, and
left a paragraph whose text started in one as a list. Remove Line
Breaks and Remove Paragraph Breaks also kept the breaks in those frames.
A selected story is one text, as it already is for Apply Bullets and
Apply Numbers and the Character and Paragraph panels, so both commands
now change every frame of the story, as one undo step.
- text.convertListToText converts every list paragraph of the story,
locked and hidden frames included; `ids` naming a locked or hidden
frame converts its paragraphs too. A call that changes nothing adds
no undo step.
- addon.cleanup.removeBreaks removes the breaks in every frame of the
selected story.
Docs: docs/mcp.md, docs/target-app-parity.md.
The script module docs, the script.run params text and the evidence line now
say that $.fileName in code that eval or Function compiled gives the file
being run, and the params text says that the empty name applies to code
compiled from a script given as text.
Two windows or processes using one Plug-ins folder could interleave their
writes: an install from one could leave its module with the other's grant,
a grant written for one plug-in could drop one written for another, and
plug-in settings and cache changes could lose each other's keys or pass the
cache caps together.
Each change to the folder now runs in one turn on disabled.lock, the file
the disabled list was already locked with:
- plugin.install takes the turn before it reads the stored grants and holds
it through the module, grant, put-back and disabled-list writes;
plugin.remove holds it through grant removal and storage deletion.
- Grant writes, the disabled list, loading the folder, and the plug-ins'
settings and cache changes read and write in a turn.
- When disabled.lock can't be locked, plugin.install and plugin.remove fail
and change nothing, plugin.setEnabled keeps its change in the process, and
loading the folder writes nothing to it.
Docs: docs/plugins.md, docs/mcp.md, the plugin.install and plugin.remove
params text, docs/target-app-parity.md.
The For you and Skills tab buttons, a skill's row, a tutorial's row and
Back changed the Learn panel's view directly, so the control channel and
MCP could not choose a tab, open a skill's tutorials or go back.
- learn.tab {tab: forYou|skills} shows the panel on that tab; the Skills
tab keeps the skill and tutorial it had open.
- learn.skill {skill} shows the panel on the Skills tab with that skill's
tutorials and returns the skill as learn.list lists it.
- learn.back {} goes up one level, as Back does.
- A tutorial's row runs learn.show.
- The commands are listed in both UI command catalogs, and their labels
have a row in every catalog.
- Docs: docs/mcp.md, docs/target-app-parity.md, docs/ui-parity.md.
Reverse Path Direction reversed the anchors but left the stroke's width
profile, pressure, tilt, bearing and rotation running the old way, so a
tapered or pressure-drawn stroke changed shape. They now turn with the
path through the blend code's stroke reorientation (the width profile's
sides swap), and the stroke draws as before. A path whose subpaths do
not all turn alike keeps its stroke as it was, as blends do. Arrowheads
stay at the path's start and end.