getRich method

Widget getRich(
  1. InlineSpan span, {
  2. bool isRoot = false,
  3. bool ambientScaling = false,
})

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);
}