getRich method
A method to get a rich text widget from an inline span.
Paragraphs that mix right-to-left text with two or more inline widgets (LaTeX, images, links) are rendered with BidiText, which works around https://github.com/flutter/flutter/issues/54400 — the engine otherwise lays those inline widgets out left to right and they come out reversed. Everything else keeps using a plain Text.
Implementation
Widget getRich(
InlineSpan span, {
bool isRoot = false,
bool ambientScaling = false,
}) {
// A nested paragraph sits inside a `WidgetSpan`, and a paragraph lays its
// inline children out in scaled space — it hands them `maxWidth / scale`
// and multiplies the reported size back. A child that scales its own text
// as well is counted twice, so nested paragraphs opt out.
//
// Passing `textScaler` here would defeat that: an explicit scaler on a
// `Text` wins over the ambient `MediaQuery`, so the paragraph would scale
// itself again despite the `withNoTextScaling` wrapper below.
//
// [ambientScaling] is the third case: a block lifted out of the paragraph
// entirely. It has to scale, so it cannot opt out — but it must scale from
// the ambient `MediaQuery`, which `GptMarkdown` has already set from
// `textScaler`. Descendant blocks inside this paragraph must switch
// blocksRenderDirectly off: their placeholder already supplies scaling.
final scaleFromAmbient = ambientScaling && !isRoot;
final effectiveScaler = scaleFromAmbient
? null
: (isRoot ? textScaler : TextScaler.noScaling);
final codeRuns = collectInlineCodeRuns(span);
// A tap target is resolved by the paragraph's render object, so a
// paragraph holding one has to go through BidiText. Missing this renders
// the span as ordinary text with no tap and no error.
final tapRuns = collectInlineTapRuns(span);
final needsBidi = needsBidiPlaceholderFix(span);
if (codeRuns.isEmpty && tapRuns.isEmpty && !needsBidi) {
// Nothing to decorate and no placeholders to reorder — the stock widget
// does the job, and stays the hot path for ordinary paragraphs.
final Widget child = Text.rich(
span,
textDirection: textDirection,
textScaler: effectiveScaler,
textAlign: textAlign,
maxLines: maxLines,
overflow: overflow,
);
if (isRoot || scaleFromAmbient) {
return child;
}
return MarkdownTextScaling.wrap(child, enabled: false);
}
final child = BidiText(
span,
bidiEnabled: needsBidi,
inlineCodeRuns: codeRuns,
inlineTapRuns: tapRuns,
textDirection: textDirection,
textScaler: effectiveScaler,
textAlign: textAlign,
maxLines: maxLines,
overflow: overflow,
);
if (isRoot || scaleFromAmbient) {
return child;
}
return MarkdownTextScaling.wrap(child, enabled: false);
}