PaintingCommandExecutorGPU.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. /*
  2. * Copyright (c) 2023, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <LibAccelGfx/GlyphAtlas.h>
  7. #include <LibWeb/Painting/BorderRadiusCornerClipper.h>
  8. #include <LibWeb/Painting/PaintingCommandExecutorGPU.h>
  9. namespace Web::Painting {
  10. PaintingCommandExecutorGPU::PaintingCommandExecutorGPU(AccelGfx::Context& context, Gfx::Bitmap& bitmap)
  11. : m_target_bitmap(bitmap)
  12. , m_context(context)
  13. {
  14. auto canvas = AccelGfx::Canvas::create(bitmap.size());
  15. auto painter = AccelGfx::Painter::create(m_context, canvas);
  16. m_stacking_contexts.append({ .canvas = canvas,
  17. .painter = move(painter),
  18. .opacity = 1.0f,
  19. .destination = {},
  20. .transform = {} });
  21. }
  22. PaintingCommandExecutorGPU::~PaintingCommandExecutorGPU()
  23. {
  24. VERIFY(m_stacking_contexts.size() == 1);
  25. painter().flush(m_target_bitmap);
  26. }
  27. CommandResult PaintingCommandExecutorGPU::draw_glyph_run(Vector<Gfx::DrawGlyphOrEmoji> const& glyph_run, Color const& color)
  28. {
  29. painter().draw_glyph_run(glyph_run, color);
  30. return CommandResult::Continue;
  31. }
  32. CommandResult PaintingCommandExecutorGPU::draw_text(Gfx::IntRect const&, String const&, Gfx::TextAlignment, Color const&, Gfx::TextElision, Gfx::TextWrapping, Optional<NonnullRefPtr<Gfx::Font>> const&)
  33. {
  34. // FIXME
  35. return CommandResult::Continue;
  36. }
  37. CommandResult PaintingCommandExecutorGPU::fill_rect(Gfx::IntRect const& rect, Color const& color)
  38. {
  39. painter().fill_rect(rect, color);
  40. return CommandResult::Continue;
  41. }
  42. static AccelGfx::Painter::ScalingMode to_accelgfx_scaling_mode(Gfx::Painter::ScalingMode scaling_mode)
  43. {
  44. switch (scaling_mode) {
  45. case Gfx::Painter::ScalingMode::NearestNeighbor:
  46. case Gfx::Painter::ScalingMode::BoxSampling:
  47. case Gfx::Painter::ScalingMode::SmoothPixels:
  48. case Gfx::Painter::ScalingMode::None:
  49. return AccelGfx::Painter::ScalingMode::NearestNeighbor;
  50. case Gfx::Painter::ScalingMode::BilinearBlend:
  51. return AccelGfx::Painter::ScalingMode::Bilinear;
  52. default:
  53. VERIFY_NOT_REACHED();
  54. }
  55. }
  56. CommandResult PaintingCommandExecutorGPU::draw_scaled_bitmap(Gfx::IntRect const& dst_rect, Gfx::Bitmap const& bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode)
  57. {
  58. painter().draw_scaled_bitmap(dst_rect, bitmap, src_rect, to_accelgfx_scaling_mode(scaling_mode));
  59. return CommandResult::Continue;
  60. }
  61. CommandResult PaintingCommandExecutorGPU::draw_scaled_immutable_bitmap(Gfx::IntRect const& dst_rect, Gfx::ImmutableBitmap const& immutable_bitmap, Gfx::IntRect const& src_rect, Gfx::Painter::ScalingMode scaling_mode)
  62. {
  63. painter().draw_scaled_immutable_bitmap(dst_rect, immutable_bitmap, src_rect, to_accelgfx_scaling_mode(scaling_mode));
  64. return CommandResult::Continue;
  65. }
  66. CommandResult PaintingCommandExecutorGPU::set_clip_rect(Gfx::IntRect const& rect)
  67. {
  68. painter().set_clip_rect(rect);
  69. return CommandResult::Continue;
  70. }
  71. CommandResult PaintingCommandExecutorGPU::clear_clip_rect()
  72. {
  73. painter().clear_clip_rect();
  74. return CommandResult::Continue;
  75. }
  76. CommandResult PaintingCommandExecutorGPU::set_font(Gfx::Font const&)
  77. {
  78. // FIXME
  79. return CommandResult::Continue;
  80. }
  81. CommandResult PaintingCommandExecutorGPU::push_stacking_context(float opacity, bool is_fixed_position, Gfx::IntRect const& source_paintable_rect, Gfx::IntPoint post_transform_translation, CSS::ImageRendering, StackingContextTransform transform, Optional<StackingContextMask>)
  82. {
  83. if (source_paintable_rect.is_empty())
  84. return CommandResult::SkipStackingContext;
  85. m_stacking_contexts.last().stacking_context_depth++;
  86. painter().save();
  87. if (is_fixed_position) {
  88. auto const& translation = painter().transform().translation();
  89. painter().translate(-translation);
  90. }
  91. auto stacking_context_transform = Gfx::extract_2d_affine_transform(transform.matrix);
  92. Gfx::AffineTransform inverse_origin_translation;
  93. inverse_origin_translation.translate(-transform.origin);
  94. Gfx::AffineTransform origin_translation;
  95. origin_translation.translate(transform.origin);
  96. Gfx::AffineTransform final_transform = origin_translation;
  97. final_transform.multiply(stacking_context_transform);
  98. final_transform.multiply(inverse_origin_translation);
  99. if (opacity < 1 || !stacking_context_transform.is_identity_or_translation()) {
  100. auto canvas = AccelGfx::Canvas::create(source_paintable_rect.size());
  101. auto painter = AccelGfx::Painter::create(m_context, canvas);
  102. painter->translate(-source_paintable_rect.location().to_type<float>());
  103. painter->clear(Color::Transparent);
  104. m_stacking_contexts.append({ .canvas = canvas,
  105. .painter = move(painter),
  106. .opacity = opacity,
  107. .destination = source_paintable_rect,
  108. .transform = final_transform });
  109. } else {
  110. painter().translate(stacking_context_transform.translation() + post_transform_translation.to_type<float>());
  111. m_stacking_contexts.append({ .canvas = {},
  112. .painter = MaybeOwned(painter()),
  113. .opacity = opacity,
  114. .destination = {},
  115. .transform = final_transform });
  116. }
  117. return CommandResult::Continue;
  118. }
  119. CommandResult PaintingCommandExecutorGPU::pop_stacking_context()
  120. {
  121. auto stacking_context = m_stacking_contexts.take_last();
  122. VERIFY(stacking_context.stacking_context_depth == 0);
  123. if (stacking_context.painter.is_owned()) {
  124. painter().blit_canvas(stacking_context.destination, *stacking_context.canvas, stacking_context.opacity, stacking_context.transform);
  125. }
  126. painter().restore();
  127. m_stacking_contexts.last().stacking_context_depth--;
  128. return CommandResult::Continue;
  129. }
  130. CommandResult PaintingCommandExecutorGPU::paint_linear_gradient(Gfx::IntRect const& rect, Web::Painting::LinearGradientData const& data)
  131. {
  132. painter().fill_rect_with_linear_gradient(rect, data.color_stops.list, data.gradient_angle, data.color_stops.repeat_length);
  133. return CommandResult::Continue;
  134. }
  135. CommandResult PaintingCommandExecutorGPU::paint_outer_box_shadow(PaintOuterBoxShadowParams const&)
  136. {
  137. // FIXME
  138. return CommandResult::Continue;
  139. }
  140. CommandResult PaintingCommandExecutorGPU::paint_inner_box_shadow(PaintOuterBoxShadowParams const&)
  141. {
  142. // FIXME
  143. return CommandResult::Continue;
  144. }
  145. CommandResult PaintingCommandExecutorGPU::paint_text_shadow(int blur_radius, Gfx::IntRect const& shadow_bounding_rect, Gfx::IntRect const& text_rect, Span<Gfx::DrawGlyphOrEmoji const> glyph_run, Color const& color, int fragment_baseline, Gfx::IntPoint const& draw_location)
  146. {
  147. auto text_shadow_canvas = AccelGfx::Canvas::create(shadow_bounding_rect.size());
  148. auto text_shadow_painter = AccelGfx::Painter::create(m_context, text_shadow_canvas);
  149. text_shadow_painter->clear(color.with_alpha(0));
  150. Gfx::FloatRect const shadow_location { draw_location, shadow_bounding_rect.size() };
  151. Gfx::IntPoint const baseline_start(text_rect.x(), text_rect.y() + fragment_baseline);
  152. text_shadow_painter->translate(baseline_start.to_type<float>());
  153. text_shadow_painter->draw_glyph_run(glyph_run, color);
  154. if (blur_radius == 0) {
  155. painter().blit_canvas(shadow_location, *text_shadow_canvas);
  156. return CommandResult::Continue;
  157. }
  158. auto horizontal_blur_canvas = AccelGfx::Canvas::create(shadow_bounding_rect.size());
  159. auto horizontal_blur_painter = AccelGfx::Painter::create(m_context, horizontal_blur_canvas);
  160. horizontal_blur_painter->clear(color.with_alpha(0));
  161. horizontal_blur_painter->blit_blurred_canvas(shadow_bounding_rect.to_type<float>(), *text_shadow_canvas, blur_radius, AccelGfx::Painter::BlurDirection::Horizontal);
  162. painter().blit_blurred_canvas(shadow_location, *horizontal_blur_canvas, blur_radius, AccelGfx::Painter::BlurDirection::Vertical);
  163. return CommandResult::Continue;
  164. }
  165. CommandResult PaintingCommandExecutorGPU::fill_rect_with_rounded_corners(Gfx::IntRect const& rect, Color const& color, Gfx::AntiAliasingPainter::CornerRadius const& top_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& top_right_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_left_radius, Gfx::AntiAliasingPainter::CornerRadius const& bottom_right_radius, Optional<Gfx::FloatPoint> const&)
  166. {
  167. painter().fill_rect_with_rounded_corners(
  168. rect, color,
  169. { static_cast<float>(top_left_radius.horizontal_radius), static_cast<float>(top_left_radius.vertical_radius) },
  170. { static_cast<float>(top_right_radius.horizontal_radius), static_cast<float>(top_right_radius.vertical_radius) },
  171. { static_cast<float>(bottom_left_radius.horizontal_radius), static_cast<float>(bottom_left_radius.vertical_radius) },
  172. { static_cast<float>(bottom_right_radius.horizontal_radius), static_cast<float>(bottom_right_radius.vertical_radius) });
  173. return CommandResult::Continue;
  174. }
  175. CommandResult PaintingCommandExecutorGPU::fill_path_using_color(Gfx::Path const&, Color const&, Gfx::Painter::WindingRule, Optional<Gfx::FloatPoint> const&)
  176. {
  177. // FIXME
  178. return CommandResult::Continue;
  179. }
  180. CommandResult PaintingCommandExecutorGPU::fill_path_using_paint_style(Gfx::Path const&, Gfx::PaintStyle const&, Gfx::Painter::WindingRule, float, Optional<Gfx::FloatPoint> const&)
  181. {
  182. // FIXME
  183. return CommandResult::Continue;
  184. }
  185. CommandResult PaintingCommandExecutorGPU::stroke_path_using_color(Gfx::Path const&, Color const&, float, Optional<Gfx::FloatPoint> const&)
  186. {
  187. // FIXME
  188. return CommandResult::Continue;
  189. }
  190. CommandResult PaintingCommandExecutorGPU::stroke_path_using_paint_style(Gfx::Path const&, Gfx::PaintStyle const&, float, float, Optional<Gfx::FloatPoint> const&)
  191. {
  192. // FIXME
  193. return CommandResult::Continue;
  194. }
  195. CommandResult PaintingCommandExecutorGPU::draw_ellipse(Gfx::IntRect const&, Color const&, int)
  196. {
  197. // FIXME
  198. return CommandResult::Continue;
  199. }
  200. CommandResult PaintingCommandExecutorGPU::fill_ellipse(Gfx::IntRect const& rect, Color const& color, Gfx::AntiAliasingPainter::BlendMode)
  201. {
  202. auto horizontal_radius = static_cast<float>(rect.width() / 2);
  203. auto vertical_radius = static_cast<float>(rect.height() / 2);
  204. painter().fill_rect_with_rounded_corners(
  205. rect, color,
  206. { horizontal_radius, vertical_radius },
  207. { horizontal_radius, vertical_radius },
  208. { horizontal_radius, vertical_radius },
  209. { horizontal_radius, vertical_radius });
  210. return CommandResult::Continue;
  211. }
  212. CommandResult PaintingCommandExecutorGPU::draw_line(Color const& color, Gfx::IntPoint const& a, Gfx::IntPoint const& b, int thickness, Gfx::Painter::LineStyle, Color const&)
  213. {
  214. // FIXME: Pass line style and alternate color once AccelGfx::Painter supports it
  215. painter().draw_line(a, b, thickness, color);
  216. return CommandResult::Continue;
  217. }
  218. CommandResult PaintingCommandExecutorGPU::draw_signed_distance_field(Gfx::IntRect const&, Color const&, Gfx::GrayscaleBitmap const&, float)
  219. {
  220. // FIXME
  221. return CommandResult::Continue;
  222. }
  223. CommandResult PaintingCommandExecutorGPU::paint_frame(Gfx::IntRect const&, Palette const&, Gfx::FrameStyle)
  224. {
  225. // FIXME
  226. return CommandResult::Continue;
  227. }
  228. CommandResult PaintingCommandExecutorGPU::apply_backdrop_filter(Gfx::IntRect const&, Web::CSS::ResolvedBackdropFilter const&)
  229. {
  230. // FIXME
  231. return CommandResult::Continue;
  232. }
  233. CommandResult PaintingCommandExecutorGPU::draw_rect(Gfx::IntRect const&, Color const&, bool)
  234. {
  235. // FIXME
  236. return CommandResult::Continue;
  237. }
  238. CommandResult PaintingCommandExecutorGPU::paint_radial_gradient(Gfx::IntRect const&, Web::Painting::RadialGradientData const&, Gfx::IntPoint const&, Gfx::IntSize const&)
  239. {
  240. // FIXME
  241. return CommandResult::Continue;
  242. }
  243. CommandResult PaintingCommandExecutorGPU::paint_conic_gradient(Gfx::IntRect const&, Web::Painting::ConicGradientData const&, Gfx::IntPoint const&)
  244. {
  245. // FIXME
  246. return CommandResult::Continue;
  247. }
  248. CommandResult PaintingCommandExecutorGPU::draw_triangle_wave(Gfx::IntPoint const&, Gfx::IntPoint const&, Color const&, int, int)
  249. {
  250. // FIXME
  251. return CommandResult::Continue;
  252. }
  253. CommandResult PaintingCommandExecutorGPU::sample_under_corners(u32 id, CornerRadii const& corner_radii, Gfx::IntRect const& border_rect, CornerClip)
  254. {
  255. m_corner_clippers.resize(id + 1);
  256. m_corner_clippers[id] = make<BorderRadiusCornerClipper>();
  257. auto& corner_clipper = *m_corner_clippers[id];
  258. auto const& top_left = corner_radii.top_left;
  259. auto const& top_right = corner_radii.top_right;
  260. auto const& bottom_right = corner_radii.bottom_right;
  261. auto const& bottom_left = corner_radii.bottom_left;
  262. auto sampling_config = calculate_border_radius_sampling_config(corner_radii, border_rect);
  263. auto const& page_locations = sampling_config.page_locations;
  264. auto const& bitmap_locations = sampling_config.bitmap_locations;
  265. auto top_left_corner_size = Gfx::IntSize { top_left.horizontal_radius, top_left.vertical_radius };
  266. auto top_right_corner_size = Gfx::IntSize { top_right.horizontal_radius, top_right.vertical_radius };
  267. auto bottom_right_corner_size = Gfx::IntSize { bottom_right.horizontal_radius, bottom_right.vertical_radius };
  268. auto bottom_left_corner_size = Gfx::IntSize { bottom_left.horizontal_radius, bottom_left.vertical_radius };
  269. corner_clipper.page_top_left_rect = { page_locations.top_left, top_left_corner_size };
  270. corner_clipper.page_top_right_rect = { page_locations.top_right, top_right_corner_size };
  271. corner_clipper.page_bottom_right_rect = { page_locations.bottom_right, bottom_right_corner_size };
  272. corner_clipper.page_bottom_left_rect = { page_locations.bottom_left, bottom_left_corner_size };
  273. corner_clipper.sample_canvas_top_left_rect = { bitmap_locations.top_left, top_left_corner_size };
  274. corner_clipper.sample_canvas_top_right_rect = { bitmap_locations.top_right, top_right_corner_size };
  275. corner_clipper.sample_canvas_bottom_right_rect = { bitmap_locations.bottom_right, bottom_right_corner_size };
  276. corner_clipper.sample_canvas_bottom_left_rect = { bitmap_locations.bottom_left, bottom_left_corner_size };
  277. corner_clipper.corners_sample_canvas = AccelGfx::Canvas::create(sampling_config.corners_bitmap_size);
  278. auto corner_painter = AccelGfx::Painter::create(m_context, *corner_clipper.corners_sample_canvas);
  279. corner_painter->clear(Color::White);
  280. corner_painter->fill_rect_with_rounded_corners(
  281. Gfx::IntRect { { 0, 0 }, sampling_config.corners_bitmap_size },
  282. Color::Transparent,
  283. { static_cast<float>(top_left.horizontal_radius), static_cast<float>(top_left.vertical_radius) },
  284. { static_cast<float>(top_right.horizontal_radius), static_cast<float>(top_right.vertical_radius) },
  285. { static_cast<float>(bottom_right.horizontal_radius), static_cast<float>(bottom_right.vertical_radius) },
  286. { static_cast<float>(bottom_left.horizontal_radius), static_cast<float>(bottom_left.vertical_radius) },
  287. AccelGfx::Painter::BlendingMode::AlphaOverride);
  288. auto const& target_canvas = painter().canvas();
  289. if (!corner_clipper.sample_canvas_top_left_rect.is_empty())
  290. corner_painter->blit_canvas(corner_clipper.sample_canvas_top_left_rect, target_canvas, painter().transform().map(corner_clipper.page_top_left_rect), 1.0f, {}, AccelGfx::Painter::BlendingMode::AlphaPreserve);
  291. if (!corner_clipper.sample_canvas_top_right_rect.is_empty())
  292. corner_painter->blit_canvas(corner_clipper.sample_canvas_top_right_rect, target_canvas, painter().transform().map(corner_clipper.page_top_right_rect), 1.0f, {}, AccelGfx::Painter::BlendingMode::AlphaPreserve);
  293. if (!corner_clipper.sample_canvas_bottom_right_rect.is_empty())
  294. corner_painter->blit_canvas(corner_clipper.sample_canvas_bottom_right_rect, target_canvas, painter().transform().map(corner_clipper.page_bottom_right_rect), 1.0f, {}, AccelGfx::Painter::BlendingMode::AlphaPreserve);
  295. if (!corner_clipper.sample_canvas_bottom_left_rect.is_empty())
  296. corner_painter->blit_canvas(corner_clipper.sample_canvas_bottom_left_rect, target_canvas, painter().transform().map(corner_clipper.page_bottom_left_rect), 1.0f, {}, AccelGfx::Painter::BlendingMode::AlphaPreserve);
  297. return CommandResult::Continue;
  298. }
  299. CommandResult PaintingCommandExecutorGPU::blit_corner_clipping(u32 id)
  300. {
  301. auto const& corner_clipper = *m_corner_clippers[id];
  302. auto const& corner_sample_canvas = *corner_clipper.corners_sample_canvas;
  303. if (!corner_clipper.sample_canvas_top_left_rect.is_empty())
  304. painter().blit_canvas(corner_clipper.page_top_left_rect, corner_sample_canvas, corner_clipper.sample_canvas_top_left_rect);
  305. if (!corner_clipper.sample_canvas_top_right_rect.is_empty())
  306. painter().blit_canvas(corner_clipper.page_top_right_rect, corner_sample_canvas, corner_clipper.sample_canvas_top_right_rect);
  307. if (!corner_clipper.sample_canvas_bottom_right_rect.is_empty())
  308. painter().blit_canvas(corner_clipper.page_bottom_right_rect, corner_sample_canvas, corner_clipper.sample_canvas_bottom_right_rect);
  309. if (!corner_clipper.sample_canvas_bottom_left_rect.is_empty())
  310. painter().blit_canvas(corner_clipper.page_bottom_left_rect, corner_sample_canvas, corner_clipper.sample_canvas_bottom_left_rect);
  311. m_corner_clippers[id].clear();
  312. return CommandResult::Continue;
  313. }
  314. CommandResult PaintingCommandExecutorGPU::paint_borders(DevicePixelRect const& border_rect, CornerRadii const& corner_radii, BordersDataDevicePixels const& borders_data)
  315. {
  316. // FIXME: Add support for corner radiuses
  317. (void)corner_radii;
  318. Gfx::IntRect top_border_rect = {
  319. border_rect.x(),
  320. border_rect.y(),
  321. border_rect.width(),
  322. borders_data.top.width
  323. };
  324. Gfx::IntRect right_border_rect = {
  325. border_rect.x() + (border_rect.width() - borders_data.right.width),
  326. border_rect.y(),
  327. borders_data.right.width,
  328. border_rect.height()
  329. };
  330. Gfx::IntRect bottom_border_rect = {
  331. border_rect.x(),
  332. border_rect.y() + (border_rect.height() - borders_data.bottom.width),
  333. border_rect.width(),
  334. borders_data.bottom.width
  335. };
  336. Gfx::IntRect left_border_rect = {
  337. border_rect.x(),
  338. border_rect.y(),
  339. borders_data.left.width,
  340. border_rect.height()
  341. };
  342. if (borders_data.top.width > 0)
  343. painter().fill_rect(top_border_rect, borders_data.top.color);
  344. if (borders_data.right.width > 0)
  345. painter().fill_rect(right_border_rect, borders_data.right.color);
  346. if (borders_data.bottom.width > 0)
  347. painter().fill_rect(bottom_border_rect, borders_data.bottom.color);
  348. if (borders_data.left.width > 0)
  349. painter().fill_rect(left_border_rect, borders_data.left.color);
  350. return CommandResult::Continue;
  351. }
  352. bool PaintingCommandExecutorGPU::would_be_fully_clipped_by_painter(Gfx::IntRect rect) const
  353. {
  354. auto translation = painter().transform().translation().to_type<int>();
  355. return !painter().clip_rect().intersects(rect.translated(translation));
  356. }
  357. void PaintingCommandExecutorGPU::prepare_glyph_texture(HashMap<Gfx::Font const*, HashTable<u32>> const& unique_glyphs)
  358. {
  359. AccelGfx::GlyphAtlas::the().update(unique_glyphs);
  360. }
  361. void PaintingCommandExecutorGPU::update_immutable_bitmap_texture_cache(HashMap<u32, Gfx::ImmutableBitmap const*>& immutable_bitmaps)
  362. {
  363. painter().update_immutable_bitmap_texture_cache(immutable_bitmaps);
  364. }
  365. }