Draw a reply's links as text spans, not a node per link

Compose materializes every LinkAnnotation as its own layout node -- a
clipped, focusable, hoverable, clickable box laid out against the text --
and the markdown renderer emits one per link. Measured on the emulator
against the same paragraphs with each link replaced by its label and URL
as plain words: the linked version cost five times the worst measure
(26.3ms vs 5.2ms) and 1.7x the place time, with less text on screen. On
the phone that was the bump at a reply's list of sources.

The paragraph, text and heading components now go through LinkedText,
which builds the renderer's annotated string with an annotator that
styles a link as a span carrying its address, and hit-tests taps against
the text layout itself. After: place back at the link-free level (worst
3.1ms), worst measure halved. Table cells and reference links keep the
renderer's path; the table draws its own cells.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
irisandClaude Fable 5.1 committed 2026-09-02 04:39:05 -04:00
1 parent 63c0bb9e4a
commit f87c99c71b
2 files changed
+154

No files matched your search

@@ -144,6 +144,19 @@ fun MarkdownText(text: String, replies: ParsedReplies, modifier: Modifier = Modi
// The m3 renderer's own default, restored: supplying `components` at all replaces
// the whole set, and this is the only member of it the Material layer overrides.
checkbox = { MarkdownCheckBox(it.content, it.node, it.typography.text) },
// Everything that draws a run of text, so a link is a span rather than a node --
// see [LinkedText]. Setext headings take the same styles as `#` and `##`, which
// is the renderer's own pairing.
text = { LinkedText(it, it.typography.text) },
paragraph = { LinkedText(it, it.typography.paragraph) },
heading1 = { LinkedText(it, it.typography.h1, heading = true) },
heading2 = { LinkedText(it, it.typography.h2, heading = true) },
heading3 = { LinkedText(it, it.typography.h3, heading = true) },
heading4 = { LinkedText(it, it.typography.h4, heading = true) },
heading5 = { LinkedText(it, it.typography.h5, heading = true) },
heading6 = { LinkedText(it, it.typography.h6, heading = true) },
setextHeading1 = { LinkedText(it, it.typography.h1, heading = true) },
setextHeading2 = { LinkedText(it, it.typography.h2, heading = true) },
table = {
MarkdownTable(
it.content,