measure method

  1. @override
NodeLayout measure({
  1. required LatexNode node,
  2. required RenderContext context,
  3. required NodeLayout measureNode(
    1. LatexNode,
    2. RenderContext
    ),
  4. required NodeLayout measureGroup(
    1. List<LatexNode>,
    2. RenderContext
    ),
})
override

Measures a node and returns its layout.

Implementation

@override
NodeLayout measure({
  required LatexNode node,
  required RenderContext context,
  required NodeLayout Function(LatexNode, RenderContext) measureNode,
  required NodeLayout Function(List<LatexNode>, RenderContext) measureGroup,
}) {
  final stackNode = node as StackNode;

  // FIX: Safely use .children() as a method per the Dart AST definitions.
  LatexNode unwrapSingleGroup(LatexNode node0) {
    LatexNode n = node0;
    while (n is GroupNode && n.children().length == 1) {
      n = n.children()[0];
    }
    return n;
  }

  LatexNode? merge(LatexNode? a, LatexNode? b) {
    if (a == null) return b;
    if (b == null) return a;
    return GroupNode([a, b]);
  }

  LatexNode baseNode = unwrapSingleGroup(stackNode.base);
  LatexNode? aboveNode = stackNode.above != null
      ? unwrapSingleGroup(stackNode.above!)
      : null;
  LatexNode? belowNode = stackNode.below != null
      ? unwrapSingleGroup(stackNode.below!)
      : null;

  while (baseNode is StackNode) {
    final inner = baseNode;
    aboveNode = merge(
      aboveNode,
      inner.above != null ? unwrapSingleGroup(inner.above!) : null,
    );
    belowNode = merge(
      belowNode,
      inner.below != null ? unwrapSingleGroup(inner.below!) : null,
    );
    baseNode = unwrapSingleGroup(inner.base);
  }

  final baseLayout = measureGroup([baseNode], context);
  final scriptStyle = context.shrink(MathConstants.stackScriptScale);

  final aboveLayout = aboveNode != null
      ? measureGroup([aboveNode], scriptStyle)
      : null;
  final belowLayout = belowNode != null
      ? measureGroup([belowNode], scriptStyle)
      : null;

  final totalWidth = math.max(
    baseLayout.width,
    math.max(aboveLayout?.width ?? 0.0, belowLayout?.width ?? 0.0),
  );

  final fontSizePx = context.fontSize;
  final gap = fontSizePx * MathConstants.stackVerticalGap;

  final double? aboveY = aboveLayout != null ? 0.0 : null;
  final baseY =
      (aboveLayout?.height ?? 0.0) + (aboveLayout != null ? gap : 0.0);
  final belowY = belowLayout != null ? baseY + baseLayout.height + gap : null;

  final totalHeight = belowLayout != null
      ? baseY + baseLayout.height + gap + belowLayout.height
      : baseY + baseLayout.height;

  final baseline = baseY + baseLayout.baseline;

  return NodeLayout(
    width: totalWidth,
    height: totalHeight,
    baseline: baseline,
    draw: (canvas, x, y) {
      final baseX = x + (totalWidth - baseLayout.width) / 2.0;
      baseLayout.draw(canvas, baseX, y + baseY);

      if (aboveLayout != null) {
        final aboveX = x + (totalWidth - aboveLayout.width) / 2.0;
        aboveLayout.draw(canvas, aboveX, y + (aboveY ?? 0.0));
      }

      if (belowLayout != null) {
        final belowX = x + (totalWidth - belowLayout.width) / 2.0;
        belowLayout.draw(canvas, belowX, y + (belowY ?? 0.0));
      }
    },
  );
}