af414b6aed
The user's first post-migration screenshot showed near-invisible suit glyphs on every card — the rank rendered at correct size but the ♠ ♥ ♦ ♣ marks were tiny dots regardless of the requested 20px / 64px font-size. Root cause: the bundled FiraMono in svg_loader::shared_fontdb doesn't carry usable Unicode suit glyphs (U+2660-2666). usvg silently fell back to a substitute rendering at default size, producing the "tofu" effect. Fixes by replacing the `<text>` glyph rendering with inline SVG paths. `suit_path_d(suit)` returns a single closed-perimeter path authored in a 32 × 32 logical box, then face_svg wraps it in two `<g transform>` blocks (top-left small + bottom-right rotated large). Path-based rendering bypasses the font system entirely — same bytes on every machine, no fontdb dependency, no substitution risk. Same path data renders correctly whether filled (♥ ♠) or outlined (♦ ♣ — the always-on color-blind glyph differentiation from the design system). Knock-on changes that must land in this commit per the migration plan's lockstep rule: - `EXPECTED` in tests/card_face_svg_pin.rs rebaselined: 52 face hashes change (text → path), 5 back hashes unchanged (back_svg untouched). The bootstrap pattern in the test handled the rebaseline cleanly — empty EXPECTED, re-run, paste, re-run. - assets/cards/faces/*.png regenerated (the 52 face PNGs). - solitaire_engine/assets/themes/default/*_*.svg regenerated (the 52 theme face SVGs that production rasterises at startup). Both rendering paths must agree. Workspace clippy + cargo test --workspace clean. Pin test passes against the new hashes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
25 lines
1.6 KiB
XML
25 lines
1.6 KiB
XML
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="384" viewBox="0 0 256 384">
|
||
<rect x="1" y="1" width="254" height="382" rx="16" ry="16"
|
||
fill="#1a1a1a" stroke="#d0d0d0" stroke-width="2"/>
|
||
|
||
<!-- Top-left rank in JetBrains-Mono-styled FiraMono (rank digits
|
||
and letters render correctly in FiraMono; only the suit glyphs
|
||
needed to escape to paths). -->
|
||
<text x="14" y="44" font-family="Fira Mono" font-size="36" font-weight="700"
|
||
fill="#d0d0d0">9</text>
|
||
|
||
<!-- Top-left small suit glyph at (14, 50), 20 × 20.
|
||
`suit_path_d` is authored in a 32-unit box, so scale 0.625
|
||
lands the visible glyph at 20 px. -->
|
||
<g transform="translate(14 50) scale(0.625)">
|
||
<path d="M16,4 C 13,4 10,7 10,10 C 10,12 11,13 12,14 C 9,14 4,17 4,21 C 4,24 7,27 10,27 C 12,27 14,26 14,24 L 13,30 L 19,30 L 18,24 C 18,26 20,27 22,27 C 25,27 28,24 28,21 C 28,17 23,14 20,14 C 21,13 22,12 22,10 C 22,7 19,4 16,4 Z" fill="none" stroke="#d0d0d0" stroke-width="3"/>
|
||
</g>
|
||
|
||
<!-- Bottom-right large suit glyph, 64 × 64, rotated 180° so it
|
||
reads upside-down (the convention for inverted-corner
|
||
indicators). The transform pipeline lands the glyph's visible
|
||
bottom-right at (242, 350) and visible top-left at (178, 286). -->
|
||
<g transform="translate(242 350) rotate(180) scale(2)">
|
||
<path d="M16,4 C 13,4 10,7 10,10 C 10,12 11,13 12,14 C 9,14 4,17 4,21 C 4,24 7,27 10,27 C 12,27 14,26 14,24 L 13,30 L 19,30 L 18,24 C 18,26 20,27 22,27 C 25,27 28,24 28,21 C 28,17 23,14 20,14 C 21,13 22,12 22,10 C 22,7 19,4 16,4 Z" fill="none" stroke="#d0d0d0" stroke-width="3"/>
|
||
</g>
|
||
</svg> |