xref: /aosp_15_r20/external/skia/tests/SkGlyphTest.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2020 Google LLC
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker 
8*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkCanvas.h"
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkDrawable.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPicture.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPictureRecorder.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/effects/SkRuntimeEffect.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkCanvasPriv.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkGlyph.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMask.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkReadBuffer.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkWriteBuffer.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
28*c8dee2aaSAndroid Build Coastguard Worker 
29*c8dee2aaSAndroid Build Coastguard Worker #include <cstddef>
30*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
31*c8dee2aaSAndroid Build Coastguard Worker #include <initializer_list>
32*c8dee2aaSAndroid Build Coastguard Worker #include <iterator>
33*c8dee2aaSAndroid Build Coastguard Worker #include <optional>
34*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkGlyphRectBasic,reporter)35*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkGlyphRectBasic, reporter) {
36*c8dee2aaSAndroid Build Coastguard Worker     using namespace skglyph;
37*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphRect r{1, 1, 10, 10};
38*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !r.empty());
39*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphRect a = rect_union(r, empty_rect());
40*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a.rect() == SkRect::MakeLTRB(1, 1, 10, 10));
41*c8dee2aaSAndroid Build Coastguard Worker     auto widthHeight = a.widthHeight();
42*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, widthHeight.x() == 9 && widthHeight.y() == 9);
43*c8dee2aaSAndroid Build Coastguard Worker 
44*c8dee2aaSAndroid Build Coastguard Worker     a = rect_intersection(r, full_rect());
45*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, a.rect() == SkRect::MakeLTRB(1, 1, 10, 10));
46*c8dee2aaSAndroid Build Coastguard Worker 
47*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphRect acc = full_rect();
48*c8dee2aaSAndroid Build Coastguard Worker     for (int x = -10; x < 10; x++) {
49*c8dee2aaSAndroid Build Coastguard Worker         for(int y = -10; y < 10; y++) {
50*c8dee2aaSAndroid Build Coastguard Worker             acc = rect_intersection(acc, SkGlyphRect(x, y, x + 20, y + 20));
51*c8dee2aaSAndroid Build Coastguard Worker         }
52*c8dee2aaSAndroid Build Coastguard Worker     }
53*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, acc.rect() == SkRect::MakeLTRB(9, 9, 10, 10));
54*c8dee2aaSAndroid Build Coastguard Worker 
55*c8dee2aaSAndroid Build Coastguard Worker     acc = empty_rect();
56*c8dee2aaSAndroid Build Coastguard Worker     for (int x = -10; x < 10; x++) {
57*c8dee2aaSAndroid Build Coastguard Worker         for(int y = -10; y < 10; y++) {
58*c8dee2aaSAndroid Build Coastguard Worker             acc = rect_union(acc, SkGlyphRect(x, y, x + 20, y + 20));
59*c8dee2aaSAndroid Build Coastguard Worker         }
60*c8dee2aaSAndroid Build Coastguard Worker     }
61*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, acc.rect() == SkRect::MakeLTRB(-10, -10, 29, 29));
62*c8dee2aaSAndroid Build Coastguard Worker }
63*c8dee2aaSAndroid Build Coastguard Worker 
64*c8dee2aaSAndroid Build Coastguard Worker class SkGlyphTestPeer {
65*c8dee2aaSAndroid Build Coastguard Worker public:
SetGlyph1(SkGlyph * glyph)66*c8dee2aaSAndroid Build Coastguard Worker     static void SetGlyph1(SkGlyph* glyph) {
67*c8dee2aaSAndroid Build Coastguard Worker         glyph->fAdvanceX = 10;
68*c8dee2aaSAndroid Build Coastguard Worker         glyph->fAdvanceY = 11;
69*c8dee2aaSAndroid Build Coastguard Worker         glyph->fLeft = -1;
70*c8dee2aaSAndroid Build Coastguard Worker         glyph->fTop = -2;
71*c8dee2aaSAndroid Build Coastguard Worker         glyph->fWidth = 8;
72*c8dee2aaSAndroid Build Coastguard Worker         glyph->fHeight = 9;
73*c8dee2aaSAndroid Build Coastguard Worker         glyph->fMaskFormat = SkMask::Format::kA8_Format;
74*c8dee2aaSAndroid Build Coastguard Worker     }
75*c8dee2aaSAndroid Build Coastguard Worker 
SetGlyph2(SkGlyph * glyph)76*c8dee2aaSAndroid Build Coastguard Worker     static void SetGlyph2(SkGlyph* glyph) {
77*c8dee2aaSAndroid Build Coastguard Worker         glyph->fAdvanceX = 10;
78*c8dee2aaSAndroid Build Coastguard Worker         glyph->fAdvanceY = 11;
79*c8dee2aaSAndroid Build Coastguard Worker         glyph->fLeft = 0;
80*c8dee2aaSAndroid Build Coastguard Worker         glyph->fTop = -1;
81*c8dee2aaSAndroid Build Coastguard Worker         glyph->fWidth = 8;
82*c8dee2aaSAndroid Build Coastguard Worker         glyph->fHeight = 9;
83*c8dee2aaSAndroid Build Coastguard Worker         glyph->fMaskFormat = SkMask::Format::kA8_Format;
84*c8dee2aaSAndroid Build Coastguard Worker     }
85*c8dee2aaSAndroid Build Coastguard Worker };
86*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkGlyph_SendMetrics,reporter)87*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkGlyph_SendMetrics, reporter) {
88*c8dee2aaSAndroid Build Coastguard Worker     {
89*c8dee2aaSAndroid Build Coastguard Worker         SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
90*c8dee2aaSAndroid Build Coastguard Worker         SkGlyphTestPeer::SetGlyph1(&srcGlyph);
91*c8dee2aaSAndroid Build Coastguard Worker 
92*c8dee2aaSAndroid Build Coastguard Worker         SkBinaryWriteBuffer writeBuffer({});
93*c8dee2aaSAndroid Build Coastguard Worker         srcGlyph.flattenMetrics(writeBuffer);
94*c8dee2aaSAndroid Build Coastguard Worker 
95*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkData> data = writeBuffer.snapshotAsData();
96*c8dee2aaSAndroid Build Coastguard Worker 
97*c8dee2aaSAndroid Build Coastguard Worker         SkReadBuffer readBuffer{data->data(), data->size()};
98*c8dee2aaSAndroid Build Coastguard Worker         std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
99*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, readBuffer.isValid());
100*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dstGlyph.has_value());
101*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
102*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
103*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
104*c8dee2aaSAndroid Build Coastguard Worker     }
105*c8dee2aaSAndroid Build Coastguard Worker     {
106*c8dee2aaSAndroid Build Coastguard Worker         SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
107*c8dee2aaSAndroid Build Coastguard Worker         SkGlyphTestPeer::SetGlyph2(&srcGlyph);
108*c8dee2aaSAndroid Build Coastguard Worker 
109*c8dee2aaSAndroid Build Coastguard Worker         SkBinaryWriteBuffer writeBuffer({});
110*c8dee2aaSAndroid Build Coastguard Worker         srcGlyph.flattenMetrics(writeBuffer);
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<SkData> data = writeBuffer.snapshotAsData();
113*c8dee2aaSAndroid Build Coastguard Worker 
114*c8dee2aaSAndroid Build Coastguard Worker         SkReadBuffer readBuffer{data->data(), data->size()};
115*c8dee2aaSAndroid Build Coastguard Worker         std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
116*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, readBuffer.isValid());
117*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dstGlyph.has_value());
118*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
119*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
120*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
121*c8dee2aaSAndroid Build Coastguard Worker     }
122*c8dee2aaSAndroid Build Coastguard Worker 
123*c8dee2aaSAndroid Build Coastguard Worker     uint8_t badData[] = {1, 2, 3, 4, 5, 6, 7, 8};
124*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer badBuffer{badData, std::size(badData)};
125*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(badBuffer);
126*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !badBuffer.isValid());
127*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !dstGlyph.has_value());
128*c8dee2aaSAndroid Build Coastguard Worker }
129*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkGlyph_SendWithImage,reporter)130*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkGlyph_SendWithImage, reporter) {
131*c8dee2aaSAndroid Build Coastguard Worker     SkArenaAlloc alloc{256};
132*c8dee2aaSAndroid Build Coastguard Worker     SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
133*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphTestPeer::SetGlyph1(&srcGlyph);
134*c8dee2aaSAndroid Build Coastguard Worker 
135*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint8_t X = 0xff;
136*c8dee2aaSAndroid Build Coastguard Worker     static constexpr uint8_t O = 0x00;
137*c8dee2aaSAndroid Build Coastguard Worker     uint8_t imageData[][8] = {
138*c8dee2aaSAndroid Build Coastguard Worker         {X,X,X,X,X,X,X,X},
139*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,O,O,O,O,X},
140*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,O,O,O,O,X},
141*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,O,O,O,O,X},
142*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,X,X,O,O,X},
143*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,O,O,O,O,X},
144*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,O,O,O,O,X},
145*c8dee2aaSAndroid Build Coastguard Worker         {X,O,O,O,O,O,O,X},
146*c8dee2aaSAndroid Build Coastguard Worker         {X,X,X,X,X,X,X,X},
147*c8dee2aaSAndroid Build Coastguard Worker     };
148*c8dee2aaSAndroid Build Coastguard Worker 
149*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.setImage(&alloc, imageData);
150*c8dee2aaSAndroid Build Coastguard Worker 
151*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer writeBuffer({});
152*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenMetrics(writeBuffer);
153*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenImage(writeBuffer);
154*c8dee2aaSAndroid Build Coastguard Worker 
155*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data = writeBuffer.snapshotAsData();
156*c8dee2aaSAndroid Build Coastguard Worker 
157*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer readBuffer{data->data(), data->size()};
158*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
159*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
160*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph.has_value());
161*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
162*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
163*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
164*c8dee2aaSAndroid Build Coastguard Worker 
165*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph->addImageFromBuffer(readBuffer, &alloc);
166*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
167*c8dee2aaSAndroid Build Coastguard Worker     const uint8_t* dstImage = (const uint8_t*)dstGlyph->image();
168*c8dee2aaSAndroid Build Coastguard Worker     for (int y = 0; y < dstGlyph->height(); ++y) {
169*c8dee2aaSAndroid Build Coastguard Worker         for (int x = 0; x < dstGlyph->width(); ++x) {
170*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, imageData[y][x] == dstImage[y * dstGlyph->rowBytes() + x]);
171*c8dee2aaSAndroid Build Coastguard Worker         }
172*c8dee2aaSAndroid Build Coastguard Worker     }
173*c8dee2aaSAndroid Build Coastguard Worker 
174*c8dee2aaSAndroid Build Coastguard Worker     // Add good metrics, but mess up image data
175*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer badWriteBuffer({});
176*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenMetrics(badWriteBuffer);
177*c8dee2aaSAndroid Build Coastguard Worker     badWriteBuffer.writeInt(7);
178*c8dee2aaSAndroid Build Coastguard Worker     badWriteBuffer.writeInt(8);
179*c8dee2aaSAndroid Build Coastguard Worker 
180*c8dee2aaSAndroid Build Coastguard Worker     data = badWriteBuffer.snapshotAsData();
181*c8dee2aaSAndroid Build Coastguard Worker 
182*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer badReadBuffer{data->data(), data->size()};
183*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
184*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, badReadBuffer.isValid());  // Reading glyph metrics is okay.
185*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph.has_value());
186*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
187*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
188*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
189*c8dee2aaSAndroid Build Coastguard Worker 
190*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph->addImageFromBuffer(badReadBuffer, &alloc);
191*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
192*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !dstGlyph->setImageHasBeenCalled());
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkGlyph_SendWithPath,reporter)195*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkGlyph_SendWithPath, reporter) {
196*c8dee2aaSAndroid Build Coastguard Worker     SkArenaAlloc alloc{256};
197*c8dee2aaSAndroid Build Coastguard Worker     SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
198*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphTestPeer::SetGlyph1(&srcGlyph);
199*c8dee2aaSAndroid Build Coastguard Worker 
200*c8dee2aaSAndroid Build Coastguard Worker     SkPath srcPath;
201*c8dee2aaSAndroid Build Coastguard Worker     srcPath.addRect(srcGlyph.rect());
202*c8dee2aaSAndroid Build Coastguard Worker 
203*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.setPath(&alloc, &srcPath, false, false);
204*c8dee2aaSAndroid Build Coastguard Worker 
205*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer writeBuffer({});
206*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenMetrics(writeBuffer);
207*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenPath(writeBuffer);
208*c8dee2aaSAndroid Build Coastguard Worker 
209*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data = writeBuffer.snapshotAsData();
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer readBuffer{data->data(), data->size()};
212*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
213*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
214*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph.has_value());
215*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
216*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
217*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
218*c8dee2aaSAndroid Build Coastguard Worker 
219*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph->addPathFromBuffer(readBuffer, &alloc);
220*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
221*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph->setPathHasBeenCalled());
222*c8dee2aaSAndroid Build Coastguard Worker     const SkPath* dstPath = dstGlyph->path();
223*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, *dstPath == srcPath);
224*c8dee2aaSAndroid Build Coastguard Worker 
225*c8dee2aaSAndroid Build Coastguard Worker     {
226*c8dee2aaSAndroid Build Coastguard Worker         // Add good metrics, but mess up path data
227*c8dee2aaSAndroid Build Coastguard Worker         SkBinaryWriteBuffer badWriteBuffer({});
228*c8dee2aaSAndroid Build Coastguard Worker         srcGlyph.flattenMetrics(badWriteBuffer);
229*c8dee2aaSAndroid Build Coastguard Worker         // Force a false value to be read in addPathFromBuffer for hasPath.
230*c8dee2aaSAndroid Build Coastguard Worker         badWriteBuffer.writeInt(8);
231*c8dee2aaSAndroid Build Coastguard Worker         badWriteBuffer.writeInt(9);
232*c8dee2aaSAndroid Build Coastguard Worker 
233*c8dee2aaSAndroid Build Coastguard Worker         data = badWriteBuffer.snapshotAsData();
234*c8dee2aaSAndroid Build Coastguard Worker 
235*c8dee2aaSAndroid Build Coastguard Worker         SkReadBuffer badReadBuffer{data->data(), data->size()};
236*c8dee2aaSAndroid Build Coastguard Worker         dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
237*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dstGlyph.has_value());
238*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
239*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
240*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
241*c8dee2aaSAndroid Build Coastguard Worker 
242*c8dee2aaSAndroid Build Coastguard Worker         dstGlyph->addPathFromBuffer(badReadBuffer, &alloc);
243*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
244*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !dstGlyph->setPathHasBeenCalled());
245*c8dee2aaSAndroid Build Coastguard Worker     }
246*c8dee2aaSAndroid Build Coastguard Worker     {
247*c8dee2aaSAndroid Build Coastguard Worker         // Add good metrics, but no path data.
248*c8dee2aaSAndroid Build Coastguard Worker         SkBinaryWriteBuffer badWriteBuffer({});
249*c8dee2aaSAndroid Build Coastguard Worker         srcGlyph.flattenMetrics(badWriteBuffer);
250*c8dee2aaSAndroid Build Coastguard Worker 
251*c8dee2aaSAndroid Build Coastguard Worker         data = badWriteBuffer.snapshotAsData();
252*c8dee2aaSAndroid Build Coastguard Worker 
253*c8dee2aaSAndroid Build Coastguard Worker         SkReadBuffer badReadBuffer{data->data(), data->size()};
254*c8dee2aaSAndroid Build Coastguard Worker         dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
255*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, badReadBuffer.isValid());  // Reading glyph metrics is okay.
256*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, dstGlyph.has_value());
257*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
258*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
259*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
260*c8dee2aaSAndroid Build Coastguard Worker 
261*c8dee2aaSAndroid Build Coastguard Worker         dstGlyph->addPathFromBuffer(badReadBuffer, &alloc);
262*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
263*c8dee2aaSAndroid Build Coastguard Worker         REPORTER_ASSERT(reporter, !dstGlyph->setPathHasBeenCalled());
264*c8dee2aaSAndroid Build Coastguard Worker     }
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkGlyph_SendWithDrawable,reporter)267*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkGlyph_SendWithDrawable, reporter) {
268*c8dee2aaSAndroid Build Coastguard Worker     SkArenaAlloc alloc{256};
269*c8dee2aaSAndroid Build Coastguard Worker     SkGlyph srcGlyph{SkPackedGlyphID{(SkGlyphID)12}};
270*c8dee2aaSAndroid Build Coastguard Worker     SkGlyphTestPeer::SetGlyph1(&srcGlyph);
271*c8dee2aaSAndroid Build Coastguard Worker 
272*c8dee2aaSAndroid Build Coastguard Worker     class TestDrawable final : public SkDrawable {
273*c8dee2aaSAndroid Build Coastguard Worker     public:
274*c8dee2aaSAndroid Build Coastguard Worker         TestDrawable(SkRect rect) : fRect(rect) {}
275*c8dee2aaSAndroid Build Coastguard Worker     private:
276*c8dee2aaSAndroid Build Coastguard Worker         const SkRect fRect;
277*c8dee2aaSAndroid Build Coastguard Worker         SkRect onGetBounds() override { return fRect;  }
278*c8dee2aaSAndroid Build Coastguard Worker         size_t onApproximateBytesUsed() override {
279*c8dee2aaSAndroid Build Coastguard Worker             return 0;
280*c8dee2aaSAndroid Build Coastguard Worker         }
281*c8dee2aaSAndroid Build Coastguard Worker         void onDraw(SkCanvas* canvas) override {
282*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint;
283*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawRect(fRect, paint);
284*c8dee2aaSAndroid Build Coastguard Worker         }
285*c8dee2aaSAndroid Build Coastguard Worker     };
286*c8dee2aaSAndroid Build Coastguard Worker 
287*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkDrawable> srcDrawable = sk_make_sp<TestDrawable>(srcGlyph.rect());
288*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.setDrawable(&alloc, srcDrawable);
289*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.setDrawableHasBeenCalled());
290*c8dee2aaSAndroid Build Coastguard Worker 
291*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer writeBuffer({});
292*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenMetrics(writeBuffer);
293*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenDrawable(writeBuffer);
294*c8dee2aaSAndroid Build Coastguard Worker 
295*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data = writeBuffer.snapshotAsData();
296*c8dee2aaSAndroid Build Coastguard Worker 
297*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer readBuffer{data->data(), data->size()};
298*c8dee2aaSAndroid Build Coastguard Worker     std::optional<SkGlyph> dstGlyph = SkGlyph::MakeFromBuffer(readBuffer);
299*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
300*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph.has_value());
301*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
302*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
303*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
304*c8dee2aaSAndroid Build Coastguard Worker 
305*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph->addDrawableFromBuffer(readBuffer, &alloc);
306*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
307*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph->setDrawableHasBeenCalled());
308*c8dee2aaSAndroid Build Coastguard Worker     SkDrawable* dstDrawable = dstGlyph->drawable();
309*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstDrawable->getBounds() == srcDrawable->getBounds());
310*c8dee2aaSAndroid Build Coastguard Worker 
311*c8dee2aaSAndroid Build Coastguard Worker     // Add good metrics, but mess up drawable data
312*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer badWriteBuffer({});
313*c8dee2aaSAndroid Build Coastguard Worker     srcGlyph.flattenMetrics(badWriteBuffer);
314*c8dee2aaSAndroid Build Coastguard Worker     badWriteBuffer.writeInt(7);
315*c8dee2aaSAndroid Build Coastguard Worker     badWriteBuffer.writeInt(8);
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker     data = badWriteBuffer.snapshotAsData();
318*c8dee2aaSAndroid Build Coastguard Worker 
319*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer badReadBuffer{data->data(), data->size()};
320*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph = SkGlyph::MakeFromBuffer(badReadBuffer);
321*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, badReadBuffer.isValid());  // Reading glyph metrics is okay.
322*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstGlyph.has_value());
323*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.advanceVector() == dstGlyph->advanceVector());
324*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.rect() == dstGlyph->rect());
325*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcGlyph.maskFormat() == dstGlyph->maskFormat());
326*c8dee2aaSAndroid Build Coastguard Worker 
327*c8dee2aaSAndroid Build Coastguard Worker     dstGlyph->addDrawableFromBuffer(badReadBuffer, &alloc);
328*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
329*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !dstGlyph->setDrawableHasBeenCalled());
330*c8dee2aaSAndroid Build Coastguard Worker }
331*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkPictureBackedGlyphDrawable_Basic,reporter)332*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPictureBackedGlyphDrawable_Basic, reporter) {
333*c8dee2aaSAndroid Build Coastguard Worker     class TestDrawable final : public SkDrawable {
334*c8dee2aaSAndroid Build Coastguard Worker     public:
335*c8dee2aaSAndroid Build Coastguard Worker         TestDrawable(SkRect rect) : fRect(rect) {}
336*c8dee2aaSAndroid Build Coastguard Worker     private:
337*c8dee2aaSAndroid Build Coastguard Worker         const SkRect fRect;
338*c8dee2aaSAndroid Build Coastguard Worker         SkRect onGetBounds() override { return fRect;  }
339*c8dee2aaSAndroid Build Coastguard Worker         size_t onApproximateBytesUsed() override {
340*c8dee2aaSAndroid Build Coastguard Worker             return 0;
341*c8dee2aaSAndroid Build Coastguard Worker         }
342*c8dee2aaSAndroid Build Coastguard Worker         void onDraw(SkCanvas* canvas) override {
343*c8dee2aaSAndroid Build Coastguard Worker             SkPaint paint;
344*c8dee2aaSAndroid Build Coastguard Worker             canvas->drawRect(fRect, paint);
345*c8dee2aaSAndroid Build Coastguard Worker         }
346*c8dee2aaSAndroid Build Coastguard Worker     };
347*c8dee2aaSAndroid Build Coastguard Worker 
348*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkDrawable> srcDrawable = sk_make_sp<TestDrawable>(SkRect::MakeWH(10, 20));
349*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer writeBuffer({});
350*c8dee2aaSAndroid Build Coastguard Worker     SkPictureBackedGlyphDrawable::FlattenDrawable(writeBuffer, srcDrawable.get());
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkData> data = writeBuffer.snapshotAsData();
353*c8dee2aaSAndroid Build Coastguard Worker 
354*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer readBuffer{data->data(), data->size()};
355*c8dee2aaSAndroid Build Coastguard Worker 
356*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPictureBackedGlyphDrawable> dstDrawable =
357*c8dee2aaSAndroid Build Coastguard Worker             SkPictureBackedGlyphDrawable::MakeFromBuffer(readBuffer);
358*c8dee2aaSAndroid Build Coastguard Worker 
359*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, readBuffer.isValid());
360*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, dstDrawable != nullptr);
361*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, srcDrawable->getBounds() == dstDrawable->getBounds());
362*c8dee2aaSAndroid Build Coastguard Worker 
363*c8dee2aaSAndroid Build Coastguard Worker     SkBinaryWriteBuffer badWriteBuffer({});
364*c8dee2aaSAndroid Build Coastguard Worker     badWriteBuffer.writeInt(7);
365*c8dee2aaSAndroid Build Coastguard Worker     badWriteBuffer.writeInt(8);
366*c8dee2aaSAndroid Build Coastguard Worker 
367*c8dee2aaSAndroid Build Coastguard Worker     data = badWriteBuffer.snapshotAsData();
368*c8dee2aaSAndroid Build Coastguard Worker 
369*c8dee2aaSAndroid Build Coastguard Worker     SkReadBuffer badReadBuffer{data->data(), data->size()};
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPictureBackedGlyphDrawable> badDrawable =
372*c8dee2aaSAndroid Build Coastguard Worker             SkPictureBackedGlyphDrawable::MakeFromBuffer(badReadBuffer);
373*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, badDrawable == nullptr);
374*c8dee2aaSAndroid Build Coastguard Worker     REPORTER_ASSERT(reporter, !badReadBuffer.isValid());
375*c8dee2aaSAndroid Build Coastguard Worker }
376*c8dee2aaSAndroid Build Coastguard Worker 
make_sksl_drawable()377*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkDrawable> make_sksl_drawable() {
378*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect = SkRect::MakeWH(50, 50);
379*c8dee2aaSAndroid Build Coastguard Worker 
380*c8dee2aaSAndroid Build Coastguard Worker     SkPictureRecorder recorder;
381*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = recorder.beginRecording(rect);
382*c8dee2aaSAndroid Build Coastguard Worker 
383*c8dee2aaSAndroid Build Coastguard Worker     const sk_sp<SkRuntimeEffect> effect =
384*c8dee2aaSAndroid Build Coastguard Worker             SkRuntimeEffect::MakeForShader(
385*c8dee2aaSAndroid Build Coastguard Worker                     SkString("half4 main(float2 xy) { return half4(0, 1, 0, 1); }"))
386*c8dee2aaSAndroid Build Coastguard Worker                     .effect;
387*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(effect);
388*c8dee2aaSAndroid Build Coastguard Worker 
389*c8dee2aaSAndroid Build Coastguard Worker     SkPaint paint;
390*c8dee2aaSAndroid Build Coastguard Worker     paint.setShader(effect->makeShader(/*uniforms=*/nullptr, /*children=*/{}));
391*c8dee2aaSAndroid Build Coastguard Worker     // See note in make_nested_sksl_drawable: We include enough ops that this drawable will be
392*c8dee2aaSAndroid Build Coastguard Worker     // preserved as a sub-picture when we wrap it in a second layer.
393*c8dee2aaSAndroid Build Coastguard Worker     for (int i = 0; i < kMaxPictureOpsToUnrollInsteadOfRef + 1; ++i) {
394*c8dee2aaSAndroid Build Coastguard Worker         canvas->drawRect(rect, paint);
395*c8dee2aaSAndroid Build Coastguard Worker     }
396*c8dee2aaSAndroid Build Coastguard Worker 
397*c8dee2aaSAndroid Build Coastguard Worker     return recorder.finishRecordingAsDrawable();
398*c8dee2aaSAndroid Build Coastguard Worker }
399*c8dee2aaSAndroid Build Coastguard Worker 
make_nested_sksl_drawable()400*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkDrawable> make_nested_sksl_drawable() {
401*c8dee2aaSAndroid Build Coastguard Worker     SkRect rect = SkRect::MakeWH(50, 50);
402*c8dee2aaSAndroid Build Coastguard Worker 
403*c8dee2aaSAndroid Build Coastguard Worker     SkPictureRecorder recorder;
404*c8dee2aaSAndroid Build Coastguard Worker     SkCanvas* canvas = recorder.beginRecording(rect);
405*c8dee2aaSAndroid Build Coastguard Worker 
406*c8dee2aaSAndroid Build Coastguard Worker     auto sksl_drawable = make_sksl_drawable();
407*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<SkPicture> sksl_picture = sksl_drawable->makePictureSnapshot();
408*c8dee2aaSAndroid Build Coastguard Worker 
409*c8dee2aaSAndroid Build Coastguard Worker     // We need to ensure that the op count of our picture is larger than this threshold, so we
410*c8dee2aaSAndroid Build Coastguard Worker     // actually get a nested (embedded) picture, rather than just playing the ops back.
411*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(sksl_picture->approximateOpCount() > kMaxPictureOpsToUnrollInsteadOfRef);
412*c8dee2aaSAndroid Build Coastguard Worker     canvas->drawPicture(sksl_picture);
413*c8dee2aaSAndroid Build Coastguard Worker 
414*c8dee2aaSAndroid Build Coastguard Worker     return recorder.finishRecordingAsDrawable();
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker 
DEF_TEST(SkPictureBackedGlyphDrawable_SkSL,reporter)417*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(SkPictureBackedGlyphDrawable_SkSL, reporter) {
418*c8dee2aaSAndroid Build Coastguard Worker     for (const sk_sp<SkDrawable>& drawable : {make_sksl_drawable(), make_nested_sksl_drawable()}) {
419*c8dee2aaSAndroid Build Coastguard Worker         for (bool allowSkSL : {true, false}) {
420*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, drawable);
421*c8dee2aaSAndroid Build Coastguard Worker 
422*c8dee2aaSAndroid Build Coastguard Worker             SkBinaryWriteBuffer writeBuffer({});
423*c8dee2aaSAndroid Build Coastguard Worker             SkPictureBackedGlyphDrawable::FlattenDrawable(writeBuffer, drawable.get());
424*c8dee2aaSAndroid Build Coastguard Worker 
425*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkData> data = writeBuffer.snapshotAsData();
426*c8dee2aaSAndroid Build Coastguard Worker 
427*c8dee2aaSAndroid Build Coastguard Worker             SkReadBuffer readBuffer{data->data(), data->size()};
428*c8dee2aaSAndroid Build Coastguard Worker             readBuffer.setAllowSkSL(allowSkSL);
429*c8dee2aaSAndroid Build Coastguard Worker 
430*c8dee2aaSAndroid Build Coastguard Worker             sk_sp<SkPictureBackedGlyphDrawable> dstDrawable =
431*c8dee2aaSAndroid Build Coastguard Worker                     SkPictureBackedGlyphDrawable::MakeFromBuffer(readBuffer);
432*c8dee2aaSAndroid Build Coastguard Worker 
433*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, readBuffer.isValid() == allowSkSL);
434*c8dee2aaSAndroid Build Coastguard Worker             REPORTER_ASSERT(reporter, !!dstDrawable == allowSkSL);
435*c8dee2aaSAndroid Build Coastguard Worker         }
436*c8dee2aaSAndroid Build Coastguard Worker     }
437*c8dee2aaSAndroid Build Coastguard Worker }
438