content: import 'dart:ui';
  
  import 'enumeration.dart';
  
  Path dashPath(
    Path source, {
    required CircularIntervalList<double> dashArray,
    DashOffset? dashOffset,
  }) {
    assert(dashArray != null); // ignore: unnecessary_null_comparison
  
    dashOffset = dashOffset ?? const DashOffset.absolute(0.0);
  
    final Path dest = Path();
    for (final PathMetric metric in source.computeMetrics()) {
      double distance = dashOffset._calculate(metric.length);
      bool draw = true;
      while (distance < metric.length) {
        final double len = dashArray.next;
        if (draw) {
          dest.addPath(metric.extractPath(distance, distance + len), Offset.zero);
        }
        distance += len;
        draw = !draw;
      }
    }
  
    return dest;
  }
  
  /// Specifies the starting position of a dash array on a path, either as a
  /// percentage or absolute value.
  ///
  /// The internal value will be guaranteed to not be null.
  class DashOffset {
    /// Create a DashOffset that will be measured as a percentage of the length
    /// of the segment being dashed.
    ///
    /// `percentage` will be clamped between 0.0 and 1.0.
    DashOffset.percentage(double percentage)
        : _rawVal = percentage.clamp(0.0, 1.0),
          _dashOffsetType = DashOffsetType.percentage;
  
    /// Create a DashOffset that will be measured in terms of absolute pixels
    /// along the length of a [Path] segment.
    const DashOffset.absolute(double start)
        : _rawVal = start,
          _dashOffsetType = DashOffsetType.absolute;
  
    final double _rawVal;
    final DashOffsetType _dashOffsetType;
  
    double _calculate(double length) {
      return _dashOffsetType == DashOffsetType.absolute
          ? _rawVal
          : length * _rawVal;
    }
  
    @override
    bool operator ==(Object other) {
      if (identical(this, other)) {
        return true;
      }
  
      return other is DashOffset &&
          other._rawVal == _rawVal &&
          other._dashOffsetType == _dashOffsetType;
    }
  
    @override
    int get hashCode => Object.hash(_rawVal, _dashOffsetType);
  }
  
  /// A circular array of dash offsets and lengths.
  ///
  /// For example, the array `[5, 10]` would result in dashes 5 pixels long
  /// followed by blank spaces 10 pixels long.  The array `[5, 10, 5]` would
  /// result in a 5 pixel dash, a 10 pixel gap, a 5 pixel dash, a 5 pixel gap,
  /// a 10 pixel dash, etc.
  ///
  /// Note that this does not quite conform to an [Iterable<T>], because it does
  /// not have a moveNext.
  class CircularIntervalList<T> {
    CircularIntervalList(this._vals);
  
    final List<T> _vals;
    int _idx = 0;
  
    T get next {
      if (_idx >= _vals.length) {
        _idx = 0;
      }
      return _vals[_idx++];
    }
  }
  