PaintStyle.h 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /*
  2. * Copyright (c) 2023, MacDue <macdue@dueutil.tech>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #pragma once
  7. #include <AK/Function.h>
  8. #include <AK/NonnullRefPtr.h>
  9. #include <AK/QuickSort.h>
  10. #include <AK/RefCounted.h>
  11. #include <AK/RefPtr.h>
  12. #include <AK/Vector.h>
  13. #include <LibGfx/Bitmap.h>
  14. #include <LibGfx/Color.h>
  15. #include <LibGfx/Forward.h>
  16. #include <LibGfx/Gradients.h>
  17. #include <LibGfx/Rect.h>
  18. namespace Gfx {
  19. class PaintStyle : public RefCounted<PaintStyle> {
  20. public:
  21. virtual ~PaintStyle() = default;
  22. using SamplerFunction = Function<Color(IntPoint)>;
  23. using PaintFunction = Function<void(SamplerFunction)>;
  24. friend Painter;
  25. friend AntiAliasingPainter;
  26. private:
  27. // Simple paint styles can simply override sample_color() if they can easily generate a color from a coordinate.
  28. virtual Color sample_color(IntPoint) const { return Color(); };
  29. // Paint styles that have paint time dependent state (e.g. based on the paint size) may find it easier to override paint().
  30. // If paint() is overridden sample_color() is unused.
  31. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const
  32. {
  33. (void)physical_bounding_box;
  34. paint([this](IntPoint point) { return sample_color(point); });
  35. }
  36. };
  37. class SolidColorPaintStyle final : public PaintStyle {
  38. public:
  39. static ErrorOr<NonnullRefPtr<SolidColorPaintStyle>> create(Color color)
  40. {
  41. return adopt_nonnull_ref_or_enomem(new (nothrow) SolidColorPaintStyle(color));
  42. }
  43. virtual Color sample_color(IntPoint) const override { return m_color; }
  44. private:
  45. SolidColorPaintStyle(Color color)
  46. : m_color(color)
  47. {
  48. }
  49. Color m_color;
  50. };
  51. class BitmapPaintStyle : public PaintStyle {
  52. public:
  53. static ErrorOr<NonnullRefPtr<BitmapPaintStyle>> create(Bitmap const& bitmap, IntPoint offset = {})
  54. {
  55. return adopt_nonnull_ref_or_enomem(new (nothrow) BitmapPaintStyle(bitmap, offset));
  56. }
  57. virtual Color sample_color(IntPoint point) const override
  58. {
  59. point += m_offset;
  60. if (m_bitmap->rect().contains(point))
  61. return m_bitmap->get_pixel(point);
  62. return Color();
  63. }
  64. private:
  65. BitmapPaintStyle(Bitmap const& bitmap, IntPoint offset)
  66. : m_bitmap(bitmap)
  67. , m_offset(offset)
  68. {
  69. }
  70. NonnullRefPtr<Bitmap const> m_bitmap;
  71. IntPoint m_offset;
  72. };
  73. class GradientPaintStyle : public PaintStyle {
  74. public:
  75. ErrorOr<void> add_color_stop(float position, Color color, Optional<float> transition_hint = {})
  76. {
  77. return add_color_stop(ColorStop { color, position, transition_hint });
  78. }
  79. ErrorOr<void> add_color_stop(ColorStop stop, bool sort = true)
  80. {
  81. TRY(m_color_stops.try_append(stop));
  82. if (sort)
  83. quick_sort(m_color_stops, [](auto& a, auto& b) { return a.position < b.position; });
  84. return {};
  85. }
  86. void set_repeat_length(float repeat_length)
  87. {
  88. m_repeat_length = repeat_length;
  89. }
  90. ReadonlySpan<ColorStop> color_stops() const { return m_color_stops; }
  91. Optional<float> repeat_length() const { return m_repeat_length; }
  92. private:
  93. Vector<ColorStop, 4> m_color_stops;
  94. Optional<float> m_repeat_length;
  95. };
  96. // These paint styles are based on the CSS gradients. They are relative to the painted
  97. // shape and support premultiplied alpha.
  98. class LinearGradientPaintStyle final : public GradientPaintStyle {
  99. public:
  100. static ErrorOr<ErrorOr<NonnullRefPtr<LinearGradientPaintStyle>>> create(float angle = 0.0f)
  101. {
  102. return adopt_nonnull_ref_or_enomem(new (nothrow) LinearGradientPaintStyle(angle));
  103. }
  104. private:
  105. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const override;
  106. LinearGradientPaintStyle(float angle)
  107. : m_angle(angle)
  108. {
  109. }
  110. float m_angle { 0.0f };
  111. };
  112. class ConicGradientPaintStyle final : public GradientPaintStyle {
  113. public:
  114. static ErrorOr<NonnullRefPtr<ConicGradientPaintStyle>> create(IntPoint center, float start_angle = 0.0f)
  115. {
  116. return adopt_nonnull_ref_or_enomem(new (nothrow) ConicGradientPaintStyle(center, start_angle));
  117. }
  118. private:
  119. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const override;
  120. ConicGradientPaintStyle(IntPoint center, float start_angle)
  121. : m_center(center)
  122. , m_start_angle(start_angle)
  123. {
  124. }
  125. IntPoint m_center;
  126. float m_start_angle { 0.0f };
  127. };
  128. class RadialGradientPaintStyle final : public GradientPaintStyle {
  129. public:
  130. static ErrorOr<NonnullRefPtr<RadialGradientPaintStyle>> create(IntPoint center, IntSize size)
  131. {
  132. return adopt_nonnull_ref_or_enomem(new (nothrow) RadialGradientPaintStyle(center, size));
  133. }
  134. private:
  135. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const override;
  136. RadialGradientPaintStyle(IntPoint center, IntSize size)
  137. : m_center(center)
  138. , m_size(size)
  139. {
  140. }
  141. IntPoint m_center;
  142. IntSize m_size;
  143. };
  144. // The following paint styles implement the gradients required for the HTML canvas.
  145. // These gradients are (unlike CSS ones) not relative to the painted shape, and do not
  146. // support premultiplied alpha.
  147. class CanvasLinearGradientPaintStyle final : public GradientPaintStyle {
  148. public:
  149. static ErrorOr<NonnullRefPtr<CanvasLinearGradientPaintStyle>> create(FloatPoint p0, FloatPoint p1)
  150. {
  151. return adopt_nonnull_ref_or_enomem(new (nothrow) CanvasLinearGradientPaintStyle(p0, p1));
  152. }
  153. private:
  154. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const override;
  155. CanvasLinearGradientPaintStyle(FloatPoint p0, FloatPoint p1)
  156. : m_p0(p0)
  157. , m_p1(p1)
  158. {
  159. }
  160. FloatPoint m_p0;
  161. FloatPoint m_p1;
  162. };
  163. class CanvasConicGradientPaintStyle final : public GradientPaintStyle {
  164. public:
  165. static ErrorOr<NonnullRefPtr<CanvasConicGradientPaintStyle>> create(FloatPoint center, float start_angle = 0.0f)
  166. {
  167. return adopt_nonnull_ref_or_enomem(new (nothrow) CanvasConicGradientPaintStyle(center, start_angle));
  168. }
  169. private:
  170. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const override;
  171. CanvasConicGradientPaintStyle(FloatPoint center, float start_angle)
  172. : m_center(center)
  173. , m_start_angle(start_angle)
  174. {
  175. }
  176. FloatPoint m_center;
  177. float m_start_angle { 0.0f };
  178. };
  179. class CanvasRadialGradientPaintStyle final : public GradientPaintStyle {
  180. public:
  181. static ErrorOr<NonnullRefPtr<CanvasRadialGradientPaintStyle>> create(FloatPoint start_center, float start_radius, FloatPoint end_center, float end_radius)
  182. {
  183. return adopt_nonnull_ref_or_enomem(new (nothrow) CanvasRadialGradientPaintStyle(start_center, start_radius, end_center, end_radius));
  184. }
  185. private:
  186. virtual void paint(IntRect physical_bounding_box, PaintFunction paint) const override;
  187. CanvasRadialGradientPaintStyle(FloatPoint start_center, float start_radius, FloatPoint end_center, float end_radius)
  188. : m_start_center(start_center)
  189. , m_start_radius(start_radius)
  190. , m_end_center(end_center)
  191. , m_end_radius(end_radius)
  192. {
  193. }
  194. FloatPoint m_start_center;
  195. float m_start_radius { 0.0f };
  196. FloatPoint m_end_center;
  197. float m_end_radius { 0.0f };
  198. };
  199. }