DisplayListPlayerSkia.cpp 46 KB

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