/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef DOM_SVG_SVGPATHSEGUTILS_H_
#define DOM_SVG_SVGPATHSEGUTILS_H_

#include "mozilla/Span.h"
#include "mozilla/gfx/Point.h"
#include "mozilla/gfx/Rect.h"

namespace mozilla {

// Position
template <typename H, typename V>
struct StyleGenericPosition;

// Command Endpoint
template <typename Position, typename LP>
struct StyleCommandEndPoint;
template <typename T>
using StyleEndPoint = StyleCommandEndPoint<StyleGenericPosition<T, T>, T>;

// Control Point
template <typename Position, typename LP>
struct StyleControlPoint;
template <typename T>
using StyleCurveControlPoint = StyleControlPoint<StyleGenericPosition<T, T>, T>;

// Shape Command
template <typename Angle, typename Position, typename LP>
struct StyleGenericShapeCommand;
using StylePathCommand =
    StyleGenericShapeCommand<float, StyleGenericPosition<float, float>, float>;

/**
 * Code that works with path segments can use an instance of this class to
 * store/provide information about the start of the current subpath and the
 * last path segment (if any).
 */
struct MOZ_STACK_CLASS SVGPathTraversalState {
  using Point = gfx::Point;

  enum class TraversalMode { UpdateAll, UpdateOnlyStartAndCurrentPos };

  bool ShouldUpdateLengthAndControlPoints() const {
    return mode == TraversalMode::UpdateAll;
  }

  Point start;  // start point of current sub path (reset each moveto)

  Point pos;  // current position (end point of previous segment)

  Point cp1;  // quadratic control point - if the previous segment was a
              // quadratic bezier curve then this is set to the absolute
              // position of its control point, otherwise its set to pos

  Point cp2;  // cubic control point - if the previous segment was a cubic
              // bezier curve then this is set to the absolute position of
              // its second control point, otherwise it's set to pos

  // accumulated path length
  float length = 0.0f;

  // indicates what to track while traversing a path
  TraversalMode mode = TraversalMode::UpdateAll;
};

/**
 * This class is just a collection of static methods - it doesn't have any data
 * members, and it's not possible to create instances of this class. This class
 * exists purely as a convenient place to gather together a bunch of methods
 * related to manipulating and answering questions about path segments.
 * Internally we represent path segments purely as an array of floats. See the
 * comment documenting SVGPathData for more info on that.
 *
 * The DOM wrapper classes for encoded path segments (data contained in
 * instances of SVGPathData) is DOMSVGPathSeg and its sub-classes. Note that
 * there are multiple different DOM classes for path segs - one for each of the
 * 19 SVG 1.1 segment types.
 */
class SVGPathSegUtils {
 private:
  SVGPathSegUtils() = default;  // private to prevent instances

 public:
  /**
   * Traverse the given path segment and update the SVGPathTraversalState
   * object. This is identical to the above one but accepts StylePathCommand.
   */
  static void TraversePathSegment(const StylePathCommand&,
                                  SVGPathTraversalState&);

  /// Detect whether the path represents a rectangle (for both filling AND
  /// stroking) and if so returns it.
  ///
  /// This is typically useful for google slides which has many of these
  /// rectangle shaped paths. It handles the same scenarios as skia's
  /// SkPathPriv::IsRectContour which it is inspired from, including zero-length
  /// edges and multiple points on edges of the rectangle, and doesn't attempt
  /// to detect flat curves (that could easily be added but the expectation is
  /// that since skia doesn't fast path it we're not likely to run into it in
  /// practice).
  ///
  /// We could implement something similar for polygons.
  static Maybe<gfx::Rect> SVGPathToAxisAlignedRect(
      Span<const StylePathCommand>);
};

}  // namespace mozilla

#endif  // DOM_SVG_SVGPATHSEGUTILS_H_
