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 horizon test compares a point's signed w with the largest absolute
value in the bottom row, and the invertibility test compares the
absolute value of the determinant with the largest absolute value among
its six products, so a negative determinant counts as invertible. A
stored projection that overflows is divided by the largest absolute
value in its bottom row.
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.