paint_preview_recorder_utils_unittest.cc 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558
  1. // Copyright 2019 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/paint_preview/renderer/paint_preview_recorder_utils.h"
  5. #include <memory>
  6. #include <string>
  7. #include "base/containers/flat_map.h"
  8. #include "base/containers/flat_set.h"
  9. #include "base/files/file.h"
  10. #include "base/files/scoped_temp_dir.h"
  11. #include "base/memory/discardable_memory_allocator.h"
  12. #include "base/memory/read_only_shared_memory_region.h"
  13. #include "base/notreached.h"
  14. #include "base/test/task_environment.h"
  15. #include "base/test/test_discardable_memory_allocator.h"
  16. #include "base/unguessable_token.h"
  17. #include "cc/paint/paint_canvas.h"
  18. #include "cc/paint/paint_flags.h"
  19. #include "cc/paint/paint_image.h"
  20. #include "cc/paint/paint_image_builder.h"
  21. #include "cc/paint/paint_recorder.h"
  22. #include "cc/paint/paint_worklet_input.h"
  23. #include "components/paint_preview/common/file_stream.h"
  24. #include "components/paint_preview/common/mojom/paint_preview_recorder.mojom-shared.h"
  25. #include "components/paint_preview/common/paint_preview_tracker.h"
  26. #include "components/paint_preview/common/serialized_recording.h"
  27. #include "components/paint_preview/common/test_utils.h"
  28. #include "mojo/public/cpp/base/big_buffer.h"
  29. #include "testing/gmock/include/gmock/gmock.h"
  30. #include "testing/gtest/include/gtest/gtest.h"
  31. #include "third_party/abseil-cpp/absl/types/optional.h"
  32. #include "third_party/skia/include/core/SkFont.h"
  33. #include "third_party/skia/include/core/SkRefCnt.h"
  34. #include "third_party/skia/include/core/SkTextBlob.h"
  35. #include "third_party/skia/include/core/SkTypeface.h"
  36. namespace paint_preview {
  37. namespace {
  38. sk_sp<cc::PaintRecord> AddLink(const std::string& link, const SkRect& rect) {
  39. cc::PaintRecorder link_recorder;
  40. cc::PaintCanvas* link_canvas = link_recorder.beginRecording(
  41. rect.x() + rect.width(), rect.y() + rect.height());
  42. link_canvas->Annotate(cc::PaintCanvas::AnnotationType::URL, rect,
  43. SkData::MakeWithCString(link.c_str()));
  44. return link_recorder.finishRecordingAsPicture();
  45. }
  46. } // namespace
  47. TEST(PaintPreviewRecorderUtilsTest, TestParseGlyphs) {
  48. auto typeface = SkTypeface::MakeDefault();
  49. SkFont font(typeface);
  50. std::string unichars_1 = "abc";
  51. std::string unichars_2 = "efg";
  52. auto blob_1 = SkTextBlob::MakeFromString(unichars_1.c_str(), font);
  53. auto blob_2 = SkTextBlob::MakeFromString(unichars_2.c_str(), font);
  54. cc::PaintFlags flags;
  55. cc::PaintRecorder outer_recorder;
  56. cc::PaintCanvas* outer_canvas = outer_recorder.beginRecording(100, 100);
  57. outer_canvas->drawTextBlob(blob_1, 10, 10, flags);
  58. cc::PaintRecorder inner_recorder;
  59. cc::PaintCanvas* inner_canvas = inner_recorder.beginRecording(50, 50);
  60. inner_canvas->drawTextBlob(blob_2, 15, 20, flags);
  61. outer_canvas->drawPicture(inner_recorder.finishRecordingAsPicture());
  62. auto record = outer_recorder.finishRecordingAsPicture();
  63. PaintPreviewTracker tracker(base::UnguessableToken::Create(),
  64. base::UnguessableToken::Create(), true);
  65. PreProcessPaintOpBuffer(record.get(), &tracker);
  66. auto* usage_map = tracker.GetTypefaceUsageMap();
  67. EXPECT_TRUE(usage_map->count(typeface->uniqueID()));
  68. EXPECT_TRUE(
  69. (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('a')));
  70. EXPECT_TRUE(
  71. (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('b')));
  72. EXPECT_TRUE(
  73. (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('c')));
  74. EXPECT_TRUE(
  75. (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('e')));
  76. EXPECT_TRUE(
  77. (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('f')));
  78. EXPECT_TRUE(
  79. (*usage_map)[typeface->uniqueID()]->IsSet(typeface->unicharToGlyph('g')));
  80. }
  81. TEST(PaintPreviewRecorderUtilsTest, TestParseLinks) {
  82. cc::PaintFlags flags;
  83. cc::PaintRecorder outer_recorder;
  84. cc::PaintCanvas* outer_canvas = outer_recorder.beginRecording(500, 500);
  85. outer_canvas->save();
  86. outer_canvas->translate(10, 20);
  87. std::string link_1 = "http://www.foo.com/";
  88. SkRect rect_1 = SkRect::MakeXYWH(10, 20, 30, 40);
  89. outer_canvas->drawPicture(AddLink(link_1, rect_1));
  90. outer_canvas->restore();
  91. outer_canvas->save();
  92. outer_canvas->concat(SkMatrix::Translate(40, 50));
  93. outer_canvas->scale(2, 4);
  94. std::string link_2 = "http://www.bar.com/";
  95. SkRect rect_2 = SkRect::MakeXYWH(1, 2, 3, 4);
  96. outer_canvas->drawPicture(AddLink(link_2, rect_2));
  97. cc::PaintRecorder inner_recorder;
  98. cc::PaintCanvas* inner_canvas = inner_recorder.beginRecording(500, 500);
  99. inner_canvas->rotate(20);
  100. std::string link_3 = "http://www.baz.com/";
  101. SkRect rect_3 = SkRect::MakeXYWH(5, 7, 9, 13);
  102. inner_canvas->drawPicture(AddLink(link_3, rect_3));
  103. outer_canvas->drawPicture(inner_recorder.finishRecordingAsPicture());
  104. outer_canvas->restore();
  105. outer_canvas->save();
  106. outer_canvas->translate(20, 50);
  107. outer_canvas->setMatrix(SkMatrix::Translate(10, 30));
  108. std::string link_4 = "http://www.example.com/";
  109. SkRect rect_4 = SkRect::MakeXYWH(10, 30, 40, 50);
  110. outer_canvas->drawPicture(AddLink(link_4, rect_4));
  111. outer_canvas->restore();
  112. outer_canvas->saveLayer(&rect_1, nullptr);
  113. outer_canvas->saveLayerAlpha(&rect_1, 8);
  114. outer_canvas->restoreToCount(1);
  115. auto record = outer_recorder.finishRecordingAsPicture();
  116. PaintPreviewTracker tracker(base::UnguessableToken::Create(),
  117. base::UnguessableToken::Create(), true);
  118. PreProcessPaintOpBuffer(record.get(), &tracker);
  119. std::vector<mojom::LinkDataPtr> links;
  120. tracker.MoveLinks(&links);
  121. ASSERT_EQ(links.size(), 4U);
  122. EXPECT_EQ(links[0]->url, link_1);
  123. EXPECT_EQ(links[0]->rect.x(), rect_1.x() + 10);
  124. EXPECT_EQ(links[0]->rect.y(), rect_1.y() + 20);
  125. EXPECT_EQ(links[0]->rect.width(), rect_1.width());
  126. EXPECT_EQ(links[0]->rect.height(), rect_1.height());
  127. EXPECT_EQ(links[1]->url, link_2);
  128. EXPECT_EQ(links[1]->rect.x(), rect_2.x() * 2 + 40);
  129. EXPECT_EQ(links[1]->rect.y(), rect_2.y() * 4 + 50);
  130. EXPECT_EQ(links[1]->rect.width(), rect_2.width() * 2);
  131. EXPECT_EQ(links[1]->rect.height(), rect_2.height() * 4);
  132. EXPECT_EQ(links[2]->url, link_3);
  133. EXPECT_EQ(links[2]->rect.x(), 35);
  134. EXPECT_EQ(links[2]->rect.y(), 83);
  135. EXPECT_EQ(links[2]->rect.width(), 25);
  136. EXPECT_EQ(links[2]->rect.height(), 61);
  137. EXPECT_EQ(links[3]->url, link_4);
  138. EXPECT_EQ(links[3]->rect.x(), rect_4.x() + 10);
  139. EXPECT_EQ(links[3]->rect.y(), rect_4.y() + 30);
  140. EXPECT_EQ(links[3]->rect.width(), rect_4.width());
  141. EXPECT_EQ(links[3]->rect.height(), rect_4.height());
  142. }
  143. TEST(PaintPreviewRecorderUtilsTest, TestTransformSubframeRects) {
  144. PaintPreviewTracker tracker(base::UnguessableToken::Create(),
  145. base::UnguessableToken::Create(), true);
  146. gfx::Rect rect(20, 30, 40, 50);
  147. auto subframe_token = base::UnguessableToken::Create();
  148. int old_id = tracker.CreateContentForRemoteFrame(rect, subframe_token);
  149. cc::PaintFlags flags;
  150. cc::PaintRecorder recorder;
  151. cc::PaintCanvas* canvas = recorder.beginRecording(500, 500);
  152. canvas->save();
  153. canvas->translate(10, 20);
  154. canvas->recordCustomData(old_id);
  155. canvas->restore();
  156. auto record = recorder.finishRecordingAsPicture();
  157. auto map = tracker.GetSubframePicsForTesting();
  158. auto it = map.find(old_id);
  159. ASSERT_NE(it, map.end());
  160. auto old_cull_rect = it->second->cullRect();
  161. EXPECT_EQ(rect.x(), old_cull_rect.x());
  162. EXPECT_EQ(rect.y(), old_cull_rect.y());
  163. EXPECT_EQ(rect.width(), old_cull_rect.width());
  164. EXPECT_EQ(rect.height(), old_cull_rect.height());
  165. PreProcessPaintOpBuffer(record.get(), &tracker);
  166. auto* picture_ctx = tracker.GetPictureSerializationContext();
  167. ASSERT_EQ(picture_ctx->content_id_to_transformed_clip.size(), 1U);
  168. auto clip_it = picture_ctx->content_id_to_transformed_clip.find(old_id);
  169. ASSERT_NE(clip_it, picture_ctx->content_id_to_transformed_clip.end());
  170. SkRect new_cull_rect = clip_it->second;
  171. EXPECT_EQ(rect.x() + 10, new_cull_rect.x());
  172. EXPECT_EQ(rect.y() + 20, new_cull_rect.y());
  173. EXPECT_EQ(rect.width(), new_cull_rect.width());
  174. EXPECT_EQ(rect.height(), new_cull_rect.height());
  175. }
  176. class PaintPreviewRecorderUtilsSerializeAsSkPictureTest
  177. : public testing::TestWithParam<RecordingPersistence> {
  178. public:
  179. PaintPreviewRecorderUtilsSerializeAsSkPictureTest()
  180. : tracker(base::UnguessableToken::Create(),
  181. base::UnguessableToken::Create(),
  182. true),
  183. dimensions(100, 100),
  184. recorder() {}
  185. ~PaintPreviewRecorderUtilsSerializeAsSkPictureTest() override = default;
  186. protected:
  187. void SetUp() override {
  188. base::DiscardableMemoryAllocator::SetInstance(&test_allocator_);
  189. canvas = recorder.beginRecording(dimensions.width(), dimensions.width());
  190. cc::PaintFlags flags;
  191. canvas->drawRect(SkRect::MakeWH(dimensions.width(), dimensions.height()),
  192. flags);
  193. }
  194. void TearDown() override {
  195. base::DiscardableMemoryAllocator::SetInstance(nullptr);
  196. }
  197. absl::optional<SerializedRecording> SerializeAsSkPicture(
  198. absl::optional<size_t> max_capture_size,
  199. size_t* serialized_size) {
  200. auto recording = recorder.finishRecordingAsPicture();
  201. PreProcessPaintOpBuffer(recording.get(), &tracker);
  202. auto skp = PaintRecordToSkPicture(recording, &tracker, dimensions);
  203. if (!skp)
  204. return absl::nullopt;
  205. canvas = nullptr;
  206. switch (GetParam()) {
  207. case RecordingPersistence::kFileSystem: {
  208. base::ScopedTempDir temp_dir;
  209. if (!temp_dir.CreateUniqueTempDir())
  210. return absl::nullopt;
  211. base::FilePath file_path = temp_dir.GetPath().AppendASCII("test_file");
  212. base::File write_file(
  213. file_path, base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  214. if (!RecordToFile(std::move(write_file), skp, &tracker,
  215. max_capture_size, serialized_size))
  216. return absl::nullopt;
  217. return {SerializedRecording(file_path)};
  218. }
  219. case RecordingPersistence::kMemoryBuffer: {
  220. absl::optional<mojo_base::BigBuffer> buffer =
  221. RecordToBuffer(skp, &tracker, max_capture_size, serialized_size);
  222. if (!buffer.has_value())
  223. return absl::nullopt;
  224. return {SerializedRecording(std::move(buffer.value()))};
  225. }
  226. }
  227. NOTREACHED();
  228. return absl::nullopt;
  229. }
  230. PaintPreviewTracker tracker;
  231. gfx::Rect dimensions;
  232. cc::PaintRecorder recorder;
  233. // Valid after SetUp() until SerializeAsSkPicture() is called.
  234. cc::PaintCanvas* canvas{};
  235. protected:
  236. base::test::TaskEnvironment task_environment_;
  237. private:
  238. base::TestDiscardableMemoryAllocator test_allocator_;
  239. };
  240. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, Roundtrip) {
  241. base::flat_set<uint32_t> ctx;
  242. uint32_t content_id = tracker.CreateContentForRemoteFrame(
  243. gfx::Rect(10, 10), base::UnguessableToken::Create());
  244. canvas->recordCustomData(content_id);
  245. tracker.TransformClipForFrame(content_id);
  246. ctx.insert(content_id);
  247. content_id = tracker.CreateContentForRemoteFrame(
  248. gfx::Rect(20, 20), base::UnguessableToken::Create());
  249. canvas->recordCustomData(content_id);
  250. tracker.TransformClipForFrame(content_id);
  251. ctx.insert(content_id);
  252. size_t out_size = 0;
  253. auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
  254. ASSERT_TRUE(recording.has_value());
  255. absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
  256. ASSERT_TRUE(result.has_value());
  257. for (auto& id : ctx) {
  258. EXPECT_TRUE(result->ctx.contains(id));
  259. result->ctx.erase(id);
  260. }
  261. EXPECT_TRUE(result->ctx.empty());
  262. }
  263. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, RoundtripWithImage) {
  264. {
  265. SkBitmap bitmap;
  266. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  267. SkCanvas sk_canvas(bitmap);
  268. sk_canvas.drawColor(SkColors::kRed);
  269. cc::PaintImage paint_image = cc::PaintImage::CreateFromBitmap(bitmap);
  270. ASSERT_FALSE(paint_image.IsLazyGenerated());
  271. ASSERT_FALSE(paint_image.IsPaintWorklet());
  272. canvas->drawImage(paint_image, 0U, 0U);
  273. }
  274. size_t out_size = 0;
  275. auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
  276. ASSERT_TRUE(recording.has_value());
  277. absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
  278. ASSERT_TRUE(result.has_value());
  279. SkBitmap bitmap;
  280. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  281. SkCanvas sk_canvas(bitmap);
  282. sk_canvas.drawPicture(result->skp);
  283. EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
  284. }
  285. class FakeTextureBacking : public cc::TextureBacking {
  286. public:
  287. explicit FakeTextureBacking(sk_sp<SkImage> image) : image_(image) {}
  288. const SkImageInfo& GetSkImageInfo() override { return image_->imageInfo(); }
  289. gpu::Mailbox GetMailbox() const override { return mailbox_; }
  290. sk_sp<SkImage> GetAcceleratedSkImage() override { return nullptr; }
  291. sk_sp<SkImage> GetSkImageViaReadback() override { return image_; }
  292. bool readPixels(const SkImageInfo& dstInfo,
  293. void* dstPixels,
  294. size_t dstRowBytes,
  295. int srcX,
  296. int srcY) override {
  297. return false;
  298. }
  299. void FlushPendingSkiaOps() override {}
  300. private:
  301. gpu::Mailbox mailbox_;
  302. sk_sp<SkImage> image_;
  303. };
  304. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
  305. RoundtripWithTexture) {
  306. {
  307. SkBitmap bitmap;
  308. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  309. SkCanvas sk_canvas(bitmap);
  310. sk_canvas.drawColor(SkColors::kRed);
  311. cc::PaintImage paint_image =
  312. cc::PaintImageBuilder::WithDefault()
  313. .set_id(cc::PaintImage::GetNextId())
  314. .set_texture_backing(
  315. sk_sp<FakeTextureBacking>(
  316. new FakeTextureBacking(SkImage::MakeFromBitmap(bitmap))),
  317. cc::PaintImage::GetNextContentId())
  318. .TakePaintImage();
  319. canvas->drawImage(paint_image, 0U, 0U);
  320. }
  321. size_t out_size = 0;
  322. auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
  323. ASSERT_TRUE(recording.has_value());
  324. absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
  325. ASSERT_TRUE(result.has_value());
  326. SkBitmap bitmap;
  327. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  328. SkCanvas sk_canvas(bitmap);
  329. sk_canvas.drawPicture(result->skp);
  330. EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
  331. }
  332. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
  333. RoundtripWithLazyTexture) {
  334. {
  335. SkBitmap bitmap;
  336. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  337. SkCanvas sk_canvas(bitmap);
  338. sk_canvas.drawColor(SkColors::kRed);
  339. auto sk_image = SkImage::MakeFromBitmap(bitmap);
  340. auto data = sk_image->encodeToData();
  341. auto lazy_sk_image = SkImage::MakeFromEncoded(data);
  342. ASSERT_TRUE(lazy_sk_image->isLazyGenerated());
  343. cc::PaintImage paint_image =
  344. cc::PaintImageBuilder::WithDefault()
  345. .set_id(cc::PaintImage::GetNextId())
  346. .set_texture_backing(sk_sp<FakeTextureBacking>(
  347. new FakeTextureBacking(lazy_sk_image)),
  348. cc::PaintImage::GetNextContentId())
  349. .TakePaintImage();
  350. cc::PaintFlags paint;
  351. paint.setBlendMode(SkBlendMode::kSrc);
  352. auto rect = SkRect::MakeWH(dimensions.width(), dimensions.height());
  353. canvas->drawImageRect(paint_image, rect, rect, SkSamplingOptions(), &paint,
  354. SkCanvas::kStrict_SrcRectConstraint);
  355. }
  356. size_t out_size = 0;
  357. auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
  358. ASSERT_TRUE(recording.has_value());
  359. absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
  360. ASSERT_TRUE(result.has_value());
  361. SkBitmap bitmap;
  362. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  363. SkCanvas sk_canvas(bitmap);
  364. sk_canvas.drawPicture(result->skp);
  365. EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
  366. }
  367. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
  368. RoundtripWithLazyImage) {
  369. {
  370. cc::PaintRecorder inner_recorder;
  371. cc::PaintCanvas* inner_canvas =
  372. inner_recorder.beginRecording(dimensions.width(), dimensions.width());
  373. inner_canvas->drawColor(SkColors::kRed);
  374. cc::PaintImage paint_image =
  375. cc::PaintImageBuilder::WithDefault()
  376. .set_id(1)
  377. .set_paint_record(inner_recorder.finishRecordingAsPicture(),
  378. dimensions, cc::PaintImage::GetNextContentId())
  379. .TakePaintImage();
  380. ASSERT_TRUE(paint_image.IsLazyGenerated());
  381. ASSERT_FALSE(paint_image.IsPaintWorklet());
  382. canvas->drawImage(paint_image, 0U, 0U);
  383. }
  384. size_t out_size = 0;
  385. auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
  386. ASSERT_TRUE(recording.has_value());
  387. absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
  388. ASSERT_TRUE(result.has_value());
  389. SkBitmap bitmap;
  390. bitmap.allocN32Pixels(dimensions.width(), dimensions.height());
  391. SkCanvas sk_canvas(bitmap);
  392. sk_canvas.drawPicture(result->skp);
  393. EXPECT_EQ(bitmap.getColor(10, 10), SK_ColorRED);
  394. }
  395. class TestPaintWorkletInput : public cc::PaintWorkletInput {
  396. public:
  397. explicit TestPaintWorkletInput(const gfx::SizeF& size)
  398. : container_size_(size) {}
  399. gfx::SizeF GetSize() const override { return container_size_; }
  400. int WorkletId() const override { return 1U; }
  401. const std::vector<PaintWorkletInput::PropertyKey>& GetPropertyKeys()
  402. const override {
  403. return property_keys_;
  404. }
  405. bool IsCSSPaintWorkletInput() const override { return false; }
  406. protected:
  407. ~TestPaintWorkletInput() override = default;
  408. private:
  409. gfx::SizeF container_size_;
  410. std::vector<PaintWorkletInput::PropertyKey> property_keys_;
  411. };
  412. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
  413. RoundtripWithPaintWorklet) {
  414. {
  415. gfx::SizeF size(100, 50);
  416. scoped_refptr<TestPaintWorkletInput> input =
  417. base::MakeRefCounted<TestPaintWorkletInput>(size);
  418. cc::PaintImage paint_image = cc::PaintImageBuilder::WithDefault()
  419. .set_id(1)
  420. .set_paint_worklet_input(std::move(input))
  421. .TakePaintImage();
  422. ASSERT_FALSE(paint_image.IsLazyGenerated());
  423. ASSERT_TRUE(paint_image.IsPaintWorklet());
  424. cc::PaintFlags paint;
  425. paint.setBlendMode(SkBlendMode::kSrc);
  426. auto rect = SkRect::MakeWH(dimensions.width(), dimensions.height());
  427. canvas->drawImageRect(paint_image, rect, rect, SkSamplingOptions(), &paint,
  428. SkCanvas::kStrict_SrcRectConstraint);
  429. }
  430. size_t out_size = 0;
  431. auto recording = SerializeAsSkPicture(absl::nullopt, &out_size);
  432. // The paint worklet needs to be skipped. Just make sure it doesn't crash.
  433. ASSERT_TRUE(recording.has_value());
  434. absl::optional<SkpResult> result = std::move(recording.value()).Deserialize();
  435. ASSERT_TRUE(result.has_value());
  436. }
  437. TEST_P(PaintPreviewRecorderUtilsSerializeAsSkPictureTest, FailIfExceedMaxSize) {
  438. size_t out_size = 2;
  439. auto recording = SerializeAsSkPicture({1}, &out_size);
  440. EXPECT_FALSE(recording.has_value());
  441. EXPECT_LE(out_size, 1U);
  442. }
  443. INSTANTIATE_TEST_SUITE_P(All,
  444. PaintPreviewRecorderUtilsSerializeAsSkPictureTest,
  445. testing::Values(RecordingPersistence::kFileSystem,
  446. RecordingPersistence::kMemoryBuffer),
  447. PersistenceParamToString);
  448. TEST(PaintPreviewRecorderUtilsTest, TestBuildResponse) {
  449. auto token = base::UnguessableToken::Create();
  450. auto embedding_token = base::UnguessableToken::Create();
  451. PaintPreviewTracker tracker(token, embedding_token, true);
  452. tracker.AnnotateLink(GURL("www.google.com"), SkRect::MakeXYWH(1, 2, 3, 4));
  453. tracker.AnnotateLink(GURL("www.chromium.org"),
  454. SkRect::MakeXYWH(10, 20, 10, 20));
  455. tracker.CreateContentForRemoteFrame(gfx::Rect(1, 1, 1, 1),
  456. base::UnguessableToken::Create());
  457. tracker.CreateContentForRemoteFrame(gfx::Rect(1, 2, 4, 8),
  458. base::UnguessableToken::Create());
  459. auto response = mojom::PaintPreviewCaptureResponse::New();
  460. BuildResponse(&tracker, response.get());
  461. EXPECT_EQ(response->embedding_token, embedding_token);
  462. EXPECT_EQ(response->links.size(), 2U);
  463. EXPECT_THAT(response->links[0]->url, GURL("www.google.com"));
  464. EXPECT_THAT(response->links[0]->rect, gfx::Rect(1, 2, 3, 4));
  465. EXPECT_THAT(response->links[1]->url, GURL("www.chromium.org"));
  466. EXPECT_THAT(response->links[1]->rect, gfx::Rect(10, 20, 10, 20));
  467. auto* picture_ctx = tracker.GetPictureSerializationContext();
  468. for (const auto& id_pair : response->content_id_to_embedding_token) {
  469. auto it = picture_ctx->content_id_to_embedding_token.find(id_pair.first);
  470. EXPECT_NE(it, picture_ctx->content_id_to_embedding_token.end());
  471. EXPECT_EQ(id_pair.first, it->first);
  472. EXPECT_EQ(id_pair.second, it->second);
  473. }
  474. }
  475. } // namespace paint_preview