1 /*
2 * Copyright 2022 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/SkData.h"
9 #include "include/core/SkFont.h"
10 #include "include/core/SkRefCnt.h"
11 #include "include/core/SkSpan.h"
12 #include "include/core/SkTypes.h"
13 #include "src/base/SkZip.h"
14 #include "src/core/SkDescriptor.h"
15 #include "src/core/SkGlyph.h"
16 #include "src/core/SkReadBuffer.h"
17 #include "src/core/SkStrike.h"
18 #include "src/core/SkStrikeSpec.h"
19 #include "src/core/SkWriteBuffer.h"
20 #include "src/text/StrikeForGPU.h"
21 #include "src/text/gpu/GlyphVector.h"
22 #include "src/text/gpu/SubRunAllocator.h"
23 #include "tests/Test.h"
24
25 #include <initializer_list>
26 #include <limits.h>
27 #include <optional>
28 #include <utility>
29
30 using GlyphVector = sktext::gpu::GlyphVector;
31 using SubRunAllocator = sktext::gpu::SubRunAllocator;
32
33 namespace sktext::gpu {
34 class GlyphVectorTestingPeer {
35 public:
GetDescriptor(const GlyphVector & v)36 static const SkDescriptor& GetDescriptor(const GlyphVector& v) {
37 return v.fStrikePromise.descriptor();
38 }
GetGlyphs(const GlyphVector & v)39 static SkSpan<GlyphVector::Variant> GetGlyphs(const GlyphVector& v) {
40 return v.fGlyphs;
41 }
42 };
43
DEF_TEST(GlyphVector_Serialization,r)44 DEF_TEST(GlyphVector_Serialization, r) {
45 SkFont font;
46 auto [strikeSpec, _] = SkStrikeSpec::MakeCanonicalized(font);
47
48 SubRunAllocator alloc;
49
50 const int N = 10;
51 SkPackedGlyphID* glyphs = alloc.makePODArray<SkPackedGlyphID>(N);
52 for (int i = 0; i < N; i++) {
53 glyphs[i] = SkPackedGlyphID(SkGlyphID(i));
54 }
55
56 SkStrikePromise promise{strikeSpec.findOrCreateStrike()};
57
58 GlyphVector src = GlyphVector::Make(std::move(promise), SkSpan(glyphs, N), &alloc);
59
60 SkBinaryWriteBuffer wBuffer;
61 src.flatten(wBuffer);
62
63 auto data = wBuffer.snapshotAsData();
64 SkReadBuffer rBuffer{data->data(), data->size()};
65 auto dst = GlyphVector::MakeFromBuffer(rBuffer, nullptr, &alloc);
66 REPORTER_ASSERT(r, dst.has_value());
67 REPORTER_ASSERT(r,
68 GlyphVectorTestingPeer::GetDescriptor(src) ==
69 GlyphVectorTestingPeer::GetDescriptor(*dst));
70
71 auto srcGlyphs = GlyphVectorTestingPeer::GetGlyphs(src);
72 auto dstGlyphs = GlyphVectorTestingPeer::GetGlyphs(*dst);
73 for (auto [srcGlyphID, dstGlyphID] : SkMakeZip(srcGlyphs, dstGlyphs)) {
74 REPORTER_ASSERT(r, srcGlyphID.packedGlyphID == dstGlyphID.packedGlyphID);
75 }
76 }
77
DEF_TEST(GlyphVector_BadLengths,r)78 DEF_TEST(GlyphVector_BadLengths, r) {
79 auto [strikeSpec, _] = SkStrikeSpec::MakeCanonicalized(SkFont());
80
81 // Strike to keep in the strike cache.
82 auto strike = strikeSpec.findOrCreateStrike();
83
84 // Be sure to keep the strike alive. The promise to serialize as the first part of the
85 // GlyphVector.
86 SkStrikePromise promise{sk_sp<SkStrike>(strike)};
87 {
88 // Make broken stream by hand - zero length
89 SkBinaryWriteBuffer wBuffer;
90 promise.flatten(wBuffer);
91 wBuffer.write32(0); // length
92 auto data = wBuffer.snapshotAsData();
93 SkReadBuffer rBuffer{data->data(), data->size()};
94 SubRunAllocator alloc;
95 auto dst = GlyphVector::MakeFromBuffer(rBuffer, nullptr, &alloc);
96 REPORTER_ASSERT(r, !dst.has_value());
97 }
98
99 {
100 // Make broken stream by hand - zero length
101 SkBinaryWriteBuffer wBuffer;
102 promise.flatten(wBuffer);
103 // Make broken stream by hand - stream is too short
104 wBuffer.write32(5); // length
105 wBuffer.writeUInt(12); // random data
106 wBuffer.writeUInt(12); // random data
107 wBuffer.writeUInt(12); // random data
108 auto data = wBuffer.snapshotAsData();
109 SkReadBuffer rBuffer{data->data(), data->size()};
110 SubRunAllocator alloc;
111 auto dst = GlyphVector::MakeFromBuffer(rBuffer, nullptr, &alloc);
112 REPORTER_ASSERT(r, !dst.has_value());
113 }
114
115 {
116 // Make broken stream by hand - length out of range of safe calculations
117 SkBinaryWriteBuffer wBuffer;
118 promise.flatten(wBuffer);
119 wBuffer.write32(INT_MAX - 10); // length
120 wBuffer.writeUInt(12); // random data
121 wBuffer.writeUInt(12); // random data
122 wBuffer.writeUInt(12); // random data
123 auto data = wBuffer.snapshotAsData();
124 SkReadBuffer rBuffer{data->data(), data->size()};
125 SubRunAllocator alloc;
126 auto dst = GlyphVector::MakeFromBuffer(rBuffer, nullptr, &alloc);
127 REPORTER_ASSERT(r, !dst.has_value());
128 }
129 }
130
131 } // namespace sktext::gpu
132