ShapeText built ShapedRunKey{..., std::string(utf8)} before find()
unconditionally — even on cache hits, on the per-frame onBuild path.
N labels meant N string copies + hashes (+ frees for non-SSO strings)
every frame, partially defeating the run cache.
Add is_transparent hash + equality functors on shapedRuns_ and probe
with a borrowing ShapedRunViewKey {const Font*, float, array<float,4>,
string_view}. The owning std::string is now materialised only on a
miss, for emplace. Cache hits copy and hash no string.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>