DisplayListPlayerSkia.cpp 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988
  1. /*
  2. * Copyright (c) 2024, Aliaksandr Kalenik <kalenik.aliaksandr@gmail.com>
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <core/SkBitmap.h>
  7. #include <core/SkBlurTypes.h>
  8. #include <core/SkCanvas.h>
  9. #include <core/SkColorFilter.h>
  10. #include <core/SkFont.h>
  11. #include <core/SkFontMgr.h>
  12. #include <core/SkMaskFilter.h>
  13. #include <core/SkPath.h>
  14. #include <core/SkPathBuilder.h>
  15. #include <core/SkPathEffect.h>
  16. #include <core/SkRRect.h>
  17. #include <core/SkSurface.h>
  18. #include <effects/SkDashPathEffect.h>
  19. #include <effects/SkGradientShader.h>
  20. #include <effects/SkImageFilters.h>
  21. #include <effects/SkRuntimeEffect.h>
  22. #include <gpu/GrDirectContext.h>
  23. #include <gpu/ganesh/SkSurfaceGanesh.h>
  24. #include <pathops/SkPathOps.h>
  25. #include <LibGfx/Font/ScaledFont.h>
  26. #include <LibGfx/PathSkia.h>
  27. #include <LibGfx/SkiaUtils.h>
  28. #include <LibWeb/CSS/ComputedValues.h>
  29. #include <LibWeb/Painting/DisplayListPlayerSkia.h>
  30. #include <LibWeb/Painting/ShadowPainting.h>
  31. namespace Web::Painting {
  32. #ifdef USE_VULKAN
  33. DisplayListPlayerSkia::DisplayListPlayerSkia(Gfx::SkiaBackendContext& context, Gfx::Bitmap& bitmap)
  34. : m_context(context)
  35. {
  36. m_surface = Gfx::PaintingSurface::create_with_size(m_context, bitmap.size(), Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied);
  37. m_flush_context = [&bitmap, surface = m_surface] mutable {
  38. surface->read_into_bitmap(bitmap);
  39. };
  40. }
  41. #endif
  42. #ifdef AK_OS_MACOS
  43. DisplayListPlayerSkia::DisplayListPlayerSkia(Gfx::SkiaBackendContext& context, NonnullRefPtr<Gfx::PaintingSurface> surface)
  44. : m_context(context)
  45. , m_surface(move(surface))
  46. {
  47. }
  48. #endif
  49. DisplayListPlayerSkia::DisplayListPlayerSkia(Gfx::Bitmap& bitmap)
  50. {
  51. m_surface = Gfx::PaintingSurface::wrap_bitmap(bitmap);
  52. }
  53. DisplayListPlayerSkia::~DisplayListPlayerSkia()
  54. {
  55. m_surface->flush();
  56. if (m_flush_context) {
  57. m_flush_context();
  58. }
  59. }
  60. static SkRRect to_skia_rrect(auto const& rect, CornerRadii const& corner_radii)
  61. {
  62. SkRRect rrect;
  63. SkVector radii[4];
  64. radii[0].set(corner_radii.top_left.horizontal_radius, corner_radii.top_left.vertical_radius);
  65. radii[1].set(corner_radii.top_right.horizontal_radius, corner_radii.top_right.vertical_radius);
  66. radii[2].set(corner_radii.bottom_right.horizontal_radius, corner_radii.bottom_right.vertical_radius);
  67. radii[3].set(corner_radii.bottom_left.horizontal_radius, corner_radii.bottom_left.vertical_radius);
  68. rrect.setRectRadii(to_skia_rect(rect), radii);
  69. return rrect;
  70. }
  71. static SkMatrix to_skia_matrix(Gfx::AffineTransform const& affine_transform)
  72. {
  73. SkScalar affine[6];
  74. affine[0] = affine_transform.a();
  75. affine[1] = affine_transform.b();
  76. affine[2] = affine_transform.c();
  77. affine[3] = affine_transform.d();
  78. affine[4] = affine_transform.e();
  79. affine[5] = affine_transform.f();
  80. SkMatrix matrix;
  81. matrix.setAffine(affine);
  82. return matrix;
  83. }
  84. Gfx::PaintingSurface& DisplayListPlayerSkia::surface() const
  85. {
  86. return *m_surface;
  87. }
  88. void DisplayListPlayerSkia::draw_glyph_run(DrawGlyphRun const& command)
  89. {
  90. auto const& gfx_font = static_cast<Gfx::ScaledFont const&>(command.glyph_run->font());
  91. auto sk_font = gfx_font.skia_font(command.scale);
  92. auto glyph_count = command.glyph_run->glyphs().size();
  93. Vector<SkGlyphID> glyphs;
  94. glyphs.ensure_capacity(glyph_count);
  95. Vector<SkPoint> positions;
  96. positions.ensure_capacity(glyph_count);
  97. auto font_ascent = gfx_font.pixel_metrics().ascent;
  98. for (auto const& glyph : command.glyph_run->glyphs()) {
  99. auto transformed_glyph = glyph;
  100. transformed_glyph.position.set_y(glyph.position.y() + font_ascent);
  101. transformed_glyph.position = transformed_glyph.position.scaled(command.scale);
  102. auto const& point = transformed_glyph.position;
  103. glyphs.append(transformed_glyph.glyph_id);
  104. positions.append(to_skia_point(point));
  105. }
  106. SkPaint paint;
  107. paint.setColor(to_skia_color(command.color));
  108. auto& canvas = surface().canvas();
  109. switch (command.orientation) {
  110. case Gfx::Orientation::Horizontal:
  111. canvas.drawGlyphs(glyphs.size(), glyphs.data(), positions.data(), to_skia_point(command.translation), sk_font, paint);
  112. break;
  113. case Gfx::Orientation::Vertical:
  114. canvas.save();
  115. canvas.translate(command.rect.width(), 0);
  116. canvas.rotate(90, command.rect.top_left().x(), command.rect.top_left().y());
  117. canvas.drawGlyphs(glyphs.size(), glyphs.data(), positions.data(), to_skia_point(command.translation), sk_font, paint);
  118. canvas.restore();
  119. break;
  120. }
  121. }
  122. void DisplayListPlayerSkia::fill_rect(FillRect const& command)
  123. {
  124. auto const& rect = command.rect;
  125. auto& canvas = surface().canvas();
  126. SkPaint paint;
  127. paint.setColor(to_skia_color(command.color));
  128. canvas.drawRect(to_skia_rect(rect), paint);
  129. }
  130. void DisplayListPlayerSkia::draw_painting_surface(DrawPaintingSurface const& command)
  131. {
  132. auto src_rect = to_skia_rect(command.src_rect);
  133. auto dst_rect = to_skia_rect(command.dst_rect);
  134. auto& sk_surface = command.surface->sk_surface();
  135. auto& canvas = surface().canvas();
  136. auto image = sk_surface.makeImageSnapshot();
  137. SkPaint paint;
  138. canvas.drawImageRect(image, src_rect, dst_rect, to_skia_sampling_options(command.scaling_mode), &paint, SkCanvas::kStrict_SrcRectConstraint);
  139. }
  140. void DisplayListPlayerSkia::draw_scaled_immutable_bitmap(DrawScaledImmutableBitmap const& command)
  141. {
  142. auto src_rect = to_skia_rect(command.src_rect);
  143. auto dst_rect = to_skia_rect(command.dst_rect);
  144. auto& canvas = surface().canvas();
  145. SkPaint paint;
  146. canvas.drawImageRect(command.bitmap->sk_image(), src_rect, dst_rect, to_skia_sampling_options(command.scaling_mode), &paint, SkCanvas::kStrict_SrcRectConstraint);
  147. }
  148. void DisplayListPlayerSkia::draw_repeated_immutable_bitmap(DrawRepeatedImmutableBitmap const& command)
  149. {
  150. SkMatrix matrix;
  151. auto dst_rect = command.dst_rect.to_type<float>();
  152. auto src_size = command.bitmap->size().to_type<float>();
  153. matrix.setScale(dst_rect.width() / src_size.width(), dst_rect.height() / src_size.height());
  154. matrix.postTranslate(dst_rect.x(), dst_rect.y());
  155. auto sampling_options = to_skia_sampling_options(command.scaling_mode);
  156. auto tile_mode_x = command.repeat.x ? SkTileMode::kRepeat : SkTileMode::kDecal;
  157. auto tile_mode_y = command.repeat.y ? SkTileMode::kRepeat : SkTileMode::kDecal;
  158. auto shader = command.bitmap->sk_image()->makeShader(tile_mode_x, tile_mode_y, sampling_options, matrix);
  159. SkPaint paint;
  160. paint.setShader(shader);
  161. auto& canvas = surface().canvas();
  162. canvas.drawPaint(paint);
  163. }
  164. void DisplayListPlayerSkia::add_clip_rect(AddClipRect const& command)
  165. {
  166. auto& canvas = surface().canvas();
  167. auto const& rect = command.rect;
  168. canvas.clipRect(to_skia_rect(rect));
  169. }
  170. void DisplayListPlayerSkia::save(Save const&)
  171. {
  172. auto& canvas = surface().canvas();
  173. canvas.save();
  174. }
  175. void DisplayListPlayerSkia::restore(Restore const&)
  176. {
  177. auto& canvas = surface().canvas();
  178. canvas.restore();
  179. }
  180. void DisplayListPlayerSkia::translate(Translate const& command)
  181. {
  182. auto& canvas = surface().canvas();
  183. canvas.translate(command.delta.x(), command.delta.y());
  184. }
  185. void DisplayListPlayerSkia::push_stacking_context(PushStackingContext const& command)
  186. {
  187. auto& canvas = surface().canvas();
  188. auto affine_transform = Gfx::extract_2d_affine_transform(command.transform.matrix);
  189. auto new_transform = Gfx::AffineTransform {}
  190. .translate(command.transform.origin)
  191. .multiply(affine_transform)
  192. .translate(-command.transform.origin);
  193. auto matrix = to_skia_matrix(new_transform);
  194. if (command.opacity < 1) {
  195. auto source_paintable_rect = to_skia_rect(command.source_paintable_rect);
  196. SkRect dest;
  197. matrix.mapRect(&dest, source_paintable_rect);
  198. canvas.saveLayerAlphaf(&dest, command.opacity);
  199. } else {
  200. canvas.save();
  201. }
  202. if (command.clip_path.has_value())
  203. canvas.clipPath(to_skia_path(command.clip_path.value()), true);
  204. canvas.concat(matrix);
  205. }
  206. void DisplayListPlayerSkia::pop_stacking_context(PopStackingContext const&)
  207. {
  208. surface().canvas().restore();
  209. }
  210. static ColorStopList replace_transition_hints_with_normal_color_stops(ColorStopList const& color_stop_list)
  211. {
  212. ColorStopList stops_with_replaced_transition_hints;
  213. auto const& first_color_stop = color_stop_list.first();
  214. // First color stop in the list should never have transition hint value
  215. VERIFY(!first_color_stop.transition_hint.has_value());
  216. stops_with_replaced_transition_hints.empend(first_color_stop.color, first_color_stop.position);
  217. // This loop replaces transition hints with five regular points, calculated using the
  218. // formula defined in the spec. After rendering using linear interpolation, this will
  219. // produce a result close enough to that obtained if the color of each point were calculated
  220. // using the non-linear formula from the spec.
  221. for (size_t i = 1; i < color_stop_list.size(); i++) {
  222. auto const& color_stop = color_stop_list[i];
  223. if (!color_stop.transition_hint.has_value()) {
  224. stops_with_replaced_transition_hints.empend(color_stop.color, color_stop.position);
  225. continue;
  226. }
  227. auto const& previous_color_stop = color_stop_list[i - 1];
  228. auto const& next_color_stop = color_stop_list[i];
  229. auto distance_between_stops = next_color_stop.position - previous_color_stop.position;
  230. auto transition_hint = color_stop.transition_hint.value();
  231. Array transition_hint_relative_sampling_positions {
  232. transition_hint * 0.33f,
  233. transition_hint * 0.66f,
  234. transition_hint,
  235. transition_hint + (1.f - transition_hint) * 0.33f,
  236. transition_hint + (1.f - transition_hint) * 0.66f,
  237. };
  238. for (auto const& transition_hint_relative_sampling_position : transition_hint_relative_sampling_positions) {
  239. auto position = previous_color_stop.position + transition_hint_relative_sampling_position * distance_between_stops;
  240. auto value = color_stop_step(previous_color_stop, next_color_stop, position);
  241. auto color = previous_color_stop.color.interpolate(next_color_stop.color, value);
  242. stops_with_replaced_transition_hints.empend(color, position);
  243. }
  244. stops_with_replaced_transition_hints.empend(color_stop.color, color_stop.position);
  245. }
  246. return stops_with_replaced_transition_hints;
  247. }
  248. static ColorStopList expand_repeat_length(ColorStopList const& color_stop_list, float repeat_length)
  249. {
  250. // https://drafts.csswg.org/css-images/#repeating-gradients
  251. // When rendered, however, the color-stops are repeated infinitely in both directions, with their
  252. // positions shifted by multiples of the difference between the last specified color-stop’s position
  253. // and the first specified color-stop’s position. For example, repeating-linear-gradient(red 10px, blue 50px)
  254. // is equivalent to linear-gradient(..., red -30px, blue 10px, red 10px, blue 50px, red 50px, blue 90px, ...).
  255. auto first_stop_position = color_stop_list.first().position;
  256. int const negative_repeat_count = AK::ceil(first_stop_position / repeat_length);
  257. int const positive_repeat_count = AK::ceil((1.0f - first_stop_position) / repeat_length);
  258. ColorStopList color_stop_list_with_expanded_repeat = color_stop_list;
  259. auto get_color_between_stops = [](float position, auto const& current_stop, auto const& previous_stop) {
  260. auto distance_between_stops = current_stop.position - previous_stop.position;
  261. auto percentage = (position - previous_stop.position) / distance_between_stops;
  262. return previous_stop.color.interpolate(current_stop.color, percentage);
  263. };
  264. for (auto repeat_count = 1; repeat_count <= negative_repeat_count; repeat_count++) {
  265. for (auto stop : color_stop_list.in_reverse()) {
  266. stop.position += repeat_length * static_cast<float>(-repeat_count);
  267. if (stop.position < 0) {
  268. stop.color = get_color_between_stops(0.0f, stop, color_stop_list_with_expanded_repeat.first());
  269. color_stop_list_with_expanded_repeat.prepend(stop);
  270. break;
  271. }
  272. color_stop_list_with_expanded_repeat.prepend(stop);
  273. }
  274. }
  275. for (auto repeat_count = 0; repeat_count < positive_repeat_count; repeat_count++) {
  276. for (auto stop : color_stop_list) {
  277. stop.position += repeat_length * static_cast<float>(repeat_count);
  278. if (stop.position > 1) {
  279. stop.color = get_color_between_stops(1.0f, stop, color_stop_list_with_expanded_repeat.last());
  280. color_stop_list_with_expanded_repeat.append(stop);
  281. break;
  282. }
  283. color_stop_list_with_expanded_repeat.append(stop);
  284. }
  285. }
  286. return color_stop_list_with_expanded_repeat;
  287. }
  288. void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
  289. {
  290. auto const& linear_gradient_data = command.linear_gradient_data;
  291. auto color_stop_list = linear_gradient_data.color_stops.list;
  292. auto const& repeat_length = linear_gradient_data.color_stops.repeat_length;
  293. VERIFY(!color_stop_list.is_empty());
  294. if (repeat_length.has_value())
  295. color_stop_list = expand_repeat_length(color_stop_list, *repeat_length);
  296. auto stops_with_replaced_transition_hints = replace_transition_hints_with_normal_color_stops(color_stop_list);
  297. Vector<SkColor4f> colors;
  298. Vector<SkScalar> positions;
  299. for (size_t stop_index = 0; stop_index < stops_with_replaced_transition_hints.size(); stop_index++) {
  300. auto const& stop = stops_with_replaced_transition_hints[stop_index];
  301. if (stop_index > 0 && stop == stops_with_replaced_transition_hints[stop_index - 1])
  302. continue;
  303. colors.append(to_skia_color4f(stop.color));
  304. positions.append(stop.position);
  305. }
  306. auto const& rect = command.gradient_rect;
  307. auto length = calculate_gradient_length<int>(rect.size(), linear_gradient_data.gradient_angle);
  308. auto bottom = rect.center().translated(0, -length / 2);
  309. auto top = rect.center().translated(0, length / 2);
  310. Array points {
  311. to_skia_point(top),
  312. to_skia_point(bottom),
  313. };
  314. auto center = to_skia_rect(rect).center();
  315. SkMatrix matrix;
  316. matrix.setRotate(linear_gradient_data.gradient_angle, center.x(), center.y());
  317. auto color_space = SkColorSpace::MakeSRGB();
  318. SkGradientShader::Interpolation interpolation = {};
  319. interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
  320. interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
  321. auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kClamp, interpolation, &matrix);
  322. SkPaint paint;
  323. paint.setShader(shader);
  324. surface().canvas().drawRect(to_skia_rect(rect), paint);
  325. }
  326. static void add_spread_distance_to_border_radius(int& border_radius, int spread_distance)
  327. {
  328. if (border_radius == 0 || spread_distance == 0)
  329. return;
  330. // https://drafts.csswg.org/css-backgrounds/#shadow-shape
  331. // To preserve the box’s shape when spread is applied, the corner radii of the shadow are also increased (decreased,
  332. // for inner shadows) from the border-box (padding-box) radii by adding (subtracting) the spread distance (and flooring
  333. // at zero). However, in order to create a sharper corner when the border radius is small (and thus ensure continuity
  334. // between round and sharp corners), when the border radius is less than the spread distance (or in the case of an inner
  335. // shadow, less than the absolute value of a negative spread distance), the spread distance is first multiplied by the
  336. // proportion 1 + (r-1)^3, where r is the ratio of the border radius to the spread distance, in calculating the corner
  337. // radii of the spread shadow shape.
  338. if (border_radius > AK::abs(spread_distance)) {
  339. border_radius += spread_distance;
  340. } else {
  341. auto r = (float)border_radius / AK::abs(spread_distance);
  342. border_radius += spread_distance * (1 + AK::pow(r - 1, 3.0f));
  343. }
  344. }
  345. void DisplayListPlayerSkia::paint_outer_box_shadow(PaintOuterBoxShadow const& command)
  346. {
  347. auto const& outer_box_shadow_params = command.box_shadow_params;
  348. auto const& color = outer_box_shadow_params.color;
  349. auto const& spread_distance = outer_box_shadow_params.spread_distance;
  350. auto const& blur_radius = outer_box_shadow_params.blur_radius;
  351. auto content_rrect = to_skia_rrect(outer_box_shadow_params.device_content_rect, outer_box_shadow_params.corner_radii);
  352. auto shadow_rect = outer_box_shadow_params.device_content_rect;
  353. shadow_rect.inflate(spread_distance, spread_distance, spread_distance, spread_distance);
  354. auto offset_x = outer_box_shadow_params.offset_x;
  355. auto offset_y = outer_box_shadow_params.offset_y;
  356. shadow_rect.translate_by(offset_x, offset_y);
  357. auto add_spread_distance_to_corner_radius = [&](auto& corner_radius) {
  358. add_spread_distance_to_border_radius(corner_radius.horizontal_radius, spread_distance);
  359. add_spread_distance_to_border_radius(corner_radius.vertical_radius, spread_distance);
  360. };
  361. auto corner_radii = outer_box_shadow_params.corner_radii;
  362. add_spread_distance_to_corner_radius(corner_radii.top_left);
  363. add_spread_distance_to_corner_radius(corner_radii.top_right);
  364. add_spread_distance_to_corner_radius(corner_radii.bottom_right);
  365. add_spread_distance_to_corner_radius(corner_radii.bottom_left);
  366. auto& canvas = surface().canvas();
  367. canvas.save();
  368. canvas.clipRRect(content_rrect, SkClipOp::kDifference, true);
  369. SkPaint paint;
  370. paint.setAntiAlias(true);
  371. paint.setColor(to_skia_color(color));
  372. paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, blur_radius / 2));
  373. auto shadow_rounded_rect = to_skia_rrect(shadow_rect, corner_radii);
  374. canvas.drawRRect(shadow_rounded_rect, paint);
  375. canvas.restore();
  376. }
  377. void DisplayListPlayerSkia::paint_inner_box_shadow(PaintInnerBoxShadow const& command)
  378. {
  379. auto const& outer_box_shadow_params = command.box_shadow_params;
  380. auto color = outer_box_shadow_params.color;
  381. auto device_content_rect = outer_box_shadow_params.device_content_rect;
  382. auto offset_x = outer_box_shadow_params.offset_x;
  383. auto offset_y = outer_box_shadow_params.offset_y;
  384. auto blur_radius = outer_box_shadow_params.blur_radius;
  385. auto spread_distance = outer_box_shadow_params.spread_distance;
  386. auto const& corner_radii = outer_box_shadow_params.corner_radii;
  387. auto outer_shadow_rect = device_content_rect.translated({ offset_x, offset_y });
  388. auto inner_shadow_rect = outer_shadow_rect.inflated(-spread_distance, -spread_distance, -spread_distance, -spread_distance);
  389. outer_shadow_rect.inflate(
  390. blur_radius + offset_y,
  391. blur_radius + abs(offset_x),
  392. blur_radius + abs(offset_y),
  393. blur_radius + offset_x);
  394. auto inner_rect_corner_radii = corner_radii;
  395. auto add_spread_distance_to_corner_radius = [&](auto& corner_radius) {
  396. add_spread_distance_to_border_radius(corner_radius.horizontal_radius, -spread_distance);
  397. add_spread_distance_to_border_radius(corner_radius.vertical_radius, -spread_distance);
  398. };
  399. add_spread_distance_to_corner_radius(inner_rect_corner_radii.top_left);
  400. add_spread_distance_to_corner_radius(inner_rect_corner_radii.top_right);
  401. add_spread_distance_to_corner_radius(inner_rect_corner_radii.bottom_right);
  402. add_spread_distance_to_corner_radius(inner_rect_corner_radii.bottom_left);
  403. auto outer_rect = to_skia_rrect(outer_shadow_rect, corner_radii);
  404. auto inner_rect = to_skia_rrect(inner_shadow_rect, inner_rect_corner_radii);
  405. SkPath outer_path;
  406. outer_path.addRRect(outer_rect);
  407. SkPath inner_path;
  408. inner_path.addRRect(inner_rect);
  409. SkPath result_path;
  410. if (!Op(outer_path, inner_path, SkPathOp::kDifference_SkPathOp, &result_path)) {
  411. VERIFY_NOT_REACHED();
  412. }
  413. auto& canvas = surface().canvas();
  414. SkPaint path_paint;
  415. path_paint.setAntiAlias(true);
  416. path_paint.setColor(to_skia_color(color));
  417. path_paint.setMaskFilter(SkMaskFilter::MakeBlur(kNormal_SkBlurStyle, blur_radius / 2));
  418. canvas.save();
  419. canvas.clipRRect(to_skia_rrect(device_content_rect, corner_radii), true);
  420. canvas.drawPath(result_path, path_paint);
  421. canvas.restore();
  422. }
  423. void DisplayListPlayerSkia::paint_text_shadow(PaintTextShadow const& command)
  424. {
  425. auto& canvas = surface().canvas();
  426. auto blur_image_filter = SkImageFilters::Blur(command.blur_radius / 2, command.blur_radius / 2, nullptr);
  427. SkPaint blur_paint;
  428. blur_paint.setImageFilter(blur_image_filter);
  429. canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, &blur_paint, nullptr, 0));
  430. draw_glyph_run({
  431. .glyph_run = command.glyph_run,
  432. .scale = command.glyph_run_scale,
  433. .rect = command.text_rect,
  434. .translation = command.draw_location + command.text_rect.location().to_type<float>(),
  435. .color = command.color,
  436. });
  437. canvas.restore();
  438. }
  439. void DisplayListPlayerSkia::fill_rect_with_rounded_corners(FillRectWithRoundedCorners const& command)
  440. {
  441. auto const& rect = command.rect;
  442. auto& canvas = surface().canvas();
  443. SkPaint paint;
  444. paint.setColor(to_skia_color(command.color));
  445. paint.setAntiAlias(true);
  446. auto rounded_rect = to_skia_rrect(rect, command.corner_radii);
  447. canvas.drawRRect(rounded_rect, paint);
  448. }
  449. void DisplayListPlayerSkia::fill_path_using_color(FillPathUsingColor const& command)
  450. {
  451. auto& canvas = surface().canvas();
  452. SkPaint paint;
  453. paint.setAntiAlias(true);
  454. paint.setColor(to_skia_color(command.color));
  455. auto path = to_skia_path(command.path);
  456. path.setFillType(to_skia_path_fill_type(command.winding_rule));
  457. path.offset(command.aa_translation.x(), command.aa_translation.y());
  458. canvas.drawPath(path, paint);
  459. }
  460. static SkTileMode to_skia_tile_mode(SVGLinearGradientPaintStyle::SpreadMethod spread_method)
  461. {
  462. switch (spread_method) {
  463. case SVGLinearGradientPaintStyle::SpreadMethod::Pad:
  464. return SkTileMode::kClamp;
  465. case SVGLinearGradientPaintStyle::SpreadMethod::Reflect:
  466. return SkTileMode::kMirror;
  467. case SVGLinearGradientPaintStyle::SpreadMethod::Repeat:
  468. return SkTileMode::kRepeat;
  469. default:
  470. VERIFY_NOT_REACHED();
  471. }
  472. }
  473. static SkPaint paint_style_to_skia_paint(Painting::SVGGradientPaintStyle const& paint_style, Gfx::FloatRect bounding_rect)
  474. {
  475. SkPaint paint;
  476. auto const& color_stops = paint_style.color_stops();
  477. Vector<SkColor> colors;
  478. colors.ensure_capacity(color_stops.size());
  479. Vector<SkScalar> positions;
  480. positions.ensure_capacity(color_stops.size());
  481. for (auto const& color_stop : color_stops) {
  482. colors.append(to_skia_color(color_stop.color));
  483. positions.append(color_stop.position);
  484. }
  485. SkMatrix matrix;
  486. matrix.setTranslate(bounding_rect.x(), bounding_rect.y());
  487. if (auto gradient_transform = paint_style.gradient_transform(); gradient_transform.has_value())
  488. matrix = matrix * to_skia_matrix(gradient_transform.value());
  489. auto tile_mode = to_skia_tile_mode(paint_style.spread_method());
  490. sk_sp<SkShader> shader;
  491. if (is<SVGLinearGradientPaintStyle>(paint_style)) {
  492. auto const& linear_gradient_paint_style = static_cast<SVGLinearGradientPaintStyle const&>(paint_style);
  493. Array points {
  494. to_skia_point(linear_gradient_paint_style.start_point()),
  495. to_skia_point(linear_gradient_paint_style.end_point()),
  496. };
  497. shader = SkGradientShader::MakeLinear(points.data(), colors.data(), positions.data(), color_stops.size(), tile_mode, 0, &matrix);
  498. } else if (is<SVGRadialGradientPaintStyle>(paint_style)) {
  499. auto const& radial_gradient_paint_style = static_cast<SVGRadialGradientPaintStyle const&>(paint_style);
  500. auto start_center = to_skia_point(radial_gradient_paint_style.start_center());
  501. auto end_center = to_skia_point(radial_gradient_paint_style.end_center());
  502. auto start_radius = radial_gradient_paint_style.start_radius();
  503. auto end_radius = radial_gradient_paint_style.end_radius();
  504. shader = SkGradientShader::MakeTwoPointConical(start_center, start_radius, end_center, end_radius, colors.data(), positions.data(), color_stops.size(), tile_mode, 0, &matrix);
  505. }
  506. paint.setShader(shader);
  507. return paint;
  508. }
  509. void DisplayListPlayerSkia::fill_path_using_paint_style(FillPathUsingPaintStyle const& command)
  510. {
  511. auto path = to_skia_path(command.path);
  512. path.offset(command.aa_translation.x(), command.aa_translation.y());
  513. path.setFillType(to_skia_path_fill_type(command.winding_rule));
  514. auto paint = paint_style_to_skia_paint(*command.paint_style, command.bounding_rect().to_type<float>());
  515. paint.setAntiAlias(true);
  516. paint.setAlphaf(command.opacity);
  517. surface().canvas().drawPath(path, paint);
  518. }
  519. void DisplayListPlayerSkia::stroke_path_using_color(StrokePathUsingColor const& command)
  520. {
  521. // Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
  522. if (!command.thickness)
  523. return;
  524. // FIXME: Use .cap_style, .join_style, .miter_limit, .dash_array, .dash_offset.
  525. auto& canvas = surface().canvas();
  526. SkPaint paint;
  527. paint.setAntiAlias(true);
  528. paint.setStyle(SkPaint::kStroke_Style);
  529. paint.setStrokeWidth(command.thickness);
  530. paint.setColor(to_skia_color(command.color));
  531. auto path = to_skia_path(command.path);
  532. path.offset(command.aa_translation.x(), command.aa_translation.y());
  533. canvas.drawPath(path, paint);
  534. }
  535. void DisplayListPlayerSkia::stroke_path_using_paint_style(StrokePathUsingPaintStyle const& command)
  536. {
  537. // Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
  538. if (!command.thickness)
  539. return;
  540. // FIXME: Use .cap_style, .join_style, .miter_limit, .dash_array, .dash_offset.
  541. auto path = to_skia_path(command.path);
  542. path.offset(command.aa_translation.x(), command.aa_translation.y());
  543. auto paint = paint_style_to_skia_paint(*command.paint_style, command.bounding_rect().to_type<float>());
  544. paint.setAntiAlias(true);
  545. paint.setAlphaf(command.opacity);
  546. paint.setStyle(SkPaint::Style::kStroke_Style);
  547. paint.setStrokeWidth(command.thickness);
  548. surface().canvas().drawPath(path, paint);
  549. }
  550. void DisplayListPlayerSkia::draw_ellipse(DrawEllipse const& command)
  551. {
  552. // Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
  553. if (!command.thickness)
  554. return;
  555. auto const& rect = command.rect;
  556. auto& canvas = surface().canvas();
  557. SkPaint paint;
  558. paint.setAntiAlias(true);
  559. paint.setStyle(SkPaint::kStroke_Style);
  560. paint.setStrokeWidth(command.thickness);
  561. paint.setColor(to_skia_color(command.color));
  562. canvas.drawOval(to_skia_rect(rect), paint);
  563. }
  564. void DisplayListPlayerSkia::fill_ellipse(FillEllipse const& command)
  565. {
  566. auto const& rect = command.rect;
  567. auto& canvas = surface().canvas();
  568. SkPaint paint;
  569. paint.setAntiAlias(true);
  570. paint.setColor(to_skia_color(command.color));
  571. canvas.drawOval(to_skia_rect(rect), paint);
  572. }
  573. void DisplayListPlayerSkia::draw_line(DrawLine const& command)
  574. {
  575. // Skia treats zero thickness as a special case and will draw a hairline, while we want to draw nothing.
  576. if (!command.thickness)
  577. return;
  578. auto from = to_skia_point(command.from);
  579. auto to = to_skia_point(command.to);
  580. auto& canvas = surface().canvas();
  581. SkPaint paint;
  582. paint.setAntiAlias(true);
  583. paint.setStrokeWidth(command.thickness);
  584. paint.setColor(to_skia_color(command.color));
  585. switch (command.style) {
  586. case Gfx::LineStyle::Solid:
  587. break;
  588. case Gfx::LineStyle::Dotted: {
  589. auto length = command.to.distance_from(command.from);
  590. auto dot_count = floor(length / (static_cast<float>(command.thickness) * 2));
  591. auto interval = length / dot_count;
  592. SkScalar intervals[] = { 0, interval };
  593. paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
  594. paint.setStrokeCap(SkPaint::Cap::kRound_Cap);
  595. // NOTE: As Skia doesn't render a dot exactly at the end of a line, we need
  596. // to extend it by less then an interval.
  597. auto direction = to - from;
  598. direction.normalize();
  599. to += direction * (interval / 2.0f);
  600. break;
  601. }
  602. case Gfx::LineStyle::Dashed: {
  603. auto length = command.to.distance_from(command.from) + command.thickness;
  604. auto dash_count = floor(length / static_cast<float>(command.thickness) / 4) * 2 + 1;
  605. auto interval = length / dash_count;
  606. SkScalar intervals[] = { interval, interval };
  607. paint.setPathEffect(SkDashPathEffect::Make(intervals, 2, 0));
  608. auto direction = to - from;
  609. direction.normalize();
  610. from -= direction * (command.thickness / 2.0f);
  611. to += direction * (command.thickness / 2.0f);
  612. break;
  613. }
  614. }
  615. canvas.drawLine(from, to, paint);
  616. }
  617. void DisplayListPlayerSkia::apply_backdrop_filter(ApplyBackdropFilter const& command)
  618. {
  619. auto& canvas = surface().canvas();
  620. auto rect = to_skia_rect(command.backdrop_region);
  621. canvas.save();
  622. canvas.clipRect(rect);
  623. ScopeGuard guard = [&] { canvas.restore(); };
  624. for (auto const& filter : command.backdrop_filter) {
  625. auto image_filter = to_skia_image_filter(filter);
  626. canvas.saveLayer(SkCanvas::SaveLayerRec(nullptr, nullptr, image_filter.get(), 0));
  627. canvas.restore();
  628. }
  629. }
  630. void DisplayListPlayerSkia::draw_rect(DrawRect const& command)
  631. {
  632. auto const& rect = command.rect;
  633. auto& canvas = surface().canvas();
  634. SkPaint paint;
  635. paint.setAntiAlias(true);
  636. paint.setStyle(SkPaint::kStroke_Style);
  637. paint.setStrokeWidth(1);
  638. paint.setColor(to_skia_color(command.color));
  639. canvas.drawRect(to_skia_rect(rect), paint);
  640. }
  641. void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& command)
  642. {
  643. auto const& radial_gradient_data = command.radial_gradient_data;
  644. auto color_stop_list = radial_gradient_data.color_stops.list;
  645. VERIFY(!color_stop_list.is_empty());
  646. auto const& repeat_length = radial_gradient_data.color_stops.repeat_length;
  647. if (repeat_length.has_value())
  648. color_stop_list = expand_repeat_length(color_stop_list, repeat_length.value());
  649. auto stops_with_replaced_transition_hints = replace_transition_hints_with_normal_color_stops(color_stop_list);
  650. Vector<SkColor4f> colors;
  651. Vector<SkScalar> positions;
  652. for (size_t stop_index = 0; stop_index < stops_with_replaced_transition_hints.size(); stop_index++) {
  653. auto const& stop = stops_with_replaced_transition_hints[stop_index];
  654. if (stop_index > 0 && stop == stops_with_replaced_transition_hints[stop_index - 1])
  655. continue;
  656. colors.append(to_skia_color4f(stop.color));
  657. positions.append(stop.position);
  658. }
  659. auto const& rect = command.rect;
  660. auto center = to_skia_point(command.center.translated(command.rect.location()));
  661. auto const size = command.size.to_type<float>();
  662. SkMatrix matrix;
  663. // Skia does not support specifying of horizontal and vertical radius's separately,
  664. // so instead we apply scale matrix
  665. matrix.setScale(size.width() / size.height(), 1.0f, center.x(), center.y());
  666. SkTileMode tile_mode = SkTileMode::kClamp;
  667. if (repeat_length.has_value())
  668. tile_mode = SkTileMode::kRepeat;
  669. auto color_space = SkColorSpace::MakeSRGB();
  670. SkGradientShader::Interpolation interpolation = {};
  671. interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
  672. interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
  673. auto shader = SkGradientShader::MakeRadial(center, size.height(), colors.data(), color_space, positions.data(), positions.size(), tile_mode, interpolation, &matrix);
  674. SkPaint paint;
  675. paint.setAntiAlias(true);
  676. paint.setShader(shader);
  677. surface().canvas().drawRect(to_skia_rect(rect), paint);
  678. }
  679. void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& command)
  680. {
  681. auto const& conic_gradient_data = command.conic_gradient_data;
  682. auto color_stop_list = conic_gradient_data.color_stops.list;
  683. auto const& repeat_length = conic_gradient_data.color_stops.repeat_length;
  684. if (repeat_length.has_value())
  685. color_stop_list = expand_repeat_length(color_stop_list, repeat_length.value());
  686. VERIFY(!color_stop_list.is_empty());
  687. auto stops_with_replaced_transition_hints = replace_transition_hints_with_normal_color_stops(color_stop_list);
  688. Vector<SkColor4f> colors;
  689. Vector<SkScalar> positions;
  690. for (size_t stop_index = 0; stop_index < stops_with_replaced_transition_hints.size(); stop_index++) {
  691. auto const& stop = stops_with_replaced_transition_hints[stop_index];
  692. if (stop_index > 0 && stop == stops_with_replaced_transition_hints[stop_index - 1])
  693. continue;
  694. colors.append(to_skia_color4f(stop.color));
  695. positions.append(stop.position);
  696. }
  697. auto const& rect = command.rect;
  698. auto center = command.position.translated(rect.location()).to_type<float>();
  699. SkMatrix matrix;
  700. matrix.setRotate(-90 + conic_gradient_data.start_angle, center.x(), center.y());
  701. auto color_space = SkColorSpace::MakeSRGB();
  702. SkGradientShader::Interpolation interpolation = {};
  703. interpolation.fColorSpace = SkGradientShader::Interpolation::ColorSpace::kSRGB;
  704. interpolation.fInPremul = SkGradientShader::Interpolation::InPremul::kYes;
  705. auto shader = SkGradientShader::MakeSweep(center.x(), center.y(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kRepeat, 0, 360, interpolation, &matrix);
  706. SkPaint paint;
  707. paint.setAntiAlias(true);
  708. paint.setShader(shader);
  709. surface().canvas().drawRect(to_skia_rect(rect), paint);
  710. }
  711. void DisplayListPlayerSkia::draw_triangle_wave(DrawTriangleWave const&)
  712. {
  713. }
  714. void DisplayListPlayerSkia::add_rounded_rect_clip(AddRoundedRectClip const& command)
  715. {
  716. auto rounded_rect = to_skia_rrect(command.border_rect, command.corner_radii);
  717. auto& canvas = surface().canvas();
  718. auto clip_op = command.corner_clip == CornerClip::Inside ? SkClipOp::kDifference : SkClipOp::kIntersect;
  719. canvas.clipRRect(rounded_rect, clip_op, true);
  720. }
  721. void DisplayListPlayerSkia::add_mask(AddMask const& command)
  722. {
  723. auto const& rect = command.rect;
  724. if (rect.is_empty())
  725. return;
  726. auto mask_surface = Gfx::PaintingSurface::create_with_size(m_context, rect.size(), Gfx::BitmapFormat::BGRA8888, Gfx::AlphaType::Premultiplied);
  727. auto previous_surface = move(m_surface);
  728. m_surface = mask_surface;
  729. execute(*command.display_list);
  730. m_surface = move(previous_surface);
  731. SkMatrix mask_matrix;
  732. mask_matrix.setTranslate(rect.x(), rect.y());
  733. auto image = mask_surface->sk_surface().makeImageSnapshot();
  734. auto shader = image->makeShader(SkSamplingOptions(), mask_matrix);
  735. surface().canvas().clipShader(shader);
  736. }
  737. void DisplayListPlayerSkia::paint_nested_display_list(PaintNestedDisplayList const& command)
  738. {
  739. auto& canvas = surface().canvas();
  740. canvas.translate(command.rect.x(), command.rect.y());
  741. execute(*command.display_list);
  742. }
  743. void DisplayListPlayerSkia::paint_scrollbar(PaintScrollBar const& command)
  744. {
  745. auto rect = to_skia_rect(command.rect);
  746. auto radius = rect.width() / 2;
  747. auto rrect = SkRRect::MakeRectXY(rect, radius, radius);
  748. auto& canvas = surface().canvas();
  749. auto fill_color = Color(Color::NamedColor::DarkGray).with_alpha(128);
  750. SkPaint fill_paint;
  751. fill_paint.setColor(to_skia_color(fill_color));
  752. canvas.drawRRect(rrect, fill_paint);
  753. auto stroke_color = Color(Color::NamedColor::LightGray).with_alpha(128);
  754. SkPaint stroke_paint;
  755. stroke_paint.setStroke(true);
  756. stroke_paint.setStrokeWidth(1);
  757. stroke_paint.setColor(to_skia_color(stroke_color));
  758. canvas.drawRRect(rrect, stroke_paint);
  759. }
  760. void DisplayListPlayerSkia::apply_opacity(ApplyOpacity const& command)
  761. {
  762. auto& canvas = surface().canvas();
  763. SkPaint paint;
  764. paint.setAlphaf(command.opacity);
  765. canvas.saveLayer(nullptr, &paint);
  766. }
  767. void DisplayListPlayerSkia::apply_filters(ApplyFilters const& command)
  768. {
  769. if (command.filter.is_empty()) {
  770. return;
  771. }
  772. sk_sp<SkImageFilter> image_filter;
  773. auto append_filter = [&image_filter](auto new_filter) {
  774. if (image_filter)
  775. image_filter = SkImageFilters::Compose(new_filter, image_filter);
  776. else
  777. image_filter = new_filter;
  778. };
  779. // Apply filters in order
  780. for (auto filter : command.filter) {
  781. append_filter(to_skia_image_filter(filter));
  782. }
  783. SkPaint paint;
  784. paint.setImageFilter(image_filter);
  785. auto& canvas = surface().canvas();
  786. canvas.saveLayer(nullptr, &paint);
  787. }
  788. void DisplayListPlayerSkia::apply_transform(ApplyTransform const& command)
  789. {
  790. auto affine_transform = Gfx::extract_2d_affine_transform(command.matrix);
  791. auto new_transform = Gfx::AffineTransform {}
  792. .translate(command.origin)
  793. .multiply(affine_transform)
  794. .translate(-command.origin);
  795. auto matrix = to_skia_matrix(new_transform);
  796. surface().canvas().concat(matrix);
  797. }
  798. void DisplayListPlayerSkia::apply_mask_bitmap(ApplyMaskBitmap const& command)
  799. {
  800. auto& canvas = surface().canvas();
  801. auto const* mask_image = command.bitmap->sk_image();
  802. char const* sksl_shader = nullptr;
  803. if (command.kind == Gfx::Bitmap::MaskKind::Luminance) {
  804. sksl_shader = R"(
  805. uniform shader mask_image;
  806. half4 main(float2 coord) {
  807. half4 color = mask_image.eval(coord);
  808. half luminance = 0.2126 * color.b + 0.7152 * color.g + 0.0722 * color.r;
  809. return half4(0.0, 0.0, 0.0, color.a * luminance);
  810. }
  811. )";
  812. } else if (command.kind == Gfx::Bitmap::MaskKind::Alpha) {
  813. sksl_shader = R"(
  814. uniform shader mask_image;
  815. half4 main(float2 coord) {
  816. half4 color = mask_image.eval(coord);
  817. return half4(0.0, 0.0, 0.0, color.a);
  818. }
  819. )";
  820. } else {
  821. VERIFY_NOT_REACHED();
  822. }
  823. auto [effect, error] = SkRuntimeEffect::MakeForShader(SkString(sksl_shader));
  824. if (!effect) {
  825. dbgln("SkSL error: {}", error.c_str());
  826. VERIFY_NOT_REACHED();
  827. }
  828. SkMatrix mask_matrix;
  829. auto mask_position = command.origin;
  830. mask_matrix.setTranslate(mask_position.x(), mask_position.y());
  831. SkRuntimeShaderBuilder builder(effect);
  832. builder.child("mask_image") = mask_image->makeShader(SkSamplingOptions(), mask_matrix);
  833. canvas.clipShader(builder.makeShader());
  834. }
  835. bool DisplayListPlayerSkia::would_be_fully_clipped_by_painter(Gfx::IntRect rect) const
  836. {
  837. return surface().canvas().quickReject(to_skia_rect(rect));
  838. }
  839. }