• 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     int lbStyle = (int)LineBreakStyle::None;
36     int lbWordStyle = (int)LineBreakWordStyle::None;
37 
38     MeasuredTextBuilder builder;
39 
40     MinikinPaint paint1(font);
41     paint1.size = 10.0f;  // make 1em = 10px
42     builder.addStyleRun(0, 2, std::move(paint1), lbStyle, lbWordStyle, false /* is RTL */);
43     builder.addReplacementRun(2, 4, REPLACEMENT_WIDTH, 0 /* locale list id */);
44     MinikinPaint paint2(font);
45     paint2.size = 10.0f;  // make 1em = 10px
46     builder.addStyleRun(4, 6, std::move(paint2), lbStyle, lbWordStyle, false /* is RTL */);
47 
48     std::vector<uint16_t> text(CHAR_COUNT, 'a');
49 
50     std::unique_ptr<MeasuredText> measuredText =
51             builder.build(text, true /* compute hyphenation */, false /* compute full layout */,
52                           false /* ignore kerning */, nullptr /* no hint */);
53 
54     ASSERT_TRUE(measuredText);
55 
56     // ReplacementRun assigns all width to the first character and leave zeros others.
57     std::vector<float> expectedWidths = {CHAR_WIDTH, CHAR_WIDTH, REPLACEMENT_WIDTH,
58                                          0,          CHAR_WIDTH, CHAR_WIDTH};
59 
60     EXPECT_EQ(expectedWidths, measuredText->widths);
61 }
62 
TEST(MeasuredTextTest,getBoundsTest)63 TEST(MeasuredTextTest, getBoundsTest) {
64     auto text = utf8ToUtf16("Hello, World!");
65     auto font = buildFontCollection("Ascii.ttf");
66     int lbStyle = (int)LineBreakStyle::None;
67     int lbWordStyle = (int)LineBreakWordStyle::None;
68 
69     MeasuredTextBuilder builder;
70     MinikinPaint paint(font);
71     paint.size = 10.0f;
72     builder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
73     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
74                             false /* ignore kerning */, nullptr /* no hint */);
75 
76     EXPECT_EQ(MinikinRect(0.0f, 0.0f, 0.0f, 0.0f), mt->getBounds(text, Range(0, 0)));
77     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
78     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
79     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(1, 2)));
80     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), mt->getBounds(text, Range(0, text.size())));
81 }
82 
TEST(MeasuredTextTest,getBoundsTest_LTR)83 TEST(MeasuredTextTest, getBoundsTest_LTR) {
84     auto text = utf8ToUtf16("\u0028");  // U+0028 has 1em in LTR, 3em in RTL.
85     auto font = buildFontCollection("Bbox.ttf");
86     int lbStyle = (int)LineBreakStyle::None;
87     int lbWordStyle = (int)LineBreakWordStyle::None;
88 
89     MeasuredTextBuilder builder;
90     MinikinPaint paint(font);
91     paint.size = 10.0f;
92     builder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
93     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
94                             false /* ignore kerning */, nullptr /* no hint */);
95 
96     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
97 }
98 
TEST(MeasuredTextTest,getBoundsTest_RTL)99 TEST(MeasuredTextTest, getBoundsTest_RTL) {
100     auto text = utf8ToUtf16("\u0028");  // U+0028 has 1em in LTR, 3em in RTL.
101     auto font = buildFontCollection("Bbox.ttf");
102     int lbStyle = (int)LineBreakStyle::None;
103     int lbWordStyle = (int)LineBreakWordStyle::None;
104 
105     MeasuredTextBuilder builder;
106     MinikinPaint paint(font);
107     paint.size = 10.0f;
108     builder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, true /* is RTL */);
109     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
110                             false /* ignore kerning */, nullptr /* no hint */);
111 
112     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
113 }
114 
TEST(MeasuredTextTest,getBoundsTest_multiStyle)115 TEST(MeasuredTextTest, getBoundsTest_multiStyle) {
116     auto text = utf8ToUtf16("Hello, World!");
117     auto font = buildFontCollection("Ascii.ttf");
118     uint32_t helloLength = 7;  // length of "Hello, "
119     int lbStyle = (int)LineBreakStyle::None;
120     int lbWordStyle = (int)LineBreakWordStyle::None;
121 
122     MeasuredTextBuilder builder;
123     MinikinPaint paint(font);
124     paint.size = 10.0f;
125     builder.addStyleRun(0, helloLength, std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
126     MinikinPaint paint2(font);
127     paint2.size = 20.0f;
128     builder.addStyleRun(helloLength, text.size(), std::move(paint2), lbStyle, lbWordStyle,
129                         false /* is RTL */);
130     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
131                             false /* ignore kerning */, nullptr /* no hint */);
132 
133     EXPECT_EQ(MinikinRect(0.0f, 0.0f, 0.0f, 0.0f), mt->getBounds(text, Range(0, 0)));
134     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(0, 1)));
135     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), mt->getBounds(text, Range(0, 2)));
136     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), mt->getBounds(text, Range(1, 2)));
137     EXPECT_EQ(MinikinRect(0.0f, 0.0f, 0.0f, 0.0f), mt->getBounds(text, Range(7, 7)));
138     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), mt->getBounds(text, Range(7, 8)));
139     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 30.0f, 0.0f), mt->getBounds(text, Range(6, 8)));
140     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 190.0f, 0.0f), mt->getBounds(text, Range(0, text.size())));
141 }
142 
TEST(MeasuredTextTest,getExtentTest)143 TEST(MeasuredTextTest, getExtentTest) {
144     auto text = utf8ToUtf16("Hello, World!");
145     auto font = buildFontCollection("Ascii.ttf");
146     int lbStyle = (int)LineBreakStyle::None;
147     int lbWordStyle = (int)LineBreakWordStyle::None;
148 
149     MeasuredTextBuilder builder;
150     MinikinPaint paint(font);
151     paint.size = 10.0f;
152     builder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
153     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
154                             false /* ignore kernign */, nullptr /* no hint */);
155 
156     EXPECT_EQ(MinikinExtent(0.0f, 0.0f), mt->getExtent(text, Range(0, 0)));
157     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 1)));
158     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 2)));
159     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(1, 2)));
160     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, text.size())));
161 }
162 
TEST(MeasuredTextTest,getExtentTest_multiStyle)163 TEST(MeasuredTextTest, getExtentTest_multiStyle) {
164     auto text = utf8ToUtf16("Hello, World!");
165     auto font = buildFontCollection("Ascii.ttf");
166     uint32_t helloLength = 7;  // length of "Hello, "
167     int lbStyle = (int)LineBreakStyle::None;
168     int lbWordStyle = (int)LineBreakWordStyle::None;
169 
170     MeasuredTextBuilder builder;
171     MinikinPaint paint(font);
172     paint.size = 10.0f;
173     builder.addStyleRun(0, helloLength, std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
174     MinikinPaint paint2(font);
175     paint2.size = 20.0f;
176     builder.addStyleRun(helloLength, text.size(), std::move(paint2), 0 /* no line break */,
177                         0 /* no line break word style */, false /* is RTL */);
178     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
179                             false /* ignore kerning */, nullptr /* no hint */);
180 
181     EXPECT_EQ(MinikinExtent(0.0f, 0.0f), mt->getExtent(text, Range(0, 0)));
182     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 1)));
183     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(0, 2)));
184     EXPECT_EQ(MinikinExtent(-80.0f, 20.0f), mt->getExtent(text, Range(1, 2)));
185     EXPECT_EQ(MinikinExtent(0.0f, 0.0f), mt->getExtent(text, Range(7, 7)));
186     EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), mt->getExtent(text, Range(7, 8)));
187     EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), mt->getExtent(text, Range(6, 8)));
188     EXPECT_EQ(MinikinExtent(-160.0f, 40.0f), mt->getExtent(text, Range(0, text.size())));
189 }
190 
TEST(MeasuredTextTest,buildLayoutTest)191 TEST(MeasuredTextTest, buildLayoutTest) {
192     auto text = utf8ToUtf16("Hello, World!");
193     auto font = buildFontCollection("Ascii.ttf");
194     Range fullContext(0, text.size());
195     int lbStyle = (int)LineBreakStyle::None;
196     int lbWordStyle = (int)LineBreakWordStyle::None;
197 
198     MeasuredTextBuilder builder;
199     MinikinPaint paint(font);
200     paint.size = 10.0f;
201     builder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
202     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
203                             false /* ignore kerning */, nullptr /* no hint */);
204 
205     MinikinRect rect;
206     MinikinPaint samePaint(font);
207     samePaint.size = 10.0f;
208 
209     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, samePaint,
210                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
211     EXPECT_EQ(0u, layout.nGlyphs());
212 
213     layout = mt->buildLayout(text, Range(0, 1), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
214                              EndHyphenEdit::NO_EDIT);
215     ASSERT_EQ(1u, layout.nGlyphs());
216     EXPECT_TRUE(layout.getFont(0));
217     EXPECT_EQ(0.0f, layout.getX(0));
218     EXPECT_EQ(0.0f, layout.getY(0));
219     EXPECT_EQ(10.0f, layout.getAdvance());
220     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
221     EXPECT_EQ(1u, layout.getAdvances().size());
222     getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
223               EndHyphenEdit::NO_EDIT, &rect);
224     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
225 
226     layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
227                              EndHyphenEdit::NO_EDIT);
228     ASSERT_EQ(2u, layout.nGlyphs());
229     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
230     EXPECT_EQ(0.0f, layout.getX(0));
231     EXPECT_EQ(0.0f, layout.getY(0));
232     EXPECT_EQ(10.0f, layout.getX(1));
233     EXPECT_EQ(0.0f, layout.getY(1));
234     EXPECT_EQ(20.0f, layout.getAdvance());
235     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
236     EXPECT_EQ(10.0f, layout.getCharAdvance(1));
237     EXPECT_EQ(2u, layout.getAdvances().size());
238     getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
239               EndHyphenEdit::NO_EDIT, &rect);
240     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect);
241 
242     layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
243                              EndHyphenEdit::NO_EDIT);
244     ASSERT_EQ(1u, layout.nGlyphs());
245     EXPECT_TRUE(layout.getFont(0));
246     EXPECT_EQ(0.0f, layout.getX(0));
247     EXPECT_EQ(0.0f, layout.getY(0));
248     EXPECT_EQ(10.0f, layout.getAdvance());
249     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
250     EXPECT_EQ(1u, layout.getAdvances().size());
251     getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
252               EndHyphenEdit::NO_EDIT, &rect);
253     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
254 
255     layout = mt->buildLayout(text, Range(0, text.size()), fullContext, samePaint,
256                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
257     ASSERT_EQ(text.size(), layout.nGlyphs());
258     EXPECT_TRUE(layout.getFont(0));
259     for (uint32_t i = 0; i < text.size(); ++i) {
260         EXPECT_EQ(layout.getFont(0), layout.getFont(i)) << i;
261         EXPECT_EQ(10.0f * i, layout.getX(i)) << i;
262         EXPECT_EQ(0.0f, layout.getY(i)) << i;
263         EXPECT_EQ(10.0f, layout.getCharAdvance(i)) << i;
264     }
265     EXPECT_EQ(130.0f, layout.getAdvance());
266     EXPECT_EQ(text.size(), layout.getAdvances().size());
267     getBounds(text, Range(0, text.size()), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
268               EndHyphenEdit::NO_EDIT, &rect);
269     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 130.0f, 0.0f), rect);
270 }
271 
TEST(MeasuredTextTest,buildLayoutTest_multiStyle)272 TEST(MeasuredTextTest, buildLayoutTest_multiStyle) {
273     auto text = utf8ToUtf16("Hello, World!");
274     auto font = buildFontCollection("Ascii.ttf");
275     uint32_t helloLength = 7;  // length of "Hello, "
276     Range fullContext(0, text.size());
277     int lbStyle = (int)LineBreakStyle::None;
278     int lbWordStyle = (int)LineBreakWordStyle::None;
279 
280     MeasuredTextBuilder builder;
281     MinikinPaint paint(font);
282     paint.size = 10.0f;
283     builder.addStyleRun(0, helloLength, std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
284     MinikinPaint paint2(font);
285     paint2.size = 20.0f;
286     builder.addStyleRun(helloLength, text.size(), std::move(paint2), lbStyle, lbWordStyle,
287                         false /* is RTL */);
288     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
289                             false /* ignore kerning */, nullptr /* no hint */);
290 
291     MinikinRect rect;
292     MinikinPaint samePaint(font);
293     samePaint.size = 10.0f;
294 
295     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, samePaint,
296                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
297     EXPECT_EQ(0u, layout.nGlyphs());
298 
299     layout = mt->buildLayout(text, Range(0, 1), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
300                              EndHyphenEdit::NO_EDIT);
301     ASSERT_EQ(1u, layout.nGlyphs());
302     EXPECT_TRUE(layout.getFont(0));
303     EXPECT_EQ(0.0f, layout.getX(0));
304     EXPECT_EQ(0.0f, layout.getY(0));
305     EXPECT_EQ(10.0f, layout.getAdvance());
306     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
307     EXPECT_EQ(1u, layout.getAdvances().size());
308     getBounds(text, Range(0, 1), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
309               EndHyphenEdit::NO_EDIT, &rect);
310     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
311 
312     layout = mt->buildLayout(text, Range(0, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
313                              EndHyphenEdit::NO_EDIT);
314     ASSERT_EQ(2u, layout.nGlyphs());
315     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
316     EXPECT_EQ(0.0f, layout.getX(0));
317     EXPECT_EQ(0.0f, layout.getY(0));
318     EXPECT_EQ(10.0f, layout.getX(1));
319     EXPECT_EQ(0.0f, layout.getY(1));
320     EXPECT_EQ(20.0f, layout.getAdvance());
321     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
322     EXPECT_EQ(10.0f, layout.getCharAdvance(1));
323     EXPECT_EQ(2u, layout.getAdvances().size());
324     getBounds(text, Range(0, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
325               EndHyphenEdit::NO_EDIT, &rect);
326     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 20.0f, 0.0f), rect);
327 
328     layout = mt->buildLayout(text, Range(1, 2), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
329                              EndHyphenEdit::NO_EDIT);
330     ASSERT_EQ(1u, layout.nGlyphs());
331     EXPECT_TRUE(layout.getFont(0));
332     EXPECT_EQ(0.0f, layout.getX(0));
333     EXPECT_EQ(0.0f, layout.getY(0));
334     EXPECT_EQ(10.0f, layout.getAdvance());
335     EXPECT_EQ(10.0f, layout.getCharAdvance(0));
336     EXPECT_EQ(1u, layout.getAdvances().size());
337     getBounds(text, Range(1, 2), Bidi::LTR, samePaint, StartHyphenEdit::NO_EDIT,
338               EndHyphenEdit::NO_EDIT, &rect);
339     EXPECT_EQ(MinikinRect(0.0f, 10.0f, 10.0f, 0.0f), rect);
340 
341     layout = mt->buildLayout(text, Range(7, 7), fullContext, samePaint, StartHyphenEdit::NO_EDIT,
342                              EndHyphenEdit::NO_EDIT);
343     EXPECT_EQ(0u, layout.nGlyphs());
344 
345     MinikinPaint samePaint2(font);
346     samePaint2.size = 20.0f;
347     layout = mt->buildLayout(text, Range(7, 8), fullContext, samePaint2, StartHyphenEdit::NO_EDIT,
348                              EndHyphenEdit::NO_EDIT);
349     ASSERT_EQ(1u, layout.nGlyphs());
350     EXPECT_TRUE(layout.getFont(0));
351     EXPECT_EQ(0.0f, layout.getX(0));
352     EXPECT_EQ(0.0f, layout.getY(0));
353     EXPECT_EQ(20.0f, layout.getAdvance());
354     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
355     EXPECT_EQ(1u, layout.getAdvances().size());
356     getBounds(text, Range(7, 8), Bidi::LTR, samePaint2, StartHyphenEdit::NO_EDIT,
357               EndHyphenEdit::NO_EDIT, &rect);
358     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
359 }
360 
TEST(MeasuredTextTest,buildLayoutTest_differentPaint)361 TEST(MeasuredTextTest, buildLayoutTest_differentPaint) {
362     auto text = utf8ToUtf16("Hello, World!");
363     auto font = buildFontCollection("Ascii.ttf");
364     Range fullContext(0, text.size());
365     int lbStyle = (int)LineBreakStyle::None;
366     int lbWordStyle = (int)LineBreakWordStyle::None;
367 
368     MeasuredTextBuilder builder;
369     MinikinPaint paint(font);
370     paint.size = 10.0f;
371     builder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
372     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
373                             false /* ignore kerning */, nullptr /* no hint */);
374 
375     MinikinRect rect;
376     MinikinPaint differentPaint(font);
377     differentPaint.size = 20.0f;
378 
379     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, differentPaint,
380                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
381     EXPECT_EQ(0u, layout.nGlyphs());
382 
383     layout = mt->buildLayout(text, Range(0, 1), fullContext, differentPaint,
384                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
385     ASSERT_EQ(1u, layout.nGlyphs());
386     EXPECT_TRUE(layout.getFont(0));
387     EXPECT_EQ(0.0f, layout.getX(0));
388     EXPECT_EQ(0.0f, layout.getY(0));
389     EXPECT_EQ(20.0f, layout.getAdvance());
390     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
391     EXPECT_EQ(1u, layout.getAdvances().size());
392     getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
393               EndHyphenEdit::NO_EDIT, &rect);
394     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
395 
396     layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint,
397                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
398     ASSERT_EQ(2u, layout.nGlyphs());
399     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
400     EXPECT_EQ(0.0f, layout.getX(0));
401     EXPECT_EQ(0.0f, layout.getY(0));
402     EXPECT_EQ(20.0f, layout.getX(1));
403     EXPECT_EQ(0.0f, layout.getY(1));
404     EXPECT_EQ(40.0f, layout.getAdvance());
405     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
406     EXPECT_EQ(20.0f, layout.getCharAdvance(1));
407     EXPECT_EQ(2u, layout.getAdvances().size());
408     getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
409               EndHyphenEdit::NO_EDIT, &rect);
410     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 40.0f, 0.0f), rect);
411 
412     layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint,
413                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
414     ASSERT_EQ(1u, layout.nGlyphs());
415     EXPECT_TRUE(layout.getFont(0));
416     EXPECT_EQ(0.0f, layout.getX(0));
417     EXPECT_EQ(0.0f, layout.getY(0));
418     EXPECT_EQ(20.0f, layout.getAdvance());
419     EXPECT_EQ(20.0f, layout.getCharAdvance(0));
420     EXPECT_EQ(1u, layout.getAdvances().size());
421     getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
422               EndHyphenEdit::NO_EDIT, &rect);
423     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 20.0f, 0.0f), rect);
424 
425     layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint,
426                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
427     ASSERT_EQ(text.size(), layout.nGlyphs());
428     EXPECT_TRUE(layout.getFont(0));
429     for (uint32_t i = 0; i < text.size(); ++i) {
430         EXPECT_EQ(layout.getFont(0), layout.getFont(i)) << i;
431         EXPECT_EQ(20.0f * i, layout.getX(i)) << i;
432         EXPECT_EQ(0.0f, layout.getY(i)) << i;
433         EXPECT_EQ(20.0f, layout.getCharAdvance(i)) << i;
434     }
435     EXPECT_EQ(260.0f, layout.getAdvance());
436     EXPECT_EQ(text.size(), layout.getAdvances().size());
437     getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
438               EndHyphenEdit::NO_EDIT, &rect);
439     EXPECT_EQ(MinikinRect(0.0f, 20.0f, 260.0f, 0.0f), rect);
440 }
441 
TEST(MeasuredTextTest,buildLayoutTest_multiStyle_differentPaint)442 TEST(MeasuredTextTest, buildLayoutTest_multiStyle_differentPaint) {
443     auto text = utf8ToUtf16("Hello, World!");
444     auto font = buildFontCollection("Ascii.ttf");
445     uint32_t helloLength = 7;  // length of "Hello, "
446     Range fullContext(0, text.size());
447     int lbStyle = (int)LineBreakStyle::None;
448     int lbWordStyle = (int)LineBreakWordStyle::None;
449 
450     MeasuredTextBuilder builder;
451     MinikinPaint paint(font);
452     paint.size = 10.0f;
453     builder.addStyleRun(0, helloLength, std::move(paint), lbStyle, lbWordStyle, false /* is RTL */);
454     MinikinPaint paint2(font);
455     paint2.size = 20.0f;
456     builder.addStyleRun(helloLength, text.size(), std::move(paint2), lbStyle, lbWordStyle,
457                         false /* is RTL */);
458     auto mt = builder.build(text, true /* hyphenation */, true /* full layout */,
459                             false /* ignore kerning */, nullptr /* no hint */);
460 
461     MinikinRect rect;
462     MinikinPaint differentPaint(font);
463     differentPaint.size = 30.0f;
464 
465     Layout layout = mt->buildLayout(text, Range(0, 0), fullContext, differentPaint,
466                                     StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
467     EXPECT_EQ(0u, layout.nGlyphs());
468 
469     layout = mt->buildLayout(text, Range(0, 1), fullContext, differentPaint,
470                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
471     ASSERT_EQ(1u, layout.nGlyphs());
472     EXPECT_TRUE(layout.getFont(0));
473     EXPECT_EQ(0.0f, layout.getX(0));
474     EXPECT_EQ(0.0f, layout.getY(0));
475     EXPECT_EQ(30.0f, layout.getAdvance());
476     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
477     EXPECT_EQ(1u, layout.getAdvances().size());
478     getBounds(text, Range(0, 1), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
479               EndHyphenEdit::NO_EDIT, &rect);
480     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
481 
482     layout = mt->buildLayout(text, Range(0, 2), fullContext, differentPaint,
483                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
484     ASSERT_EQ(2u, layout.nGlyphs());
485     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
486     EXPECT_EQ(0.0f, layout.getX(0));
487     EXPECT_EQ(0.0f, layout.getY(0));
488     EXPECT_EQ(30.0f, layout.getX(1));
489     EXPECT_EQ(0.0f, layout.getY(1));
490     EXPECT_EQ(60.0f, layout.getAdvance());
491     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
492     EXPECT_EQ(30.0f, layout.getCharAdvance(1));
493     EXPECT_EQ(2u, layout.getAdvances().size());
494     getBounds(text, Range(0, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
495               EndHyphenEdit::NO_EDIT, &rect);
496     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect);
497 
498     layout = mt->buildLayout(text, Range(1, 2), fullContext, differentPaint,
499                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
500     ASSERT_EQ(1u, layout.nGlyphs());
501     EXPECT_TRUE(layout.getFont(0));
502     EXPECT_EQ(0.0f, layout.getX(0));
503     EXPECT_EQ(0.0f, layout.getY(0));
504     EXPECT_EQ(30.0f, layout.getAdvance());
505     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
506     EXPECT_EQ(1u, layout.getAdvances().size());
507     getBounds(text, Range(1, 2), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
508               EndHyphenEdit::NO_EDIT, &rect);
509     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
510 
511     layout = mt->buildLayout(text, Range(7, 7), fullContext, differentPaint,
512                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
513     EXPECT_EQ(0u, layout.nGlyphs());
514 
515     layout = mt->buildLayout(text, Range(7, 8), fullContext, differentPaint,
516                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
517     ASSERT_EQ(1u, layout.nGlyphs());
518     EXPECT_TRUE(layout.getFont(0));
519     EXPECT_EQ(0.0f, layout.getX(0));
520     EXPECT_EQ(0.0f, layout.getY(0));
521     EXPECT_EQ(30.0f, layout.getAdvance());
522     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
523     EXPECT_EQ(1u, layout.getAdvances().size());
524     getBounds(text, Range(7, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
525               EndHyphenEdit::NO_EDIT, &rect);
526     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 30.0f, 0.0f), rect);
527 
528     layout = mt->buildLayout(text, Range(6, 8), fullContext, differentPaint,
529                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
530     ASSERT_EQ(2u, layout.nGlyphs());
531     EXPECT_TRUE(layout.getFont(0) && layout.getFont(0) == layout.getFont(1));
532     EXPECT_EQ(0.0f, layout.getX(0));
533     EXPECT_EQ(0.0f, layout.getY(0));
534     EXPECT_EQ(30.0f, layout.getX(1));
535     EXPECT_EQ(0.0f, layout.getY(1));
536     EXPECT_EQ(60.0f, layout.getAdvance());
537     EXPECT_EQ(30.0f, layout.getCharAdvance(0));
538     EXPECT_EQ(30.0f, layout.getCharAdvance(1));
539     EXPECT_EQ(2u, layout.getAdvances().size());
540     getBounds(text, Range(6, 8), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
541               EndHyphenEdit::NO_EDIT, &rect);
542     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 60.0f, 0.0f), rect);
543 
544     layout = mt->buildLayout(text, Range(0, text.size()), fullContext, differentPaint,
545                              StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT);
546     ASSERT_EQ(text.size(), layout.nGlyphs());
547     EXPECT_TRUE(layout.getFont(0));
548     for (uint32_t i = 0; i < text.size(); ++i) {
549         EXPECT_EQ(layout.getFont(0), layout.getFont(i)) << i;
550         EXPECT_EQ(30.0f * i, layout.getX(i)) << i;
551         EXPECT_EQ(0.0f, layout.getY(i)) << i;
552         EXPECT_EQ(30.0f, layout.getCharAdvance(i)) << i;
553     }
554     EXPECT_EQ(390.0f, layout.getAdvance());
555     EXPECT_EQ(text.size(), layout.getAdvances().size());
556     getBounds(text, Range(0, text.size()), Bidi::LTR, differentPaint, StartHyphenEdit::NO_EDIT,
557               EndHyphenEdit::NO_EDIT, &rect);
558     EXPECT_EQ(MinikinRect(0.0f, 30.0f, 390.0f, 0.0f), rect);
559 }
560 
TEST(MeasuredTextTest,testLineBreakStyle_from_builder)561 TEST(MeasuredTextTest, testLineBreakStyle_from_builder) {
562     auto text = utf8ToUtf16("Hello, World!");
563     auto font = buildFontCollection("Ascii.ttf");
564     int lbStyle = (int)LineBreakStyle::Loose;           // loose
565     int lbWordStyle = (int)LineBreakWordStyle::Phrase;  // phrase
566 
567     MeasuredTextBuilder looseStyleBuilder;
568     MinikinPaint paint(font);
569     looseStyleBuilder.addStyleRun(0, text.size(), std::move(paint), lbStyle, lbWordStyle, false);
570     auto mt = looseStyleBuilder.build(text, true /* hyphenation */, true /* full layout */,
571                                       false /* ignore kerning */, nullptr /* no hint */);
572 
573     EXPECT_EQ((size_t)1, mt->runs.size());
574     EXPECT_EQ(LineBreakStyle::Loose, mt->runs[0]->lineBreakStyle());
575     EXPECT_EQ(LineBreakWordStyle::Phrase, mt->runs[0]->lineBreakWordStyle());
576 
577     lbStyle = (int)LineBreakStyle::Normal;  // normal
578     MeasuredTextBuilder normalStyleBuilder;
579     MinikinPaint normalStylePaint(font);
580     normalStyleBuilder.addStyleRun(0, text.size(), std::move(normalStylePaint), lbStyle,
581                                    lbWordStyle, false);
582     mt = normalStyleBuilder.build(text, true /* hyphenation */, true /* full layout */,
583                                   false /* ignore kerning */, nullptr /* no hint */);
584 
585     EXPECT_EQ((size_t)1, mt->runs.size());
586     EXPECT_EQ(LineBreakStyle::Normal, mt->runs[0]->lineBreakStyle());
587     EXPECT_EQ(LineBreakWordStyle::Phrase, mt->runs[0]->lineBreakWordStyle());
588 
589     lbStyle = (int)LineBreakStyle::Strict;        // strict
590     lbWordStyle = (int)LineBreakWordStyle::None;  // no word style
591     MeasuredTextBuilder strictStyleBuilder;
592     MinikinPaint strictStylePaint(font);
593     strictStyleBuilder.addStyleRun(0, text.size(), std::move(strictStylePaint), lbStyle,
594                                    lbWordStyle, false);
595     mt = strictStyleBuilder.build(text, true /* hyphenation */, true /* full layout */,
596                                   false /* ignore kerning */, nullptr /* no hint */);
597 
598     EXPECT_EQ((size_t)1, mt->runs.size());
599     EXPECT_EQ(LineBreakStyle::Strict, mt->runs[0]->lineBreakStyle());
600     EXPECT_EQ(LineBreakWordStyle::None, mt->runs[0]->lineBreakWordStyle());
601 }
602 
TEST(MeasuredTextTest,testLineBreakStyle_from_run)603 TEST(MeasuredTextTest, testLineBreakStyle_from_run) {
604     auto text = utf8ToUtf16("Hello, World!");
605     auto font = buildFontCollection("Ascii.ttf");
606     int lbStyle = (int)LineBreakStyle::Strict;
607     int lbWordStyle = (int)LineBreakWordStyle::Phrase;
608     Range range(0, text.size());
609     MinikinPaint paint(font);
610 
611     StyleRun styleRun(range, std::move(paint), lbStyle, lbWordStyle, false /* isRtl */);
612     EXPECT_EQ(LineBreakStyle::Strict, styleRun.lineBreakStyle());
613     EXPECT_EQ(LineBreakWordStyle::Phrase, styleRun.lineBreakWordStyle());
614 
615     ReplacementRun replacementRun(range, 10.0f /* width */, 0 /* locale list id */);
616     EXPECT_EQ(LineBreakStyle::None, replacementRun.lineBreakStyle());
617     EXPECT_EQ(LineBreakWordStyle::None, replacementRun.lineBreakWordStyle());
618 }
619 
620 }  // namespace minikin
621