TextPaintPlan constructor

TextPaintPlan({
  1. required Size box,
  2. required Offset at,
  3. required Rect ink,
  4. required List<Fill> fill,
  5. required Stroke? stroke,
  6. required List<TextEffect> effects,
})

Plans the painting of letters drawn at at in a box of box, whose ink lies within ink.

Implementation

TextPaintPlan({
  required ui.Size box,
  required this.at,
  required ui.Rect ink,
  required List<Fill> fill,
  required Stroke? stroke,
  required List<TextEffect> effects,
}) {
  final ui.Rect rect = ui.Offset.zero & box;
  _box = rect;
  _fills = <(Object, ui.Paint)>[for (final Fill layer in fill.reversed) fillPaint(layer, box)];
  final bool fillOpaque = fill.any(isOpaque);
  final List<TextInnerShadow> inner = effects.isEmpty
      ? const <TextInnerShadow>[]
      : <TextInnerShadow>[
          for (final TextEffect e in effects.reversed)
            if (e is TextInnerShadow) e,
        ];
  _innerShadows = inner;

  double extent = 0;
  if (stroke == null || stroke.weight == 0 || stroke.fill.isEmpty) {
    _mode = .none;
  } else {
    final double w = stroke.weight;
    // Outside and inside strokes are drawn twice as wide, then cut to one side of the outline.
    final double width = stroke.align == .center ? w : 2 * w;
    _mode = switch (stroke.align) {
      .center => .center,
      // An opaque fill hides the stroke's inner half, so drawn beneath it no cut is needed.
      .outside when fillOpaque && inner.isEmpty => .under,
      .outside => .outside,
      .inside => .inside,
    };
    _strokes = <(Object, ui.Paint)>[
      for (final Fill layer in stroke.fill.reversed)
        ((#stroke, layer, width, _placed(layer, box)), _stroking(paintFor(layer, rect), width)),
    ];
    extent = stroke.outset;
    if (extent > 0) _silhouetteStroke = 2 * extent;
    // The shadows see the stroke's outer edge; an opaque one covers them.
    _covered = fillOpaque && (extent == 0 || stroke.fill.any(isOpaque));
  }
  if (_mode == .none) _covered = fillOpaque;

  _dropShadows = effects.isEmpty
      ? const <TextDropShadow>[]
      : <TextDropShadow>[
          for (final TextEffect e in effects.reversed)
            if (e is TextDropShadow) e,
        ];
  _blurs = layerBlursOf(effects);
  _bounds = ink.inflate(extent + effectsReach(effects) + 1);
  _placesPaints = !fill.every(_isSolid) || !(stroke?.fill.every(_isSolid) ?? true);
}