Path.h 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. * Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/ByteString.h>
  8. #include <AK/HashMap.h>
  9. #include <AK/Optional.h>
  10. #include <AK/Vector.h>
  11. #include <LibGfx/Font/Font.h>
  12. #include <LibGfx/Forward.h>
  13. #include <LibGfx/Line.h>
  14. #include <LibGfx/Point.h>
  15. #include <LibGfx/Rect.h>
  16. namespace Gfx {
  17. class Segment : public RefCounted<Segment> {
  18. public:
  19. enum class Type {
  20. Invalid,
  21. MoveTo,
  22. LineTo,
  23. QuadraticBezierCurveTo,
  24. CubicBezierCurveTo,
  25. };
  26. Segment(FloatPoint point)
  27. : m_point(point)
  28. {
  29. }
  30. virtual ~Segment() = default;
  31. FloatPoint point() const { return m_point; }
  32. virtual Type type() const = 0;
  33. protected:
  34. FloatPoint m_point;
  35. };
  36. class MoveSegment final : public Segment {
  37. public:
  38. MoveSegment(FloatPoint point)
  39. : Segment(point)
  40. {
  41. }
  42. private:
  43. virtual Type type() const override { return Segment::Type::MoveTo; }
  44. };
  45. class LineSegment final : public Segment {
  46. public:
  47. LineSegment(FloatPoint point)
  48. : Segment(point)
  49. {
  50. }
  51. virtual ~LineSegment() override = default;
  52. private:
  53. virtual Type type() const override { return Segment::Type::LineTo; }
  54. };
  55. class QuadraticBezierCurveSegment final : public Segment {
  56. public:
  57. QuadraticBezierCurveSegment(FloatPoint point, FloatPoint through)
  58. : Segment(point)
  59. , m_through(through)
  60. {
  61. }
  62. virtual ~QuadraticBezierCurveSegment() override = default;
  63. FloatPoint through() const { return m_through; }
  64. private:
  65. virtual Type type() const override { return Segment::Type::QuadraticBezierCurveTo; }
  66. FloatPoint m_through;
  67. };
  68. class CubicBezierCurveSegment final : public Segment {
  69. public:
  70. CubicBezierCurveSegment(FloatPoint point, FloatPoint through_0, FloatPoint through_1)
  71. : Segment(point)
  72. , m_through_0(through_0)
  73. , m_through_1(through_1)
  74. {
  75. }
  76. virtual ~CubicBezierCurveSegment() override = default;
  77. FloatPoint through_0() const { return m_through_0; }
  78. FloatPoint through_1() const { return m_through_1; }
  79. private:
  80. virtual Type type() const override { return Segment::Type::CubicBezierCurveTo; }
  81. FloatPoint m_through_0;
  82. FloatPoint m_through_1;
  83. };
  84. class Path {
  85. public:
  86. Path() = default;
  87. void move_to(FloatPoint point)
  88. {
  89. append_segment<MoveSegment>(point);
  90. }
  91. void line_to(FloatPoint point)
  92. {
  93. append_segment<LineSegment>(point);
  94. invalidate_split_lines();
  95. }
  96. void horizontal_line_to(float x)
  97. {
  98. float previous_y = 0;
  99. if (!m_segments.is_empty())
  100. previous_y = m_segments.last()->point().y();
  101. line_to({ x, previous_y });
  102. }
  103. void vertical_line_to(float y)
  104. {
  105. float previous_x = 0;
  106. if (!m_segments.is_empty())
  107. previous_x = m_segments.last()->point().x();
  108. line_to({ previous_x, y });
  109. }
  110. void quadratic_bezier_curve_to(FloatPoint through, FloatPoint point)
  111. {
  112. append_segment<QuadraticBezierCurveSegment>(point, through);
  113. invalidate_split_lines();
  114. }
  115. void cubic_bezier_curve_to(FloatPoint c1, FloatPoint c2, FloatPoint p2)
  116. {
  117. append_segment<CubicBezierCurveSegment>(p2, c1, c2);
  118. invalidate_split_lines();
  119. }
  120. void elliptical_arc_to(FloatPoint point, FloatSize radii, float x_axis_rotation, bool large_arc, bool sweep);
  121. void arc_to(FloatPoint point, float radius, bool large_arc, bool sweep)
  122. {
  123. elliptical_arc_to(point, { radius, radius }, 0, large_arc, sweep);
  124. }
  125. void text(Utf8View, Font const&);
  126. FloatPoint last_point();
  127. void close();
  128. void close_all_subpaths();
  129. Vector<NonnullRefPtr<Segment const>> const& segments() const { return m_segments; }
  130. auto& split_lines() const
  131. {
  132. if (!m_split_lines.has_value()) {
  133. const_cast<Path*>(this)->segmentize_path();
  134. VERIFY(m_split_lines.has_value());
  135. }
  136. return m_split_lines.value();
  137. }
  138. void clear()
  139. {
  140. m_segments.clear();
  141. m_split_lines.clear();
  142. }
  143. Gfx::FloatRect const& bounding_box() const
  144. {
  145. if (!m_bounding_box.has_value()) {
  146. const_cast<Path*>(this)->segmentize_path();
  147. VERIFY(m_bounding_box.has_value());
  148. }
  149. return m_bounding_box.value();
  150. }
  151. void append_path(Path const& path)
  152. {
  153. m_segments.ensure_capacity(m_segments.size() + path.m_segments.size());
  154. for (auto const& segment : path.m_segments)
  155. m_segments.unchecked_append(segment);
  156. invalidate_split_lines();
  157. }
  158. Path copy_transformed(AffineTransform const&) const;
  159. void add_path(Path const&);
  160. void ensure_subpath(FloatPoint point);
  161. ByteString to_byte_string() const;
  162. Path stroke_to_fill(float thickness) const;
  163. Path place_text_along(Utf8View text, Font const&) const;
  164. private:
  165. void approximate_elliptical_arc_with_cubic_beziers(FloatPoint center, FloatSize radii, float x_axis_rotation, float theta, float theta_delta);
  166. void invalidate_split_lines()
  167. {
  168. m_bounding_box.clear();
  169. m_split_lines.clear();
  170. }
  171. void segmentize_path();
  172. template<typename T, typename... Args>
  173. void append_segment(Args&&... args)
  174. {
  175. m_segments.append(adopt_ref(*new T(forward<Args>(args)...)));
  176. }
  177. Vector<NonnullRefPtr<Segment const>> m_segments {};
  178. Optional<Vector<FloatLine>> m_split_lines {};
  179. Optional<Gfx::FloatRect> m_bounding_box;
  180. bool m_need_new_subpath = { true };
  181. };
  182. }