openpencil/crates
Eslam Ahmad 7f8340f2a0 fix(renderer): shape complex scripts instead of painting them in storage order (#194)
Native `draw_text` painted every run through `Canvas::draw_str`, which maps
to Skia's `drawSimpleText` — a plain cmap lookup with no bidi reordering and
no contextual glyph selection. Arabic therefore rendered in storage order
with isolated letterforms. CanvasKit's `drawText` has the same limitation on
web, and `drawScriptRun` there segmented a run by script before drawing the
segments left to right, so bidi was resolved inside each segment and then
undone across them.

The paragraph shaper was bypassed natively on purpose: jian's
`draw_text_paragraph` builds a fresh `FontCollection` on every call, which
is what produced the ~605ms chrome frames noted in crates/CLAUDE.md. That
cost is avoidable rather than inherent — `ParagraphBaseline` already keeps a
generation-guarded collection — so this caches the collection and routes
only the runs that genuinely need a shaper. Latin and CJK stay on the cmap
fast path, leaving the frame budget and their rendered output untouched.

Measurement moves with paint. `measure_text_*` summed isolated-glyph
advances, so wrap decisions and caret geometry were computed against widths
the painter never used and text overflowed its boxes. The routing predicate
lives in op-editor-core so the two hosts cannot disagree about which runs
are shaped, and so paint and measure within a host cannot drift apart.

Hebrew is deliberately out of scope and stays on the fast path.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 19:18:50 +08:00
..
op-acp fix(editor): async hygiene — safe block_on, bounded acp channels, thread teardown 2026-07-26 13:19:34 +08:00
op-ai feat(agent): surface a quality credential after generation 2026-07-28 00:29:39 +08:00
op-ai-skills feat(ai): give the planning corpus a presentation-deck tier 2026-08-02 11:02:33 +08:00
op-auth-bridge feat(collab): require recovery epochs in union policy v2 2026-08-01 16:30:38 +08:00
op-cli chore(rust): align workspace checks 2026-08-01 16:19:26 +08:00
op-codegen refactor: typed error enums across the whole workspace 2026-07-27 21:09:06 +08:00
op-collab chore(rust): align workspace checks 2026-08-01 16:19:26 +08:00
op-collab-policy-file fix(collab): harden p2p collaboration against resource exhaustion 2026-08-01 09:48:23 +08:00
op-collab-relay-client fix(collab): close review follow-ups and align the reauth budget test 2026-08-01 11:42:10 +08:00
op-collab-relay-control-plane feat(collab): replace public invites with 10-char region-tagged pairing codes 2026-08-02 08:31:13 +08:00
op-collab-relay-locator-hsm feat(collab): add isolated PKCS11 locator signer 2026-08-01 16:35:59 +08:00
op-collab-relay-locator-server feat(collab): replace public invites with 10-char region-tagged pairing codes 2026-08-02 08:31:13 +08:00
op-collab-relay-protocol feat(collab): replace public invites with 10-char region-tagged pairing codes 2026-08-02 08:31:13 +08:00
op-collab-relay-server feat(collab): minimize the relay credential and confirm the owner on LAN 2026-08-01 14:24:46 +08:00
op-collab-smoke feat(collab): allow cross-account collaboration 2026-08-01 13:01:24 +08:00
op-collab-transport fix(collab): tolerate public relay handshake latency 2026-08-02 18:39:21 +08:00
op-config-store test(desktop): keep persistence tests out of the real user config 2026-07-28 00:29:39 +08:00
op-design-lint refactor: final 800-line sweep across editor, mcp, services, and tool crates 2026-07-26 22:34:37 +08:00
op-editor-core fix(renderer): shape complex scripts instead of painting them in storage order (#194) 2026-08-02 19:18:50 +08:00
op-editor-host-core feat(collab): add authenticated p2p collaboration 2026-07-29 00:06:58 +08:00
op-editor-ui feat(desktop): open scene templates from File > new from template 2026-08-02 11:00:34 +08:00
op-figma refactor: typed error enums across the whole workspace 2026-07-27 21:09:06 +08:00
op-git
op-host-desktop fix(collab): tolerate public relay handshake latency 2026-08-02 18:39:21 +08:00
op-host-native fix(renderer): shape complex scripts instead of painting them in storage order (#194) 2026-08-02 19:18:50 +08:00
op-host-services fix(mcp): authenticate the live endpoint and degrade the bootstrap cache 2026-08-01 12:23:09 +08:00
op-host-web fix(renderer): shape complex scripts instead of painting them in storage order (#194) 2026-08-02 19:18:50 +08:00
op-host-web-server refactor: dedupe cross-crate code and converge hardcoded literals 2026-07-26 11:24:22 +08:00
op-html refactor: typed error enums across the whole workspace 2026-07-27 21:09:06 +08:00
op-i18n feat(i18n): translate the scene template center 2026-08-02 11:02:33 +08:00
op-mcp fix(mcp): tolerate a trailing separator on a program DSL line 2026-07-31 21:00:50 +08:00
op-opmerge
op-orchestrator fix(agent): scaffold a deck's screen roots in one insert 2026-08-02 11:44:32 +08:00
op-pen-loader fix(canvas): adopt stack semantics for layout:none and retire the flow bandaid 2026-07-28 22:11:59 +08:00
op-process-io
op-rpc-transport fix(mcp): authenticate the live endpoint and degrade the bootstrap cache 2026-08-01 12:23:09 +08:00
op-smoke feat(agent): add a fixed-input modify mode to the smoke harness 2026-07-31 21:06:35 +08:00
op-util feat(collab): add authenticated p2p collaboration 2026-07-29 00:06:58 +08:00
op-web-sdk refactor: typed error enums across the whole workspace 2026-07-27 21:09:06 +08:00
CLAUDE.md feat(collab): add authenticated p2p collaboration 2026-07-29 00:06:58 +08:00