• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "minikin/MeasuredText.h"
18 
19 #include <gtest/gtest.h>
20 
21 #include "minikin/LineBreaker.h"
22 #include "minikin/Measurement.h"
23 
24 #include "FontTestUtils.h"
25 #include "UnicodeUtils.h"
26 
27 namespace minikin {
28 
29 constexpr float CHAR_WIDTH = 10.0;  // Mock implementation always returns 10.0 for advance.
30 
TEST(MeasuredTextTest,RunTests)31 TEST(MeasuredTextTest, RunTests) {
32     constexpr uint32_t CHAR_COUNT = 6;
33     constexpr float REPLACEMENT_WIDTH = 20.0f;
34     auto font = buildFontCollection("Ascii.ttf");
35 
36     MeasuredTextBuilder builder;
37 
38     MinikinPaint paint1(font);
39     paint1.size = 10.0f;  // make 1em = 10px
40     builder.addStyleRun(0, 2, std::move(paint1), false /* is RTL */);
41     builder.addReplacementRun(2, 4, REPLACEMENT_WIDTH, 0 /* locale list id */);
42     MinikinPaint paint2(font);
43     paint2.size = 10.0f;  // make 1em = 10px
44     builder.addStyleRun(4, 6, std::move(paint2), false /* is RTL */);
45 
46     std::vector<uint16_t> text(CHAR_COUNT, 'a');
47 
48     std::unique_ptr<MeasuredText> measuredText =
49             builder.build(text, true /* compute hyphenation */, false /* compute full layout */,
50                           nullptr /* no hint */);
51 
52     ASSERT_TRUE(measuredText);
53 
54     // ReplacementRun assigns all width to the first character and leave zeros others.
55     std::vector<float> expectedWidths = {CHAR_WIDTH, CHAR_WIDTH, REPLACEMENT_WIDTH,
56                                          0,          CHAR_WIDTH, CHAR_WIDTH};
57 
58     EXPECT_EQ(expectedWidths, measuredText->widths);
59 }
60 
TEST(MeasuredTextTest,getBoundsTest)61 TEST(MeasuredTextTest, getBoundsTest) {
62     auto text = utf8ToUtf16("Hello, World!");
63     auto font = buildFontCollection("Ascii.ttf");
64 
65     MeasuredTextBuilder builder;
66     MinikinPaint paint(font);
67     paint.size = 10.0f;
68     builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */);
69     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
70                             nullptr /* no hint */);
71 
72     EXPECT_EQ(MinikinRect(0.0f, 0.0f, 0.0f, 0.0f), mt->getBounds(text, Range(0, 0)));
73     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
74     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
75     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(1, 2)));
76     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), mt->getBounds(text, Range(0, text.size())));
77 }
78 
TEST(MeasuredTextTest,getBoundsTest_LTR)79 TEST(MeasuredTextTest, getBoundsTest_LTR) {
80     auto text = utf8ToUtf16("\u0028");  // U+0028 has 1em in LTR, 3em in RTL.
81     auto font = buildFontCollection("Bbox.ttf");
82 
83     MeasuredTextBuilder builder;
84     MinikinPaint paint(font);
85     paint.size = 10.0f;
86     builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */);
87     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
88                             nullptr /* no hint */);
89 
90     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
91 }
92 
TEST(MeasuredTextTest,getBoundsTest_RTL)93 TEST(MeasuredTextTest, getBoundsTest_RTL) {
94     auto text = utf8ToUtf16("\u0028");  // U+0028 has 1em in LTR, 3em in RTL.
95     auto font = buildFontCollection("Bbox.ttf");
96 
97     MeasuredTextBuilder builder;
98     MinikinPaint paint(font);
99     paint.size = 10.0f;
100     builder.addStyleRun(0, text.size(), std::move(paint), true /* is RTL */);
101     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
102                             nullptr /* no hint */);
103 
104     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
105 }
106 
TEST(MeasuredTextTest,getBoundsTest_multiStyle)107 TEST(MeasuredTextTest, getBoundsTest_multiStyle) {
108     auto text = utf8ToUtf16("Hello, World!");
109     auto font = buildFontCollection("Ascii.ttf");
110     uint32_t helloLength = 7;  // length of "Hello, "
111 
112     MeasuredTextBuilder builder;
113     MinikinPaint paint(font);
114     paint.size = 10.0f;
115     builder.addStyleRun(0, helloLength, std::move(paint), false /* is RTL */);
116     MinikinPaint paint2(font);
117     paint2.size = 20.0f;
118     builder.addStyleRun(helloLength, text.size(), std::move(paint2), false /* is RTL */);
119     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
120                             nullptr /* no hint */);
121 
122     EXPECT_EQ(MinikinRect(0.0f, 0.0f, 0.0f, 0.0f), mt->getBounds(text, Range(0, 0)));
123     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
124     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
125     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(1, 2)));
126     EXPECT_EQ(MinikinRect(0.0f, 0.0f, 0.0f, 0.0f), mt->getBounds(text, Range(7, 7)));
127     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), mt->getBounds(text, Range(7, 8)));
128     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), mt->getBounds(text, Range(6, 8)));
129     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 190.0f, 0.0f), mt->getBounds(text, Range(0, text.size())));
130 }
131 
TEST(MeasuredTextTest,getExtentTest)132 TEST(MeasuredTextTest, getExtentTest) {
133     auto text = utf8ToUtf16("Hello, World!");
134     auto font = buildFontCollection("Ascii.ttf");
135 
136     MeasuredTextBuilder builder;
137     MinikinPaint paint(font);
138     paint.size = 10.0f;
139     builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */);
140     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
141                             nullptr /* no hint */);
142 
143     EXPECT_EQ(MinikinExtent(0.0f, 0.0f), mt->getExtent(text, Range(0, 0)));
144     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 1)));
145     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 2)));
146     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(1, 2)));
147     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, text.size())));
148 }
149 
TEST(MeasuredTextTest,getExtentTest_multiStyle)150 TEST(MeasuredTextTest, getExtentTest_multiStyle) {
151     auto text = utf8ToUtf16("Hello, World!");
152     auto font = buildFontCollection("Ascii.ttf");
153     uint32_t helloLength = 7;  // length of "Hello, "
154 
155     MeasuredTextBuilder builder;
156     MinikinPaint paint(font);
157     paint.size = 10.0f;
158     builder.addStyleRun(0, helloLength, std::move(paint), false /* is RTL */);
159     MinikinPaint paint2(font);
160     paint2.size = 20.0f;
161     builder.addStyleRun(helloLength, text.size(), std::move(paint2), false /* is RTL */);
162     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
163                             nullptr /* no hint */);
164 
165     EXPECT_EQ(MinikinExtent(0.0f, 0.0f), mt->getExtent(text, Range(0, 0)));
166     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 1)));
167     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 2)));
168     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(1, 2)));
169     EXPECT_EQ(MinikinExtent(0.0f, 0.0f), mt->getExtent(text, Range(7, 7)));
170     EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), mt->getExtent(text, Range(7, 8)));
171     EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), mt->getExtent(text, Range(6, 8)));
172     EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), mt->getExtent(text, Range(0, text.size())));
173 }
174 
TEST(MeasuredTextTest,buildLayoutTest)175 TEST(MeasuredTextTest, buildLayoutTest) {
176     auto text = utf8ToUtf16("Hello, World!");
177     auto font = buildFontCollection("Ascii.ttf");
178     Range fullContext(0, text.size());
179 
180     MeasuredTextBuilder builder;
181     MinikinPaint paint(font);
182     paint.size = 10.0f;
183     builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */);
184     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
185                             nullptr /* no hint */);
186 
187     MinikinRect rect;
188     MinikinPaint samePaint(font);
189     samePaint.size = 10.0f;
190 
191     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, samePaint,
192                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
193     EXPECT_EQ(0u, layout.nGlyphs());
194 
195     layout = mt->buildLayout(text, Range(0, 1), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
196                              EndHyphenEdit::NO_EDIT);
197     ASSERT_EQ(1u, layout.nGlyphs());
198     EXPECT_TRUE(layout.getFont(0));
199     EXPECT_EQ(0.0f, layout.getX(0));
200     EXPECT_EQ(0.0f, layout.getY(0));
201     EXPECT_EQ(10.0f, layout.getAdvance());
202     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
203     EXPECT_EQ(1u, layout.getAdvances().size());
204     getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
205               EndHyphenEdit::NO_EDIT, &rect);
206     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
207 
208     layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
209                              EndHyphenEdit::NO_EDIT);
210     ASSERT_EQ(2u, layout.nGlyphs());
211     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
212     EXPECT_EQ(0.0f, layout.getX(0));
213     EXPECT_EQ(0.0f, layout.getY(0));
214     EXPECT_EQ(10.0f, layout.getX(1));
215     EXPECT_EQ(0.0f, layout.getY(1));
216     EXPECT_EQ(20.0f, layout.getAdvance());
217     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
218     EXPECT_EQ(10.0f, layout.getCharAdvance(1));
219     EXPECT_EQ(2u, layout.getAdvances().size());
220     getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
221               EndHyphenEdit::NO_EDIT, &rect);
222     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect);
223 
224     layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
225                              EndHyphenEdit::NO_EDIT);
226     ASSERT_EQ(1u, layout.nGlyphs());
227     EXPECT_TRUE(layout.getFont(0));
228     EXPECT_EQ(0.0f, layout.getX(0));
229     EXPECT_EQ(0.0f, layout.getY(0));
230     EXPECT_EQ(10.0f, layout.getAdvance());
231     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
232     EXPECT_EQ(1u, layout.getAdvances().size());
233     getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
234               EndHyphenEdit::NO_EDIT, &rect);
235     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
236 
237     layout = mt->buildLayout(text, Range(0, text.size()), fullContext, samePaint,
238                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
239     ASSERT_EQ(text.size(), layout.nGlyphs());
240     EXPECT_TRUE(layout.getFont(0));
241     for (uint32_t i = 0; i < text.size(); ++i) {
242         EXPECT_EQ(layout.getFont(0), layout.getFont(i)) << i;
243         EXPECT_EQ(10.0f * i, layout.getX(i)) << i;
244         EXPECT_EQ(0.0f, layout.getY(i)) << i;
245         EXPECT_EQ(10.0f, layout.getCharAdvance(i)) << i;
246     }
247     EXPECT_EQ(130.0f, layout.getAdvance());
248     EXPECT_EQ(text.size(), layout.getAdvances().size());
249     getBounds(text, Range(0, text.size()), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
250               EndHyphenEdit::NO_EDIT, &rect);
251     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), rect);
252 }
253 
TEST(MeasuredTextTest,buildLayoutTest_multiStyle)254 TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
255     auto text = utf8ToUtf16("Hello, World!");
256     auto font = buildFontCollection("Ascii.ttf");
257     uint32_t helloLength = 7;  // length of "Hello, "
258     Range fullContext(0, text.size());
259 
260     MeasuredTextBuilder builder;
261     MinikinPaint paint(font);
262     paint.size = 10.0f;
263     builder.addStyleRun(0, helloLength, std::move(paint), false /* is RTL */);
264     MinikinPaint paint2(font);
265     paint2.size = 20.0f;
266     builder.addStyleRun(helloLength, text.size(), std::move(paint2), false /* is RTL */);
267     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
268                             nullptr /* no hint */);
269 
270     MinikinRect rect;
271     MinikinPaint samePaint(font);
272     samePaint.size = 10.0f;
273 
274     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, samePaint,
275                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
276     EXPECT_EQ(0u, layout.nGlyphs());
277 
278     layout = mt->buildLayout(text, Range(0, 1), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
279                              EndHyphenEdit::NO_EDIT);
280     ASSERT_EQ(1u, layout.nGlyphs());
281     EXPECT_TRUE(layout.getFont(0));
282     EXPECT_EQ(0.0f, layout.getX(0));
283     EXPECT_EQ(0.0f, layout.getY(0));
284     EXPECT_EQ(10.0f, layout.getAdvance());
285     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
286     EXPECT_EQ(1u, layout.getAdvances().size());
287     getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
288               EndHyphenEdit::NO_EDIT, &rect);
289     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
290 
291     layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
292                              EndHyphenEdit::NO_EDIT);
293     ASSERT_EQ(2u, layout.nGlyphs());
294     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
295     EXPECT_EQ(0.0f, layout.getX(0));
296     EXPECT_EQ(0.0f, layout.getY(0));
297     EXPECT_EQ(10.0f, layout.getX(1));
298     EXPECT_EQ(0.0f, layout.getY(1));
299     EXPECT_EQ(20.0f, layout.getAdvance());
300     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
301     EXPECT_EQ(10.0f, layout.getCharAdvance(1));
302     EXPECT_EQ(2u, layout.getAdvances().size());
303     getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
304               EndHyphenEdit::NO_EDIT, &rect);
305     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect);
306 
307     layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
308                              EndHyphenEdit::NO_EDIT);
309     ASSERT_EQ(1u, layout.nGlyphs());
310     EXPECT_TRUE(layout.getFont(0));
311     EXPECT_EQ(0.0f, layout.getX(0));
312     EXPECT_EQ(0.0f, layout.getY(0));
313     EXPECT_EQ(10.0f, layout.getAdvance());
314     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
315     EXPECT_EQ(1u, layout.getAdvances().size());
316     getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
317               EndHyphenEdit::NO_EDIT, &rect);
318     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
319 
320     layout = mt->buildLayout(text, Range(7, 7), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
321                              EndHyphenEdit::NO_EDIT);
322     EXPECT_EQ(0u, layout.nGlyphs());
323 
324     MinikinPaint samePaint2(font);
325     samePaint2.size = 20.0f;
326     layout = mt->buildLayout(text, Range(7, 8), fullContext, samePaint2, StartHyphenEdit::NO_EDIT,
327                              EndHyphenEdit::NO_EDIT);
328     ASSERT_EQ(1u, layout.nGlyphs());
329     EXPECT_TRUE(layout.getFont(0));
330     EXPECT_EQ(0.0f, layout.getX(0));
331     EXPECT_EQ(0.0f, layout.getY(0));
332     EXPECT_EQ(20.0f, layout.getAdvance());
333     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
334     EXPECT_EQ(1u, layout.getAdvances().size());
335     getBounds(text, Range(7, 8), Bidi::LTR, samePaint2, StartHyphenEdit::NO_EDIT,
336               EndHyphenEdit::NO_EDIT, &rect);
337     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
338 }
339 
TEST(MeasuredTextTest,buildLayoutTest_differentPaint)340 TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
341     auto text = utf8ToUtf16("Hello, World!");
342     auto font = buildFontCollection("Ascii.ttf");
343     Range fullContext(0, text.size());
344 
345     MeasuredTextBuilder builder;
346     MinikinPaint paint(font);
347     paint.size = 10.0f;
348     builder.addStyleRun(0, text.size(), std::move(paint), false /* is RTL */);
349     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
350                             nullptr /* no hint */);
351 
352     MinikinRect rect;
353     MinikinPaint differentPaint(font);
354     differentPaint.size = 20.0f;
355 
356     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, differentPaint,
357                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
358     EXPECT_EQ(0u, layout.nGlyphs());
359 
360     layout = mt->buildLayout(text, Range(0, 1), fullContext, differentPaint,
361                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
362     ASSERT_EQ(1u, layout.nGlyphs());
363     EXPECT_TRUE(layout.getFont(0));
364     EXPECT_EQ(0.0f, layout.getX(0));
365     EXPECT_EQ(0.0f, layout.getY(0));
366     EXPECT_EQ(20.0f, layout.getAdvance());
367     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
368     EXPECT_EQ(1u, layout.getAdvances().size());
369     getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
370               EndHyphenEdit::NO_EDIT, &rect);
371     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
372 
373     layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint,
374                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
375     ASSERT_EQ(2u, layout.nGlyphs());
376     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
377     EXPECT_EQ(0.0f, layout.getX(0));
378     EXPECT_EQ(0.0f, layout.getY(0));
379     EXPECT_EQ(20.0f, layout.getX(1));
380     EXPECT_EQ(0.0f, layout.getY(1));
381     EXPECT_EQ(40.0f, layout.getAdvance());
382     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
383     EXPECT_EQ(20.0f, layout.getCharAdvance(1));
384     EXPECT_EQ(2u, layout.getAdvances().size());
385     getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
386               EndHyphenEdit::NO_EDIT, &rect);
387     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 40.0f, 0.0f), rect);
388 
389     layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint,
390                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
391     ASSERT_EQ(1u, layout.nGlyphs());
392     EXPECT_TRUE(layout.getFont(0));
393     EXPECT_EQ(0.0f, layout.getX(0));
394     EXPECT_EQ(0.0f, layout.getY(0));
395     EXPECT_EQ(20.0f, layout.getAdvance());
396     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
397     EXPECT_EQ(1u, layout.getAdvances().size());
398     getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
399               EndHyphenEdit::NO_EDIT, &rect);
400     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
401 
402     layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint,
403                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
404     ASSERT_EQ(text.size(), layout.nGlyphs());
405     EXPECT_TRUE(layout.getFont(0));
406     for (uint32_t i = 0; i < text.size(); ++i) {
407         EXPECT_EQ(layout.getFont(0), layout.getFont(i)) << i;
408         EXPECT_EQ(20.0f * i, layout.getX(i)) << i;
409         EXPECT_EQ(0.0f, layout.getY(i)) << i;
410         EXPECT_EQ(20.0f, layout.getCharAdvance(i)) << i;
411     }
412     EXPECT_EQ(260.0f, layout.getAdvance());
413     EXPECT_EQ(text.size(), layout.getAdvances().size());
414     getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
415               EndHyphenEdit::NO_EDIT, &rect);
416     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 260.0f, 0.0f), rect);
417 }
418 
TEST(MeasuredTextTest,buildLayoutTest_multiStyle_differentPaint)419 TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
420     auto text = utf8ToUtf16("Hello, World!");
421     auto font = buildFontCollection("Ascii.ttf");
422     uint32_t helloLength = 7;  // length of "Hello, "
423     Range fullContext(0, text.size());
424 
425     MeasuredTextBuilder builder;
426     MinikinPaint paint(font);
427     paint.size = 10.0f;
428     builder.addStyleRun(0, helloLength, std::move(paint), false /* is RTL */);
429     MinikinPaint paint2(font);
430     paint2.size = 20.0f;
431     builder.addStyleRun(helloLength, text.size(), std::move(paint2), false /* is RTL */);
432     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
433                             nullptr /* no hint */);
434 
435     MinikinRect rect;
436     MinikinPaint differentPaint(font);
437     differentPaint.size = 30.0f;
438 
439     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, differentPaint,
440                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
441     EXPECT_EQ(0u, layout.nGlyphs());
442 
443     layout = mt->buildLayout(text, Range(0, 1), fullContext, differentPaint,
444                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
445     ASSERT_EQ(1u, layout.nGlyphs());
446     EXPECT_TRUE(layout.getFont(0));
447     EXPECT_EQ(0.0f, layout.getX(0));
448     EXPECT_EQ(0.0f, layout.getY(0));
449     EXPECT_EQ(30.0f, layout.getAdvance());
450     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
451     EXPECT_EQ(1u, layout.getAdvances().size());
452     getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
453               EndHyphenEdit::NO_EDIT, &rect);
454     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
455 
456     layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint,
457                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
458     ASSERT_EQ(2u, layout.nGlyphs());
459     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
460     EXPECT_EQ(0.0f, layout.getX(0));
461     EXPECT_EQ(0.0f, layout.getY(0));
462     EXPECT_EQ(30.0f, layout.getX(1));
463     EXPECT_EQ(0.0f, layout.getY(1));
464     EXPECT_EQ(60.0f, layout.getAdvance());
465     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
466     EXPECT_EQ(30.0f, layout.getCharAdvance(1));
467     EXPECT_EQ(2u, layout.getAdvances().size());
468     getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
469               EndHyphenEdit::NO_EDIT, &rect);
470     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect);
471 
472     layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint,
473                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
474     ASSERT_EQ(1u, layout.nGlyphs());
475     EXPECT_TRUE(layout.getFont(0));
476     EXPECT_EQ(0.0f, layout.getX(0));
477     EXPECT_EQ(0.0f, layout.getY(0));
478     EXPECT_EQ(30.0f, layout.getAdvance());
479     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
480     EXPECT_EQ(1u, layout.getAdvances().size());
481     getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
482               EndHyphenEdit::NO_EDIT, &rect);
483     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
484 
485     layout = mt->buildLayout(text, Range(7, 7), fullContext, differentPaint,
486                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
487     EXPECT_EQ(0u, layout.nGlyphs());
488 
489     layout = mt->buildLayout(text, Range(7, 8), fullContext, differentPaint,
490                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
491     ASSERT_EQ(1u, layout.nGlyphs());
492     EXPECT_TRUE(layout.getFont(0));
493     EXPECT_EQ(0.0f, layout.getX(0));
494     EXPECT_EQ(0.0f, layout.getY(0));
495     EXPECT_EQ(30.0f, layout.getAdvance());
496     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
497     EXPECT_EQ(1u, layout.getAdvances().size());
498     getBounds(text, Range(7, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
499               EndHyphenEdit::NO_EDIT, &rect);
500     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
501 
502     layout = mt->buildLayout(text, Range(6, 8), fullContext, differentPaint,
503                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
504     ASSERT_EQ(2u, layout.nGlyphs());
505     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
506     EXPECT_EQ(0.0f, layout.getX(0));
507     EXPECT_EQ(0.0f, layout.getY(0));
508     EXPECT_EQ(30.0f, layout.getX(1));
509     EXPECT_EQ(0.0f, layout.getY(1));
510     EXPECT_EQ(60.0f, layout.getAdvance());
511     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
512     EXPECT_EQ(30.0f, layout.getCharAdvance(1));
513     EXPECT_EQ(2u, layout.getAdvances().size());
514     getBounds(text, Range(6, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
515               EndHyphenEdit::NO_EDIT, &rect);
516     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect);
517 
518     layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint,
519                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
520     ASSERT_EQ(text.size(), layout.nGlyphs());
521     EXPECT_TRUE(layout.getFont(0));
522     for (uint32_t i = 0; i < text.size(); ++i) {
523         EXPECT_EQ(layout.getFont(0), layout.getFont(i)) << i;
524         EXPECT_EQ(30.0f * i, layout.getX(i)) << i;
525         EXPECT_EQ(0.0f, layout.getY(i)) << i;
526         EXPECT_EQ(30.0f, layout.getCharAdvance(i)) << i;
527     }
528     EXPECT_EQ(390.0f, layout.getAdvance());
529     EXPECT_EQ(text.size(), layout.getAdvances().size());
530     getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
531               EndHyphenEdit::NO_EDIT, &rect);
532     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 390.0f, 0.0f), rect);
533 }
534 
535 }  // namespace minikin
536