metafile_skia_unittest.cc 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. // Copyright 2018 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 "printing/metafile_skia.h"
  5. #include <utility>
  6. #include "build/build_config.h"
  7. #include "cc/paint/paint_record.h"
  8. #include "printing/common/metafile_utils.h"
  9. #include "printing/mojom/print.mojom.h"
  10. #include "testing/gtest/include/gtest/gtest.h"
  11. #include "third_party/skia/include/core/SkBitmap.h"
  12. #include "third_party/skia/include/core/SkCanvas.h"
  13. #include "third_party/skia/include/core/SkPaint.h"
  14. #include "third_party/skia/include/core/SkPicture.h"
  15. #include "third_party/skia/include/core/SkPictureRecorder.h"
  16. #include "third_party/skia/include/core/SkRect.h"
  17. #include "third_party/skia/include/core/SkRefCnt.h"
  18. #include "third_party/skia/include/core/SkSerialProcs.h"
  19. #include "third_party/skia/include/core/SkSize.h"
  20. #include "third_party/skia/include/core/SkStream.h"
  21. #include "third_party/skia/include/core/SkSurfaceProps.h"
  22. #include "third_party/skia/include/core/SkTextBlob.h"
  23. namespace printing {
  24. TEST(MetafileSkiaTest, TestFrameContent) {
  25. constexpr int kPictureSideLen = 100;
  26. constexpr int kPageSideLen = 150;
  27. // Create a placeholder picture.
  28. sk_sp<SkPicture> pic_holder = SkPicture::MakePlaceholder(
  29. SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen));
  30. // Create the page with nested content which is the placeholder and will be
  31. // replaced later.
  32. sk_sp<cc::PaintRecord> record = sk_make_sp<cc::PaintRecord>();
  33. cc::PaintFlags flags;
  34. flags.setColor(SK_ColorWHITE);
  35. const SkRect page_rect = SkRect::MakeXYWH(0, 0, kPageSideLen, kPageSideLen);
  36. record->push<cc::DrawRectOp>(page_rect, flags);
  37. const uint32_t content_id = pic_holder->uniqueID();
  38. record->push<cc::CustomDataOp>(content_id);
  39. SkSize page_size = SkSize::Make(kPageSideLen, kPageSideLen);
  40. // Finish creating the entire metafile.
  41. MetafileSkia metafile(mojom::SkiaDocumentType::kMSKP, 1);
  42. metafile.AppendPage(page_size, std::move(record));
  43. metafile.AppendSubframeInfo(content_id, base::UnguessableToken::Create(),
  44. std::move(pic_holder));
  45. metafile.FinishFrameContent();
  46. SkStreamAsset* metafile_stream = metafile.GetPdfData();
  47. ASSERT_TRUE(metafile_stream);
  48. // Draw a 100 by 100 red square which will be the actual content of
  49. // the placeholder.
  50. SkPictureRecorder recorder;
  51. SkCanvas* canvas = recorder.beginRecording(kPictureSideLen, kPictureSideLen);
  52. SkPaint paint;
  53. paint.setStyle(SkPaint::kFill_Style);
  54. paint.setColor(SK_ColorRED);
  55. paint.setAlpha(SK_AlphaOPAQUE);
  56. canvas->drawRect(SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen),
  57. paint);
  58. sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
  59. EXPECT_TRUE(picture);
  60. // Get the complete picture by replacing the placeholder.
  61. PictureDeserializationContext subframes;
  62. subframes[content_id] = picture;
  63. SkDeserialProcs procs = DeserializationProcs(&subframes, nullptr);
  64. sk_sp<SkPicture> pic = SkPicture::MakeFromStream(metafile_stream, &procs);
  65. ASSERT_TRUE(pic);
  66. // Verify the resultant picture is as expected by comparing the sizes and
  67. // detecting the color inside and outside of the square area.
  68. EXPECT_TRUE(pic->cullRect() == page_rect);
  69. SkBitmap bitmap;
  70. bitmap.allocN32Pixels(kPageSideLen, kPageSideLen);
  71. SkCanvas bitmap_canvas(bitmap, SkSurfaceProps{});
  72. pic->playback(&bitmap_canvas);
  73. // Check top left pixel color of the red square.
  74. EXPECT_EQ(bitmap.getColor(0, 0), SK_ColorRED);
  75. // Check bottom right pixel of the red square.
  76. EXPECT_EQ(bitmap.getColor(kPictureSideLen - 1, kPictureSideLen - 1),
  77. SK_ColorRED);
  78. // Check inside of the red square.
  79. EXPECT_EQ(bitmap.getColor(kPictureSideLen / 2, kPictureSideLen / 2),
  80. SK_ColorRED);
  81. // Check outside of the red square.
  82. EXPECT_EQ(bitmap.getColor(kPictureSideLen, kPictureSideLen), SK_ColorWHITE);
  83. }
  84. TEST(MetafileSkiaTest, TestMultiPictureDocumentTypefaces) {
  85. constexpr int kPictureSideLen = 100;
  86. constexpr int kPageSideLen = 150;
  87. constexpr int kDocumentCookie = 1;
  88. constexpr int kNumDocumentPages = 2;
  89. // The content tracking for serialization/deserialization.
  90. ContentProxySet serialize_typeface_ctx;
  91. PictureDeserializationContext subframes;
  92. TypefaceDeserializationContext typefaces;
  93. SkDeserialProcs procs = DeserializationProcs(&subframes, &typefaces);
  94. // The typefaces which will be reused across the multiple (duplicate) pages.
  95. constexpr char kTypefaceName1[] = "sans-serif";
  96. #if BUILDFLAG(IS_WIN)
  97. constexpr char kTypefaceName2[] = "Courier New";
  98. #else
  99. constexpr char kTypefaceName2[] = "monospace";
  100. #endif
  101. constexpr size_t kNumTypefaces = 2;
  102. sk_sp<SkTypeface> typeface1 =
  103. SkTypeface::MakeFromName(kTypefaceName1, SkFontStyle());
  104. sk_sp<SkTypeface> typeface2 =
  105. SkTypeface::MakeFromName(kTypefaceName2, SkFontStyle());
  106. const SkFont font1 = SkFont(typeface1, 10);
  107. const SkFont font2 = SkFont(typeface2, 12);
  108. // Node IDs for the text, which will increase for each text blob added.
  109. cc::NodeId node_id = 7;
  110. // All text can just be black.
  111. cc::PaintFlags flags_text;
  112. flags_text.setColor(SK_ColorBLACK);
  113. // Mark the text on white pages, each of the same size.
  114. cc::PaintFlags flags;
  115. flags.setColor(SK_ColorWHITE);
  116. const SkRect page_rect = SkRect::MakeXYWH(0, 0, kPageSideLen, kPageSideLen);
  117. SkSize page_size = SkSize::Make(kPageSideLen, kPageSideLen);
  118. for (int i = 0; i < kNumDocumentPages; i++) {
  119. MetafileSkia metafile(mojom::SkiaDocumentType::kMSKP, kDocumentCookie);
  120. // When the stream is serialized inside FinishFrameContent(), any typeface
  121. // which is used on any page will be serialized only once by the first
  122. // page's metafile which needed it. Any subsequent page that reuses the
  123. // same typeface will rely upon `serialize_typeface_ctx` which is used by
  124. // printing::SerializeOopTypeface() to optimize away the need to resend.
  125. metafile.UtilizeTypefaceContext(&serialize_typeface_ctx);
  126. sk_sp<SkPicture> pic_holder = SkPicture::MakePlaceholder(
  127. SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen));
  128. // Create the page for the text content.
  129. sk_sp<cc::PaintRecord> record = sk_make_sp<cc::PaintRecord>();
  130. record->push<cc::DrawRectOp>(page_rect, flags);
  131. const uint32_t content_id = pic_holder->uniqueID();
  132. record->push<cc::CustomDataOp>(content_id);
  133. // Mark the page with some text using multiple fonts.
  134. // Use the first font.
  135. sk_sp<SkTextBlob> text_blob1 = SkTextBlob::MakeFromString("foo", font1);
  136. record->push<cc::DrawTextBlobOp>(text_blob1, 0.0f, 0.0f, ++node_id,
  137. flags_text);
  138. // Use the second font.
  139. sk_sp<SkTextBlob> text_blob2 = SkTextBlob::MakeFromString("bar", font2);
  140. record->push<cc::DrawTextBlobOp>(text_blob2, 0.0f, 0.0f, ++node_id,
  141. flags_text);
  142. // Reuse the first font again on same page.
  143. sk_sp<SkTextBlob> text_blob3 = SkTextBlob::MakeFromString("bar", font2);
  144. record->push<cc::DrawTextBlobOp>(text_blob3, 0.0f, 0.0f, ++node_id,
  145. flags_text);
  146. metafile.AppendPage(page_size, std::move(record));
  147. metafile.AppendSubframeInfo(content_id, base::UnguessableToken::Create(),
  148. std::move(pic_holder));
  149. metafile.FinishFrameContent();
  150. SkStreamAsset* metafile_stream = metafile.GetPdfData();
  151. ASSERT_TRUE(metafile_stream);
  152. // Deserialize the stream. Any given typeface is expected to appear only
  153. // once in the stream, so the deserialization context of `typefaces` bundled
  154. // with `procs` should be empty the first time through, and afterwards
  155. // there should never be more than the number of unique typefaces we used,
  156. // regardless of number of pages.
  157. EXPECT_EQ(typefaces.size(), i ? kNumTypefaces : 0);
  158. ASSERT_TRUE(SkPicture::MakeFromStream(metafile_stream, &procs));
  159. EXPECT_EQ(typefaces.size(), kNumTypefaces);
  160. }
  161. }
  162. } // namespace printing