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