blob: 519a8593a3fe7a2ba44d97b1d3fd182576dec9f6 [file] [log] [blame]
Wei Li1d345bf2018-08-10 02:52:371// 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
Wei Liab754772018-08-22 22:41:175#include "printing/metafile_skia.h"
Wei Li1d345bf2018-08-10 02:52:376
Alan Screen06d20162020-06-26 17:42:127#include <utility>
8
9#include "build/build_config.h"
Wei Li1d345bf2018-08-10 02:52:3710#include "cc/paint/paint_record.h"
Wei Liab754772018-08-22 22:41:1711#include "printing/common/metafile_utils.h"
Julie Jeongeun Kime1abed92020-06-11 11:01:4812#include "printing/mojom/print.mojom.h"
Wei Li1d345bf2018-08-10 02:52:3713#include "testing/gtest/include/gtest/gtest.h"
14#include "third_party/skia/include/core/SkPictureRecorder.h"
15
16namespace printing {
17
Wei Liab754772018-08-22 22:41:1718TEST(MetafileSkiaTest, TestFrameContent) {
Wei Li1d345bf2018-08-10 02:52:3719 constexpr int kPictureSideLen = 100;
20 constexpr int kPageSideLen = 150;
21
22 // Create a placeholder picture.
23 sk_sp<SkPicture> pic_holder = SkPicture::MakePlaceholder(
24 SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen));
25
26 // Create the page with nested content which is the placeholder and will be
27 // replaced later.
28 sk_sp<cc::PaintRecord> record = sk_make_sp<cc::PaintRecord>();
29 cc::PaintFlags flags;
30 flags.setColor(SK_ColorWHITE);
31 const SkRect page_rect = SkRect::MakeXYWH(0, 0, kPageSideLen, kPageSideLen);
32 record->push<cc::DrawRectOp>(page_rect, flags);
33 const uint32_t content_id = pic_holder->uniqueID();
34 record->push<cc::CustomDataOp>(content_id);
35 SkSize page_size = SkSize::Make(kPageSideLen, kPageSideLen);
36
37 // Finish creating the entire metafile.
Julie Jeongeun Kime1abed92020-06-11 11:01:4838 MetafileSkia metafile(mojom::SkiaDocumentType::kMSKP, 1);
Wei Li1d345bf2018-08-10 02:52:3739 metafile.AppendPage(page_size, std::move(record));
Gyuyoung Kim5f7f4c72020-07-14 13:09:0340 metafile.AppendSubframeInfo(content_id, base::UnguessableToken::Create(),
41 std::move(pic_holder));
Wei Li1d345bf2018-08-10 02:52:3742 metafile.FinishFrameContent();
43 SkStreamAsset* metafile_stream = metafile.GetPdfData();
44 ASSERT_TRUE(metafile_stream);
45
46 // Draw a 100 by 100 red square which will be the actual content of
47 // the placeholder.
48 SkPictureRecorder recorder;
49 SkCanvas* canvas = recorder.beginRecording(kPictureSideLen, kPictureSideLen);
50 SkPaint paint;
Mike Reed7a1ae652020-05-20 02:30:0251 paint.setStyle(SkPaint::kFill_Style);
Wei Li1d345bf2018-08-10 02:52:3752 paint.setColor(SK_ColorRED);
53 paint.setAlpha(SK_AlphaOPAQUE);
54 canvas->drawRect(SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen),
55 paint);
56 sk_sp<SkPicture> picture(recorder.finishRecordingAsPicture());
57 EXPECT_TRUE(picture);
58
59 // Get the complete picture by replacing the placeholder.
Alan Screenab94cfe2020-06-24 20:21:1760 PictureDeserializationContext subframes;
Wei Li1d345bf2018-08-10 02:52:3761 subframes[content_id] = picture;
Alan Screen06d20162020-06-26 17:42:1262 SkDeserialProcs procs = DeserializationProcs(&subframes, nullptr);
Wei Li1d345bf2018-08-10 02:52:3763 sk_sp<SkPicture> pic = SkPicture::MakeFromStream(metafile_stream, &procs);
64 ASSERT_TRUE(pic);
65
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);
Ian Preste598eece2020-10-19 23:31:0271 SkCanvas bitmap_canvas(bitmap, SkSurfaceProps{});
Wei Li1d345bf2018-08-10 02:52:3772 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
Alan Screen06d20162020-06-26 17:42:1285TEST(MetafileSkiaTest, TestMultiPictureDocumentTypefaces) {
86 constexpr int kPictureSideLen = 100;
87 constexpr int kPageSideLen = 150;
88 constexpr int kDocumentCookie = 1;
Alan Screen06d20162020-06-26 17:42:1289 constexpr int kNumDocumentPages = 2;
90
91 // The content tracking for serialization/deserialization.
92 ContentProxySet serialize_typeface_ctx;
93 PictureDeserializationContext subframes;
94 TypefaceDeserializationContext typefaces;
95 SkDeserialProcs procs = DeserializationProcs(&subframes, &typefaces);
96
97 // The typefaces which will be reused across the multiple (duplicate) pages.
98 constexpr char kTypefaceName1[] = "sans-serif";
99#if defined(OS_WIN)
100 constexpr char kTypefaceName2[] = "Courier New";
101#else
102 constexpr char kTypefaceName2[] = "monospace";
103#endif
104 constexpr size_t kNumTypefaces = 2;
105 sk_sp<SkTypeface> typeface1 =
106 SkTypeface::MakeFromName(kTypefaceName1, SkFontStyle());
107 sk_sp<SkTypeface> typeface2 =
108 SkTypeface::MakeFromName(kTypefaceName2, SkFontStyle());
109 const SkFont font1 = SkFont(typeface1, 10);
110 const SkFont font2 = SkFont(typeface2, 12);
111
112 // Node IDs for the text, which will increase for each text blob added.
113 cc::NodeId node_id = 7;
114
115 // All text can just be black.
116 cc::PaintFlags flags_text;
117 flags_text.setColor(SK_ColorBLACK);
118
119 // Mark the text on white pages, each of the same size.
120 cc::PaintFlags flags;
121 flags.setColor(SK_ColorWHITE);
122 const SkRect page_rect = SkRect::MakeXYWH(0, 0, kPageSideLen, kPageSideLen);
123 SkSize page_size = SkSize::Make(kPageSideLen, kPageSideLen);
124
125 for (int i = 0; i < kNumDocumentPages; i++) {
126 MetafileSkia metafile(mojom::SkiaDocumentType::kMSKP, kDocumentCookie);
127
128 // When the stream is serialized inside FinishFrameContent(), any typeface
129 // which is used on any page will be serialized only once by the first
130 // page's metafile which needed it. Any subsequent page that reuses the
Daniel Hosseinian3553e272021-04-24 00:51:18131 // same typeface will rely upon `serialize_typeface_ctx` which is used by
Alan Screen06d20162020-06-26 17:42:12132 // printing::SerializeOopTypeface() to optimize away the need to resend.
133 metafile.UtilizeTypefaceContext(&serialize_typeface_ctx);
134
135 sk_sp<SkPicture> pic_holder = SkPicture::MakePlaceholder(
136 SkRect::MakeXYWH(0, 0, kPictureSideLen, kPictureSideLen));
137
138 // Create the page for the text content.
139 sk_sp<cc::PaintRecord> record = sk_make_sp<cc::PaintRecord>();
140 record->push<cc::DrawRectOp>(page_rect, flags);
141 const uint32_t content_id = pic_holder->uniqueID();
142 record->push<cc::CustomDataOp>(content_id);
143
144 // Mark the page with some text using multiple fonts.
145 // Use the first font.
146 sk_sp<SkTextBlob> text_blob1 = SkTextBlob::MakeFromString("foo", font1);
147 record->push<cc::DrawTextBlobOp>(text_blob1, 0, 0, ++node_id, flags_text);
148
149 // Use the second font.
150 sk_sp<SkTextBlob> text_blob2 = SkTextBlob::MakeFromString("bar", font2);
151 record->push<cc::DrawTextBlobOp>(text_blob2, 0, 0, ++node_id, flags_text);
152
153 // Reuse the first font again on same page.
154 sk_sp<SkTextBlob> text_blob3 = SkTextBlob::MakeFromString("bar", font2);
155 record->push<cc::DrawTextBlobOp>(text_blob3, 0, 0, ++node_id, flags_text);
156
157 metafile.AppendPage(page_size, std::move(record));
Gyuyoung Kim5f7f4c72020-07-14 13:09:03158 metafile.AppendSubframeInfo(content_id, base::UnguessableToken::Create(),
159 std::move(pic_holder));
Alan Screen06d20162020-06-26 17:42:12160 metafile.FinishFrameContent();
161 SkStreamAsset* metafile_stream = metafile.GetPdfData();
162 ASSERT_TRUE(metafile_stream);
163
164 // Deserialize the stream. Any given typeface is expected to appear only
Daniel Hosseinian3553e272021-04-24 00:51:18165 // once in the stream, so the deserialization context of `typefaces` bundled
166 // with `procs` should be empty the first time through, and afterwards
Alan Screen06d20162020-06-26 17:42:12167 // there should never be more than the number of unique typefaces we used,
168 // regardless of number of pages.
169 EXPECT_EQ(typefaces.size(), i ? kNumTypefaces : 0);
170 ASSERT_TRUE(SkPicture::MakeFromStream(metafile_stream, &procs));
171 EXPECT_EQ(typefaces.size(), kNumTypefaces);
172 }
173}
174
Wei Li1d345bf2018-08-10 02:52:37175} // namespace printing