1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2014 Google Inc.
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/SkColor.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFont.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontStyle.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkFontTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImage.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkImageInfo.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPaint.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSerialProcs.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurface.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTextBlob.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypeface.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTArray.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTemplates.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkTo.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkFontPriv.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTextBlobPriv.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "tests/Test.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "tools/ToolUtils.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "tools/fonts/FontToolUtils.h"
34*c8dee2aaSAndroid Build Coastguard Worker
35*c8dee2aaSAndroid Build Coastguard Worker #include <algorithm>
36*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
37*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
38*c8dee2aaSAndroid Build Coastguard Worker #include <string>
39*c8dee2aaSAndroid Build Coastguard Worker
40*c8dee2aaSAndroid Build Coastguard Worker using namespace skia_private;
41*c8dee2aaSAndroid Build Coastguard Worker
42*c8dee2aaSAndroid Build Coastguard Worker class TextBlobTester {
43*c8dee2aaSAndroid Build Coastguard Worker public:
44*c8dee2aaSAndroid Build Coastguard Worker // This unit test feeds an SkTextBlobBuilder various runs then checks to see if
45*c8dee2aaSAndroid Build Coastguard Worker // the result contains the provided data and merges runs when appropriate.
TestBuilder(skiatest::Reporter * reporter)46*c8dee2aaSAndroid Build Coastguard Worker static void TestBuilder(skiatest::Reporter* reporter) {
47*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder builder;
48*c8dee2aaSAndroid Build Coastguard Worker
49*c8dee2aaSAndroid Build Coastguard Worker // empty run set
50*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, nullptr, 0, nullptr, 0);
51*c8dee2aaSAndroid Build Coastguard Worker
52*c8dee2aaSAndroid Build Coastguard Worker RunDef set1[] = {
53*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 100 },
54*c8dee2aaSAndroid Build Coastguard Worker };
55*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set1, std::size(set1), set1, std::size(set1));
56*c8dee2aaSAndroid Build Coastguard Worker
57*c8dee2aaSAndroid Build Coastguard Worker RunDef set2[] = {
58*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 100 },
59*c8dee2aaSAndroid Build Coastguard Worker };
60*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set2, std::size(set2), set2, std::size(set2));
61*c8dee2aaSAndroid Build Coastguard Worker
62*c8dee2aaSAndroid Build Coastguard Worker RunDef set3[] = {
63*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 100, 100 },
64*c8dee2aaSAndroid Build Coastguard Worker };
65*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set3, std::size(set3), set3, std::size(set3));
66*c8dee2aaSAndroid Build Coastguard Worker
67*c8dee2aaSAndroid Build Coastguard Worker RunDef set4[] = {
68*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
69*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
70*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
71*c8dee2aaSAndroid Build Coastguard Worker };
72*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set4, std::size(set4), set4, std::size(set4));
73*c8dee2aaSAndroid Build Coastguard Worker
74*c8dee2aaSAndroid Build Coastguard Worker RunDef set5[] = {
75*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 150 },
76*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 200, 150 },
77*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 300, 250 },
78*c8dee2aaSAndroid Build Coastguard Worker };
79*c8dee2aaSAndroid Build Coastguard Worker RunDef mergedSet5[] = {
80*c8dee2aaSAndroid Build Coastguard Worker { 256, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 150 },
81*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 250 },
82*c8dee2aaSAndroid Build Coastguard Worker };
83*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set5, std::size(set5), mergedSet5,
84*c8dee2aaSAndroid Build Coastguard Worker std::size(mergedSet5));
85*c8dee2aaSAndroid Build Coastguard Worker
86*c8dee2aaSAndroid Build Coastguard Worker RunDef set6[] = {
87*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 100, 100 },
88*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 200, 200 },
89*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 300, 300 },
90*c8dee2aaSAndroid Build Coastguard Worker };
91*c8dee2aaSAndroid Build Coastguard Worker RunDef mergedSet6[] = {
92*c8dee2aaSAndroid Build Coastguard Worker { 384, SkTextBlobRunIterator::kFull_Positioning, 0, 0 },
93*c8dee2aaSAndroid Build Coastguard Worker };
94*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set6, std::size(set6), mergedSet6,
95*c8dee2aaSAndroid Build Coastguard Worker std::size(mergedSet6));
96*c8dee2aaSAndroid Build Coastguard Worker
97*c8dee2aaSAndroid Build Coastguard Worker RunDef set7[] = {
98*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
99*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
100*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 150 },
101*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 200, 150 },
102*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 350 },
103*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 350 },
104*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 },
105*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 },
106*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 100, 550 },
107*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 200, 650 },
108*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 750 },
109*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kFull_Positioning, 400, 850 },
110*c8dee2aaSAndroid Build Coastguard Worker };
111*c8dee2aaSAndroid Build Coastguard Worker RunDef mergedSet7[] = {
112*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
113*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 150 },
114*c8dee2aaSAndroid Build Coastguard Worker { 256, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 150 },
115*c8dee2aaSAndroid Build Coastguard Worker { 256, SkTextBlobRunIterator::kFull_Positioning, 0, 0 },
116*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 },
117*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kDefault_Positioning, 100, 450 },
118*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 550 },
119*c8dee2aaSAndroid Build Coastguard Worker { 128, SkTextBlobRunIterator::kHorizontal_Positioning, 0, 650 },
120*c8dee2aaSAndroid Build Coastguard Worker { 256, SkTextBlobRunIterator::kFull_Positioning, 0, 0 },
121*c8dee2aaSAndroid Build Coastguard Worker };
122*c8dee2aaSAndroid Build Coastguard Worker RunBuilderTest(reporter, builder, set7, std::size(set7), mergedSet7,
123*c8dee2aaSAndroid Build Coastguard Worker std::size(mergedSet7));
124*c8dee2aaSAndroid Build Coastguard Worker }
125*c8dee2aaSAndroid Build Coastguard Worker
126*c8dee2aaSAndroid Build Coastguard Worker // This unit test verifies blob bounds computation.
TestBounds(skiatest::Reporter * reporter)127*c8dee2aaSAndroid Build Coastguard Worker static void TestBounds(skiatest::Reporter* reporter) {
128*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder builder;
129*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultFont();
130*c8dee2aaSAndroid Build Coastguard Worker
131*c8dee2aaSAndroid Build Coastguard Worker // Explicit bounds.
132*c8dee2aaSAndroid Build Coastguard Worker {
133*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
134*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !blob);
135*c8dee2aaSAndroid Build Coastguard Worker }
136*c8dee2aaSAndroid Build Coastguard Worker
137*c8dee2aaSAndroid Build Coastguard Worker {
138*c8dee2aaSAndroid Build Coastguard Worker SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
139*c8dee2aaSAndroid Build Coastguard Worker builder.allocRun(font, 16, 0, 0, &r1);
140*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
141*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob->bounds() == r1);
142*c8dee2aaSAndroid Build Coastguard Worker }
143*c8dee2aaSAndroid Build Coastguard Worker
144*c8dee2aaSAndroid Build Coastguard Worker {
145*c8dee2aaSAndroid Build Coastguard Worker SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
146*c8dee2aaSAndroid Build Coastguard Worker builder.allocRunPosH(font, 16, 0, &r1);
147*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
148*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob->bounds() == r1);
149*c8dee2aaSAndroid Build Coastguard Worker }
150*c8dee2aaSAndroid Build Coastguard Worker
151*c8dee2aaSAndroid Build Coastguard Worker {
152*c8dee2aaSAndroid Build Coastguard Worker SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
153*c8dee2aaSAndroid Build Coastguard Worker builder.allocRunPos(font, 16, &r1);
154*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
155*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob->bounds() == r1);
156*c8dee2aaSAndroid Build Coastguard Worker }
157*c8dee2aaSAndroid Build Coastguard Worker
158*c8dee2aaSAndroid Build Coastguard Worker {
159*c8dee2aaSAndroid Build Coastguard Worker SkRect r1 = SkRect::MakeXYWH(10, 10, 20, 20);
160*c8dee2aaSAndroid Build Coastguard Worker SkRect r2 = SkRect::MakeXYWH(15, 20, 50, 50);
161*c8dee2aaSAndroid Build Coastguard Worker SkRect r3 = SkRect::MakeXYWH(0, 5, 10, 5);
162*c8dee2aaSAndroid Build Coastguard Worker
163*c8dee2aaSAndroid Build Coastguard Worker builder.allocRun(font, 16, 0, 0, &r1);
164*c8dee2aaSAndroid Build Coastguard Worker builder.allocRunPosH(font, 16, 0, &r2);
165*c8dee2aaSAndroid Build Coastguard Worker builder.allocRunPos(font, 16, &r3);
166*c8dee2aaSAndroid Build Coastguard Worker
167*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
168*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob->bounds() == SkRect::MakeXYWH(0, 5, 65, 65));
169*c8dee2aaSAndroid Build Coastguard Worker }
170*c8dee2aaSAndroid Build Coastguard Worker
171*c8dee2aaSAndroid Build Coastguard Worker {
172*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
173*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !blob);
174*c8dee2aaSAndroid Build Coastguard Worker }
175*c8dee2aaSAndroid Build Coastguard Worker
176*c8dee2aaSAndroid Build Coastguard Worker // Implicit bounds
177*c8dee2aaSAndroid Build Coastguard Worker
178*c8dee2aaSAndroid Build Coastguard Worker {
179*c8dee2aaSAndroid Build Coastguard Worker // Exercise the empty bounds path, and ensure that RunRecord-aligned pos buffers
180*c8dee2aaSAndroid Build Coastguard Worker // don't trigger asserts (http://crbug.com/542643).
181*c8dee2aaSAndroid Build Coastguard Worker font.setSize(0);
182*c8dee2aaSAndroid Build Coastguard Worker
183*c8dee2aaSAndroid Build Coastguard Worker const char* txt = "BOOO";
184*c8dee2aaSAndroid Build Coastguard Worker const size_t txtLen = strlen(txt);
185*c8dee2aaSAndroid Build Coastguard Worker const int glyphCount = font.countText(txt, txtLen, SkTextEncoding::kUTF8);
186*c8dee2aaSAndroid Build Coastguard Worker const SkTextBlobBuilder::RunBuffer& buffer = builder.allocRunPos(font, glyphCount);
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker font.textToGlyphs(txt, txtLen, SkTextEncoding::kUTF8, buffer.glyphs, glyphCount);
189*c8dee2aaSAndroid Build Coastguard Worker
190*c8dee2aaSAndroid Build Coastguard Worker memset(buffer.pos, 0, sizeof(SkScalar) * glyphCount * 2);
191*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
192*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob->bounds().isEmpty());
193*c8dee2aaSAndroid Build Coastguard Worker }
194*c8dee2aaSAndroid Build Coastguard Worker }
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker // Verify that text-related properties are captured in run paints.
TestPaintProps(skiatest::Reporter * reporter)197*c8dee2aaSAndroid Build Coastguard Worker static void TestPaintProps(skiatest::Reporter* reporter) {
198*c8dee2aaSAndroid Build Coastguard Worker SkFont font;
199*c8dee2aaSAndroid Build Coastguard Worker // Kitchen sink font.
200*c8dee2aaSAndroid Build Coastguard Worker font.setSize(42);
201*c8dee2aaSAndroid Build Coastguard Worker font.setScaleX(4.2f);
202*c8dee2aaSAndroid Build Coastguard Worker font.setTypeface(ToolUtils::CreatePortableTypeface("Sans", SkFontStyle::Bold()));
203*c8dee2aaSAndroid Build Coastguard Worker font.setSkewX(0.42f);
204*c8dee2aaSAndroid Build Coastguard Worker font.setHinting(SkFontHinting::kFull);
205*c8dee2aaSAndroid Build Coastguard Worker font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
206*c8dee2aaSAndroid Build Coastguard Worker font.setEmbolden(true);
207*c8dee2aaSAndroid Build Coastguard Worker font.setLinearMetrics(true);
208*c8dee2aaSAndroid Build Coastguard Worker font.setSubpixel(true);
209*c8dee2aaSAndroid Build Coastguard Worker font.setEmbeddedBitmaps(true);
210*c8dee2aaSAndroid Build Coastguard Worker font.setForceAutoHinting(true);
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker // Ensure we didn't pick default values by mistake.
213*c8dee2aaSAndroid Build Coastguard Worker SkFont defaultFont = ToolUtils::DefaultFont();
214*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.getSize() != font.getSize());
215*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.getScaleX() != font.getScaleX());
216*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.getTypeface() != font.getTypeface());
217*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.getSkewX() != font.getSkewX());
218*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.getHinting() != font.getHinting());
219*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.getEdging() != font.getEdging());
220*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.isEmbolden() != font.isEmbolden());
221*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.isLinearMetrics() != font.isLinearMetrics());
222*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.isSubpixel() != font.isSubpixel());
223*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter,
224*c8dee2aaSAndroid Build Coastguard Worker defaultFont.isEmbeddedBitmaps() != font.isEmbeddedBitmaps());
225*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, defaultFont.isForceAutoHinting() != font.isForceAutoHinting());
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder builder;
228*c8dee2aaSAndroid Build Coastguard Worker AddRun(font, 1, SkTextBlobRunIterator::kDefault_Positioning, SkPoint::Make(0, 0), builder);
229*c8dee2aaSAndroid Build Coastguard Worker AddRun(font, 1, SkTextBlobRunIterator::kHorizontal_Positioning, SkPoint::Make(0, 0),
230*c8dee2aaSAndroid Build Coastguard Worker builder);
231*c8dee2aaSAndroid Build Coastguard Worker AddRun(font, 1, SkTextBlobRunIterator::kFull_Positioning, SkPoint::Make(0, 0), builder);
232*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
233*c8dee2aaSAndroid Build Coastguard Worker
234*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobRunIterator it(blob.get());
235*c8dee2aaSAndroid Build Coastguard Worker while (!it.done()) {
236*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.font() == font);
237*c8dee2aaSAndroid Build Coastguard Worker it.next();
238*c8dee2aaSAndroid Build Coastguard Worker }
239*c8dee2aaSAndroid Build Coastguard Worker
240*c8dee2aaSAndroid Build Coastguard Worker }
241*c8dee2aaSAndroid Build Coastguard Worker
242*c8dee2aaSAndroid Build Coastguard Worker private:
243*c8dee2aaSAndroid Build Coastguard Worker struct RunDef {
244*c8dee2aaSAndroid Build Coastguard Worker unsigned count;
245*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobRunIterator::GlyphPositioning pos;
246*c8dee2aaSAndroid Build Coastguard Worker SkScalar x, y;
247*c8dee2aaSAndroid Build Coastguard Worker };
248*c8dee2aaSAndroid Build Coastguard Worker
RunBuilderTest(skiatest::Reporter * reporter,SkTextBlobBuilder & builder,const RunDef in[],unsigned inCount,const RunDef out[],unsigned outCount)249*c8dee2aaSAndroid Build Coastguard Worker static void RunBuilderTest(skiatest::Reporter* reporter, SkTextBlobBuilder& builder,
250*c8dee2aaSAndroid Build Coastguard Worker const RunDef in[], unsigned inCount,
251*c8dee2aaSAndroid Build Coastguard Worker const RunDef out[], unsigned outCount) {
252*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultFont();
253*c8dee2aaSAndroid Build Coastguard Worker
254*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < inCount; ++i) {
255*c8dee2aaSAndroid Build Coastguard Worker AddRun(font, in[i].count, in[i].pos, SkPoint::Make(in[i].x, in[i].y), builder);
256*c8dee2aaSAndroid Build Coastguard Worker }
257*c8dee2aaSAndroid Build Coastguard Worker
258*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(builder.make());
259*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, (inCount > 0) == SkToBool(blob));
260*c8dee2aaSAndroid Build Coastguard Worker if (!blob) {
261*c8dee2aaSAndroid Build Coastguard Worker return;
262*c8dee2aaSAndroid Build Coastguard Worker }
263*c8dee2aaSAndroid Build Coastguard Worker
264*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobRunIterator it(blob.get());
265*c8dee2aaSAndroid Build Coastguard Worker for (unsigned i = 0; i < outCount; ++i) {
266*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !it.done());
267*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, out[i].pos == it.positioning());
268*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, out[i].count == it.glyphCount());
269*c8dee2aaSAndroid Build Coastguard Worker if (SkTextBlobRunIterator::kDefault_Positioning == out[i].pos) {
270*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, out[i].x == it.offset().x());
271*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, out[i].y == it.offset().y());
272*c8dee2aaSAndroid Build Coastguard Worker } else if (SkTextBlobRunIterator::kHorizontal_Positioning == out[i].pos) {
273*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, out[i].y == it.offset().y());
274*c8dee2aaSAndroid Build Coastguard Worker }
275*c8dee2aaSAndroid Build Coastguard Worker
276*c8dee2aaSAndroid Build Coastguard Worker for (unsigned k = 0; k < it.glyphCount(); ++k) {
277*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, k % 128 == it.glyphs()[k]);
278*c8dee2aaSAndroid Build Coastguard Worker if (SkTextBlobRunIterator::kHorizontal_Positioning == it.positioning()) {
279*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k]);
280*c8dee2aaSAndroid Build Coastguard Worker } else if (SkTextBlobRunIterator::kFull_Positioning == it.positioning()) {
281*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkIntToScalar(k % 128) == it.pos()[k * 2]);
282*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, -SkIntToScalar(k % 128) == it.pos()[k * 2 + 1]);
283*c8dee2aaSAndroid Build Coastguard Worker }
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker
286*c8dee2aaSAndroid Build Coastguard Worker it.next();
287*c8dee2aaSAndroid Build Coastguard Worker }
288*c8dee2aaSAndroid Build Coastguard Worker
289*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.done());
290*c8dee2aaSAndroid Build Coastguard Worker }
291*c8dee2aaSAndroid Build Coastguard Worker
AddRun(const SkFont & font,int count,SkTextBlobRunIterator::GlyphPositioning pos,const SkPoint & offset,SkTextBlobBuilder & builder,const SkRect * bounds=nullptr)292*c8dee2aaSAndroid Build Coastguard Worker static void AddRun(const SkFont& font, int count, SkTextBlobRunIterator::GlyphPositioning pos,
293*c8dee2aaSAndroid Build Coastguard Worker const SkPoint& offset, SkTextBlobBuilder& builder,
294*c8dee2aaSAndroid Build Coastguard Worker const SkRect* bounds = nullptr) {
295*c8dee2aaSAndroid Build Coastguard Worker switch (pos) {
296*c8dee2aaSAndroid Build Coastguard Worker case SkTextBlobRunIterator::kDefault_Positioning: {
297*c8dee2aaSAndroid Build Coastguard Worker const SkTextBlobBuilder::RunBuffer& rb = builder.allocRun(font, count, offset.x(),
298*c8dee2aaSAndroid Build Coastguard Worker offset.y(), bounds);
299*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i) {
300*c8dee2aaSAndroid Build Coastguard Worker rb.glyphs[i] = i;
301*c8dee2aaSAndroid Build Coastguard Worker }
302*c8dee2aaSAndroid Build Coastguard Worker } break;
303*c8dee2aaSAndroid Build Coastguard Worker case SkTextBlobRunIterator::kHorizontal_Positioning: {
304*c8dee2aaSAndroid Build Coastguard Worker const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPosH(font, count, offset.y(),
305*c8dee2aaSAndroid Build Coastguard Worker bounds);
306*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i) {
307*c8dee2aaSAndroid Build Coastguard Worker rb.glyphs[i] = i;
308*c8dee2aaSAndroid Build Coastguard Worker rb.pos[i] = SkIntToScalar(i);
309*c8dee2aaSAndroid Build Coastguard Worker }
310*c8dee2aaSAndroid Build Coastguard Worker } break;
311*c8dee2aaSAndroid Build Coastguard Worker case SkTextBlobRunIterator::kFull_Positioning: {
312*c8dee2aaSAndroid Build Coastguard Worker const SkTextBlobBuilder::RunBuffer& rb = builder.allocRunPos(font, count, bounds);
313*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < count; ++i) {
314*c8dee2aaSAndroid Build Coastguard Worker rb.glyphs[i] = i;
315*c8dee2aaSAndroid Build Coastguard Worker rb.pos[i * 2] = SkIntToScalar(i);
316*c8dee2aaSAndroid Build Coastguard Worker rb.pos[i * 2 + 1] = -SkIntToScalar(i);
317*c8dee2aaSAndroid Build Coastguard Worker }
318*c8dee2aaSAndroid Build Coastguard Worker } break;
319*c8dee2aaSAndroid Build Coastguard Worker default:
320*c8dee2aaSAndroid Build Coastguard Worker SK_ABORT("unhandled positioning value");
321*c8dee2aaSAndroid Build Coastguard Worker }
322*c8dee2aaSAndroid Build Coastguard Worker }
323*c8dee2aaSAndroid Build Coastguard Worker };
324*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(TextBlob_builder,reporter)325*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_builder, reporter) {
326*c8dee2aaSAndroid Build Coastguard Worker TextBlobTester::TestBuilder(reporter);
327*c8dee2aaSAndroid Build Coastguard Worker TextBlobTester::TestBounds(reporter);
328*c8dee2aaSAndroid Build Coastguard Worker }
329*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(TextBlob_paint,reporter)330*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_paint, reporter) {
331*c8dee2aaSAndroid Build Coastguard Worker TextBlobTester::TestPaintProps(reporter);
332*c8dee2aaSAndroid Build Coastguard Worker }
333*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(TextBlob_extended,reporter)334*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_extended, reporter) {
335*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder textBlobBuilder;
336*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultFont();
337*c8dee2aaSAndroid Build Coastguard Worker const char text1[] = "Foo";
338*c8dee2aaSAndroid Build Coastguard Worker const char text2[] = "Bar";
339*c8dee2aaSAndroid Build Coastguard Worker
340*c8dee2aaSAndroid Build Coastguard Worker int glyphCount = font.countText(text1, strlen(text1), SkTextEncoding::kUTF8);
341*c8dee2aaSAndroid Build Coastguard Worker AutoTMalloc<uint16_t> glyphs(glyphCount);
342*c8dee2aaSAndroid Build Coastguard Worker (void)font.textToGlyphs(text1, strlen(text1), SkTextEncoding::kUTF8, glyphs.get(), glyphCount);
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker auto run = textBlobBuilder.allocRunText(font, glyphCount, 0, 0, SkToInt(strlen(text2)));
345*c8dee2aaSAndroid Build Coastguard Worker memcpy(run.glyphs, glyphs.get(), sizeof(uint16_t) * glyphCount);
346*c8dee2aaSAndroid Build Coastguard Worker memcpy(run.utf8text, text2, strlen(text2));
347*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < glyphCount; ++i) {
348*c8dee2aaSAndroid Build Coastguard Worker run.clusters[i] = std::min(SkToU32(i), SkToU32(strlen(text2)));
349*c8dee2aaSAndroid Build Coastguard Worker }
350*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob(textBlobBuilder.make());
351*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob);
352*c8dee2aaSAndroid Build Coastguard Worker
353*c8dee2aaSAndroid Build Coastguard Worker for (SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) {
354*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.glyphCount() == (uint32_t)glyphCount);
355*c8dee2aaSAndroid Build Coastguard Worker for (uint32_t i = 0; i < it.glyphCount(); ++i) {
356*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.glyphs()[i] == glyphs[i]);
357*c8dee2aaSAndroid Build Coastguard Worker }
358*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, SkTextBlobRunIterator::kDefault_Positioning == it.positioning());
359*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, (SkPoint{0.0f, 0.0f}) == it.offset());
360*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.textSize() > 0);
361*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.clusters());
362*c8dee2aaSAndroid Build Coastguard Worker for (uint32_t i = 0; i < it.glyphCount(); ++i) {
363*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, i == it.clusters()[i]);
364*c8dee2aaSAndroid Build Coastguard Worker }
365*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, 0 == strncmp(text2, it.text(), it.textSize()));
366*c8dee2aaSAndroid Build Coastguard Worker }
367*c8dee2aaSAndroid Build Coastguard Worker }
368*c8dee2aaSAndroid Build Coastguard Worker
369*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
add_run(SkTextBlobBuilder * builder,const char text[],SkScalar x,SkScalar y,sk_sp<SkTypeface> tf)370*c8dee2aaSAndroid Build Coastguard Worker static void add_run(SkTextBlobBuilder* builder, const char text[], SkScalar x, SkScalar y,
371*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTypeface> tf) {
372*c8dee2aaSAndroid Build Coastguard Worker SkFont font;
373*c8dee2aaSAndroid Build Coastguard Worker font.setEdging(SkFont::Edging::kAntiAlias);
374*c8dee2aaSAndroid Build Coastguard Worker font.setSubpixel(true);
375*c8dee2aaSAndroid Build Coastguard Worker font.setSize(16);
376*c8dee2aaSAndroid Build Coastguard Worker font.setTypeface(tf);
377*c8dee2aaSAndroid Build Coastguard Worker
378*c8dee2aaSAndroid Build Coastguard Worker int glyphCount = font.countText(text, strlen(text), SkTextEncoding::kUTF8);
379*c8dee2aaSAndroid Build Coastguard Worker
380*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder::RunBuffer buffer = builder->allocRun(font, glyphCount, x, y);
381*c8dee2aaSAndroid Build Coastguard Worker
382*c8dee2aaSAndroid Build Coastguard Worker (void)font.textToGlyphs(text, strlen(text), SkTextEncoding::kUTF8, buffer.glyphs, glyphCount);
383*c8dee2aaSAndroid Build Coastguard Worker }
384*c8dee2aaSAndroid Build Coastguard Worker
render(const SkTextBlob * blob)385*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkImage> render(const SkTextBlob* blob) {
386*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(blob);
387*c8dee2aaSAndroid Build Coastguard Worker auto surf = SkSurfaces::Raster(
388*c8dee2aaSAndroid Build Coastguard Worker SkImageInfo::MakeN32Premul(SkScalarRoundToInt(blob->bounds().width()),
389*c8dee2aaSAndroid Build Coastguard Worker SkScalarRoundToInt(blob->bounds().height())));
390*c8dee2aaSAndroid Build Coastguard Worker if (!surf) {
391*c8dee2aaSAndroid Build Coastguard Worker return nullptr; // bounds are empty?
392*c8dee2aaSAndroid Build Coastguard Worker }
393*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->clear(SK_ColorWHITE);
394*c8dee2aaSAndroid Build Coastguard Worker surf->getCanvas()->drawTextBlob(blob, -blob->bounds().left(), -blob->bounds().top(), SkPaint());
395*c8dee2aaSAndroid Build Coastguard Worker return surf->makeImageSnapshot();
396*c8dee2aaSAndroid Build Coastguard Worker }
397*c8dee2aaSAndroid Build Coastguard Worker
SerializeTypeface(SkTypeface * tf,void * ctx)398*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkData> SerializeTypeface(SkTypeface* tf, void* ctx) {
399*c8dee2aaSAndroid Build Coastguard Worker // Do not serialize the empty font.
400*c8dee2aaSAndroid Build Coastguard Worker if (!tf || (tf->countGlyphs() == 0 && tf->getBounds().isEmpty())) {
401*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
402*c8dee2aaSAndroid Build Coastguard Worker }
403*c8dee2aaSAndroid Build Coastguard Worker auto array = (TArray<sk_sp<SkTypeface>>*)ctx;
404*c8dee2aaSAndroid Build Coastguard Worker const size_t idx = array->size();
405*c8dee2aaSAndroid Build Coastguard Worker array->emplace_back(sk_ref_sp(tf));
406*c8dee2aaSAndroid Build Coastguard Worker // In this test, we are deserializing on the same machine, so we don't worry about endianness.
407*c8dee2aaSAndroid Build Coastguard Worker return SkData::MakeWithCopy(&idx, sizeof(idx));
408*c8dee2aaSAndroid Build Coastguard Worker }
409*c8dee2aaSAndroid Build Coastguard Worker
DeserializeTypeface(const void * data,size_t length,void * ctx)410*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkTypeface> DeserializeTypeface(const void* data, size_t length, void* ctx) {
411*c8dee2aaSAndroid Build Coastguard Worker auto array = (TArray<sk_sp<SkTypeface>>*)ctx;
412*c8dee2aaSAndroid Build Coastguard Worker if (length != sizeof(size_t)) {
413*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Did not serialize an index");
414*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
415*c8dee2aaSAndroid Build Coastguard Worker }
416*c8dee2aaSAndroid Build Coastguard Worker if (!data) {
417*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
418*c8dee2aaSAndroid Build Coastguard Worker }
419*c8dee2aaSAndroid Build Coastguard Worker size_t idx = 0;
420*c8dee2aaSAndroid Build Coastguard Worker std::memcpy(&idx, data, sizeof(size_t));
421*c8dee2aaSAndroid Build Coastguard Worker if (idx >= SkToSizeT(array->size())) {
422*c8dee2aaSAndroid Build Coastguard Worker SkDEBUGFAIL("Index too big");
423*c8dee2aaSAndroid Build Coastguard Worker return nullptr;
424*c8dee2aaSAndroid Build Coastguard Worker }
425*c8dee2aaSAndroid Build Coastguard Worker return (*array)[idx];
426*c8dee2aaSAndroid Build Coastguard Worker }
427*c8dee2aaSAndroid Build Coastguard Worker
428*c8dee2aaSAndroid Build Coastguard Worker /*
429*c8dee2aaSAndroid Build Coastguard Worker * Build a blob with more than one typeface.
430*c8dee2aaSAndroid Build Coastguard Worker * Draw it into an offscreen,
431*c8dee2aaSAndroid Build Coastguard Worker * then serialize and deserialize,
432*c8dee2aaSAndroid Build Coastguard Worker * Then draw the new instance and assert it draws the same as the original.
433*c8dee2aaSAndroid Build Coastguard Worker */
DEF_TEST(TextBlob_serialize,reporter)434*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_serialize, reporter) {
435*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob0 = [reporter]() {
436*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTypeface> tf = ToolUtils::CreateTestTypeface(nullptr, SkFontStyle::BoldItalic());
437*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, tf, "Test typeface was nullptr");
438*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, tf->countGlyphs() > 0, "Test typeface had no glyphs");
439*c8dee2aaSAndroid Build Coastguard Worker
440*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder builder;
441*c8dee2aaSAndroid Build Coastguard Worker add_run(&builder, "Hello", 10, 20, nullptr); // don't flatten a typeface
442*c8dee2aaSAndroid Build Coastguard Worker add_run(&builder, "World", 10, 40, tf); // do flatten this typeface
443*c8dee2aaSAndroid Build Coastguard Worker return builder.make();
444*c8dee2aaSAndroid Build Coastguard Worker }();
445*c8dee2aaSAndroid Build Coastguard Worker
446*c8dee2aaSAndroid Build Coastguard Worker TArray<sk_sp<SkTypeface>> array;
447*c8dee2aaSAndroid Build Coastguard Worker SkSerialProcs serializeProcs;
448*c8dee2aaSAndroid Build Coastguard Worker serializeProcs.fTypefaceProc = &SerializeTypeface;
449*c8dee2aaSAndroid Build Coastguard Worker serializeProcs.fTypefaceCtx = (void*) &array;
450*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkData> data = blob0->serialize(serializeProcs);
451*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, array.size() == 1,
452*c8dee2aaSAndroid Build Coastguard Worker "Did not serialize exactly one non-empty font, instead %d", array.size());
453*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, array[0]->countGlyphs() > 0, "Serialized typeface had no glyphs");
454*c8dee2aaSAndroid Build Coastguard Worker SkDeserialProcs deserializeProcs;
455*c8dee2aaSAndroid Build Coastguard Worker deserializeProcs.fTypefaceProc = &DeserializeTypeface;
456*c8dee2aaSAndroid Build Coastguard Worker deserializeProcs.fTypefaceCtx = (void*) &array;
457*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTextBlob> blob1 = SkTextBlob::Deserialize(data->data(), data->size(), deserializeProcs);
458*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blob1);
459*c8dee2aaSAndroid Build Coastguard Worker
460*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> img0 = render(blob0.get());
461*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkImage> img1 = render(blob1.get());
462*c8dee2aaSAndroid Build Coastguard Worker if (img0 && img1) {
463*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, ToolUtils::equal_pixels(img0.get(), img1.get()));
464*c8dee2aaSAndroid Build Coastguard Worker }
465*c8dee2aaSAndroid Build Coastguard Worker }
466*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(TextBlob_MakeAsDrawText,reporter)467*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_MakeAsDrawText, reporter) {
468*c8dee2aaSAndroid Build Coastguard Worker const char text[] = "Hello";
469*c8dee2aaSAndroid Build Coastguard Worker auto blob = SkTextBlob::MakeFromString(text, ToolUtils::DefaultFont(), SkTextEncoding::kUTF8);
470*c8dee2aaSAndroid Build Coastguard Worker
471*c8dee2aaSAndroid Build Coastguard Worker int runs = 0;
472*c8dee2aaSAndroid Build Coastguard Worker for(SkTextBlobRunIterator it(blob.get()); !it.done(); it.next()) {
473*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.glyphCount() == strlen(text));
474*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, it.positioning() == SkTextBlobRunIterator::kFull_Positioning);
475*c8dee2aaSAndroid Build Coastguard Worker runs += 1;
476*c8dee2aaSAndroid Build Coastguard Worker }
477*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, runs == 1);
478*c8dee2aaSAndroid Build Coastguard Worker
479*c8dee2aaSAndroid Build Coastguard Worker }
480*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(TextBlob_iter,reporter)481*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_iter, reporter) {
482*c8dee2aaSAndroid Build Coastguard Worker sk_sp<SkTypeface> tf = ToolUtils::CreateTestTypeface(nullptr, SkFontStyle::BoldItalic());
483*c8dee2aaSAndroid Build Coastguard Worker
484*c8dee2aaSAndroid Build Coastguard Worker SkTextBlobBuilder builder;
485*c8dee2aaSAndroid Build Coastguard Worker add_run(&builder, "Hello", 10, 20, tf);
486*c8dee2aaSAndroid Build Coastguard Worker add_run(&builder, "World!", 10, 40, tf);
487*c8dee2aaSAndroid Build Coastguard Worker auto blob = builder.make();
488*c8dee2aaSAndroid Build Coastguard Worker
489*c8dee2aaSAndroid Build Coastguard Worker SkTextBlob::Iter::Run expected[] = {
490*c8dee2aaSAndroid Build Coastguard Worker { tf.get(), 5, nullptr },
491*c8dee2aaSAndroid Build Coastguard Worker { tf.get(), 6, nullptr },
492*c8dee2aaSAndroid Build Coastguard Worker };
493*c8dee2aaSAndroid Build Coastguard Worker
494*c8dee2aaSAndroid Build Coastguard Worker SkTextBlob::Iter iter(*blob);
495*c8dee2aaSAndroid Build Coastguard Worker SkTextBlob::Iter::Run run;
496*c8dee2aaSAndroid Build Coastguard Worker for (auto exp : expected) {
497*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, iter.next(&run));
498*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, run.fTypeface == exp.fTypeface);
499*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, run.fGlyphCount == exp.fGlyphCount);
500*c8dee2aaSAndroid Build Coastguard Worker for (int i = 0; i < run.fGlyphCount; ++i) {
501*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, run.fGlyphIndices[i] != 0,
502*c8dee2aaSAndroid Build Coastguard Worker "Glyph Index %d is unexpectedly 0", i);
503*c8dee2aaSAndroid Build Coastguard Worker }
504*c8dee2aaSAndroid Build Coastguard Worker }
505*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, !iter.next(&run)); // we're done
506*c8dee2aaSAndroid Build Coastguard Worker
507*c8dee2aaSAndroid Build Coastguard Worker SkTextBlob::Iter iter2(*blob);
508*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, iter2.next(&run));
509*c8dee2aaSAndroid Build Coastguard Worker // Hello should have the same glyph repeated for the 'l'
510*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, run.fGlyphIndices[2] == run.fGlyphIndices[3]);
511*c8dee2aaSAndroid Build Coastguard Worker }
512*c8dee2aaSAndroid Build Coastguard Worker
DEF_TEST(TextBlob_getIntercepts,reporter)513*c8dee2aaSAndroid Build Coastguard Worker DEF_TEST(TextBlob_getIntercepts, reporter) {
514*c8dee2aaSAndroid Build Coastguard Worker SkFont font = ToolUtils::DefaultFont();
515*c8dee2aaSAndroid Build Coastguard Worker font.setSize(16);
516*c8dee2aaSAndroid Build Coastguard Worker
517*c8dee2aaSAndroid Build Coastguard Worker SkPoint lowPos[1] = { SkPoint::Make(0, 5) };
518*c8dee2aaSAndroid Build Coastguard Worker SkPoint highPos[1] = { SkPoint::Make(0, -8) };
519*c8dee2aaSAndroid Build Coastguard Worker SkPoint zeroPos[1] = { SkPoint::Make(0, 0) };
520*c8dee2aaSAndroid Build Coastguard Worker
521*c8dee2aaSAndroid Build Coastguard Worker // 'x' sitting on baseline
522*c8dee2aaSAndroid Build Coastguard Worker auto blobZeroX = SkTextBlob::MakeFromPosText("x", 1, zeroPos, font);
523*c8dee2aaSAndroid Build Coastguard Worker // 'x' lowered to intersect baseline
524*c8dee2aaSAndroid Build Coastguard Worker auto blobLowX = SkTextBlob::MakeFromPosText("x", 1, lowPos, font);
525*c8dee2aaSAndroid Build Coastguard Worker // 'y' sitting on baseline
526*c8dee2aaSAndroid Build Coastguard Worker auto blobZeroY = SkTextBlob::MakeFromPosText("y", 1, zeroPos, font);
527*c8dee2aaSAndroid Build Coastguard Worker // 'y' raised to not intersect baseline
528*c8dee2aaSAndroid Build Coastguard Worker auto blobHighY = SkTextBlob::MakeFromPosText("y", 1, highPos, font);
529*c8dee2aaSAndroid Build Coastguard Worker
530*c8dee2aaSAndroid Build Coastguard Worker // bounds right below baseline
531*c8dee2aaSAndroid Build Coastguard Worker SkScalar bounds[2] = { 1, 2 };
532*c8dee2aaSAndroid Build Coastguard Worker
533*c8dee2aaSAndroid Build Coastguard Worker // 'x' on baseline should not intersect
534*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blobZeroX->getIntercepts(bounds, nullptr) == 0);
535*c8dee2aaSAndroid Build Coastguard Worker // lowered 'x' should intersect
536*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blobLowX->getIntercepts(bounds, nullptr) == 2);
537*c8dee2aaSAndroid Build Coastguard Worker // 'y' on baseline should intersect
538*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blobZeroY->getIntercepts(bounds, nullptr) == 2);
539*c8dee2aaSAndroid Build Coastguard Worker // raised 'y' should not intersect
540*c8dee2aaSAndroid Build Coastguard Worker REPORTER_ASSERT(reporter, blobHighY->getIntercepts(bounds, nullptr) == 0);
541*c8dee2aaSAndroid Build Coastguard Worker }
542