The gate failed kept_menu_names_are_menu_labels_left_in_english: sv is in
KEEPS_MENU_NAMES, so the MENU_KEEP_AS_IS names (VectorCraft, OpenType, the
workspace names, the perspective-grid presets) must stay in English. The
coverage report had listed them as missing; the 20 rows are removed so the
names fall back to English again. The two genuinely-missing strings
(Font Size:, digits Hindi) stay.
Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
The gate failed kept_menu_names_are_menu_labels_left_in_english: ru is in
KEEPS_MENU_NAMES, so the MENU_KEEP_AS_IS names (VectorCraft, OpenType, the
workspace names, the perspective-grid presets) must stay in English. The
coverage report had listed them as missing; the 20 rows are removed so the
names fall back to English again. The 110 genuinely-missing strings stay.
Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
`gcheck` and `scheck` answered false for every operand. The PLRM (3rd
ed., `gcheck`) says they are true for a simple object, and false only
for a composite one in local VM. The eps2write prolog copies its
initial graphics state into global VM and leaves a value alone only
when `gcheck` is true. So the integers in the `currenthalftone`
dictionary took the copy path, left the stack one item off, and the
next `put` failed with a typecheck in `cp2g`.
Simple objects now answer true. Composites still answer false, since
every composite here is in local VM.
The table chain's records and entry names now have a whole-archive allowance, only the
first name of an id is decoded and kept (no clone into the entry map), and an entry's
size is charged before it is decompressed and stays charged when it fails, with the
failure remembered so a broken entry is not decompressed again.
The walk that skips objects it has already visited keys them by address
instead of id, so two objects that share an id in a damaged file are
both counted. An object reached through a selected group and again on
its own still counts once.
Found while testing crates/svg/src/export/nodes.rs:492 (Writer::node, `xlink:href` built with xml_escape)
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The power of two that brings a small map's entries up before a point is mapped is now reduced by the power of two of the point's larger coordinate, so no product of an entry and a coordinate reaches 1. A map that mapped a point before the scaling step does so again, and affine_at uses the same entries.
apply and affine_at multiply every entry by the power of two that brings the
largest to at least 1/2 when all entries are below 1/2, so products that would
be subnormal keep their precision. The identity times 5e-324 mapped (0.5, 0.5)
to (0, 0) before. Maps with an entry of 1/2 or more are unchanged.
adjugate_inverse no longer applies the relative determinant test to its result. That test is not symmetric between a map and its inverse: a map whose determinant is 1e-8 of its largest product can have a finite, accurate inverse whose own ratio is near 1e-16, so inverse() was None while is_invertible() was true. The result is now kept when every entry is finite and its determinant, summed from the six products in split form, is not 0.
The inverse holds every cofactor and the determinant as a mantissa and a
power of two, and forms each entry from their quotient. A map such as
diag(1e-300, 1e300, 1e-300), which counts as invertible, now gets its
inverse diag(1e300, 1e-300, 1e300) instead of none.
When a cofactor of a map with a normal but very small determinant underflows to 0, the
inverse formed from the map itself can have a w row of 0, so every point mapped through it
is refused. The inverse is now kept only when it is itself invertible, and is otherwise
formed from the map divided by a power of two that brings its determinant's products near 1.
The scale-free determinant test no longer builds a rescaled copy of the map. It
forms each of the six determinant products as a mantissa product and an
exponent sum and compares their sum with the largest of them, so a map such as
diag(1e307, 1e-157, 1e-157), whose rescaled copy overflows, is still invertible
and loads from a document. The rescaled copy is built only to invert a map whose
determinant is not finite or is below the normal range.
A homography means the same map at any nonzero uniform scale of its
entries, but `apply`, `is_invertible` and `inverse` compared w and the
determinant with absolute thresholds. A map stored with small entries
refused every point and could not be inverted, and a map with large
entries drew points past its horizon.
- `apply` refuses a point when w is at most 1e-9 times the largest
magnitude in the w row.
- A map counts as invertible when its determinant is more than 1e-15
times the largest of the six products the determinant sums, taken on
a copy rescaled by a power of two. An inverse whose determinant
overflows or underflows is taken on that copy.
A character style whose Up/Down or Left/Right offset lies past MAX_COORD
either way now opens with the nearer end, as text runs already do, so
text that takes the style no longer gets the out-of-range offset. An
offset within range is not rewritten.
An object with a gradient or a pattern on both its fill and its stroke
counted twice in Objects. It now counts once for each paint kind it uses.
With Selection Only, a selection that holds a group and an object inside
it walked that object twice, so the object counts, the paths' total
length and Repeat Objects counted it twice. The walk now visits each
object once.
In a Separation color space, the colorant name All marks every plate and
None marks no plate (ISO 32000-1:2008, 8.6.6.4). A spot swatch with one of
those names was written under its own name, so its paint printed on every
plate or on none.
PDF export now writes such an ink as All Spot or None Spot, numbered
All Spot 2, All Spot 3 and on when a spot swatch already has that name,
the same rule EPS export uses. The new name is used for fills and strokes,
tint shadings, DeviceN gradients, colorized images and the Lab alternates.
Registration still writes All.
A manual kerning value on an inline graphic's character was stored and
shown but did not move the text after it. The graphic's advance now
includes the value, as a letter's does, and in right-to-left horizontal
type its art moves right by the value, so the space goes between it and
the next character in reading order. Auto and Optical kerning still apply
no font pairs to an inline graphic.
Select › Same › Text Fill & Stroke Color (select.same.textFillAndStrokeColor) selects the type
objects with a run of characters whose fill and stroke both match the first character of the
first selected type. Type that matches only the fill or only the stroke, or has the fill in one
run and the stroke in another, is left out. The entry follows Text Stroke Color in the menu and
has a row in every catalog.
The Swedish catalog lacked 22 interface strings: the workspace names
(Essentials, Painting, Typography, Web, Touch), the 1P/2P/3P view
preset names and the Hindi digit-script name.
Adds them with the vocabulary the catalog already uses (Utskrift,
Teckenstorlek). After this the report lists nothing missing for sv.
Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
An id the importer writes into an element no longer matches a style sheet's
#id selector or a <use> link that no element matched before. The ids are
read from the decoded attribute values and text of the file, once.
The Russian catalog covered 6,126 of the 6,256 interface strings: the
workspace names (Essentials, Painting, Typography…), their Reset
entries, the artboard and dimension annotations, the PDF and export
preset names, the library panel sentences and several control-channel
messages still fell back to English.
Adds the 130 missing entries in the catalog's TSV format with the
Illustrator-style vocabulary the catalog already uses (монтажная
область, выносные линии, плашечные цвета, трассировка). After this the
report lists nothing missing for ru.
Co-authored-by: rahul05ranjan <11793455+rahul05ranjan@users.noreply.github.com>
An ellipse whose radius is smaller than the point tolerance at its coordinates, but at least two
f32 steps, now imports as the four-anchor ellipse instead of usvg's curves with rounded handles.
Each id made up on import starts where the last one stopped instead of at
the number of ids made so far, so a file that already holds many of the
made-up ids does not make every new id try them all again. The ids made
up are the same.
The import gives an element an id when it needs to find it again in
usvg's tree (links, symbol uses, events, data attributes, and now
circles and ellipses). A made-up id could repeat one the file already
had, such as vectorcraft-id-0, so a <use> or paint reference to that
element showed the other one. Made-up ids now skip every id in the file.
Circles and ellipses in a file whose style sheet has an [id selector get
no made-up id and keep usvg's curves, so the selector matches the same
elements as before.
The tolerance that compares the points usvg makes of a <circle> or
<ellipse> grew with the center's distance from the origin, so a circle
of radius 400 at x 40,000,000 fell back to eight anchors. The tolerance
is now a few f32 steps at the size of the coordinates, and the on-ellipse
check allows the same steps relative to the smaller radius.
usvg turns each <circle> and <ellipse> into arcs and then into a number
of cubics that depends on f32 rounding: an ellipse that export wrote as
<ellipse> could come back with eight anchors instead of the four it was
written from. The renderer flattens the two outlines differently, so a
round trip of a flat filled ellipse redrew 158 edge pixels by up to 43
levels, and prop_svg::plain_art_survives_visually failed on main.
Import now records the ids of <circle> and <ellipse> elements in the
prepass and rebuilds each as the ellipse VectorCraft draws: four smooth
anchors on the axes, starting at the right as SVG defines, with handles
KAPPA of the radii long, then transformed as before.
Tests: prop_svg::filled_ellipse_on_the_artboard_edge_survives_visually
(the failing case) and basic_shapes::circles_and_ellipses_import_as_the_ellipse_drawn
fail without the change.
With Envelope Options > Distort Appearance on, a path whose Transform
effect has Scale Strokes & Effects or Transform Patterns on, or copies it
with a gradient, was baked with the effect as geometry only: every copy
kept the original's stroke weight, dashes and pattern placement before
the envelope bent it. bake_appearance now makes such a path into the
per-copy art that drawing, export and Expand Appearance already use, and
bakes each copy's strokes into filled outlines from there.
The menu bar takes ⌘V's key-down as Edit › Paste's key equivalent, and
`native_menu::key_events` turns it back into egui input. With text on the
clipboard that was a Paste event; with only a picture (a screenshot) it
was nothing, leaving the paste to the window's own key-up. egui's window
integration only releases a key whose press it saw, so that release never
came and ⌘V pasted nothing, while Edit › Paste and ⌘V with the menu open
worked.
`key_events` now ends ⌘V with the key's release, as it already did for
⌘X and ⌘C: without a Paste event that release is the picture paste
`PasteChord` looks for, and after one it ends that paste so the next
picture paste still fires.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The geometry effects after a fill's or stroke's own Transform effect with
Scale Strokes & Effects or Transform Patterns now take the bounds of the
transformed path and all its copies as their reference box, as an
object's own effects do. A later Rotate turns the copies about their
combined center instead of turning each copy about its own, and a later
Offset Path or plain Transform applies to the paths themselves. Each copy
keeps its own scaled distances.
Part of #885
transform_item_leaf now holds back the leaf's geometry for each plain or transformed piece that follows a transformed fill or stroke, so the copies of an earlier item no longer use up the budget that a later fill or stroke still needs. The nested pass over a transformed piece keeps to the same reduced limit.