• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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 <memory>
18 
19 #include <gtest/gtest.h>
20 
21 #include "minikin/Hyphenator.h"
22 
23 #include "FileUtils.h"
24 #include "FontTestUtils.h"
25 #include "HyphenatorMap.h"
26 #include "LineBreakerTestHelper.h"
27 #include "LocaleListCache.h"
28 #include "MinikinInternal.h"
29 #include "OptimalLineBreaker.h"
30 #include "UnicodeUtils.h"
31 #include "WordBreaker.h"
32 
33 namespace minikin {
34 namespace {
35 
36 using line_breaker_test_helper::ConstantRun;
37 using line_breaker_test_helper::LineBreakExpectation;
38 using line_breaker_test_helper::RectangleLineWidth;
39 using line_breaker_test_helper::sameLineBreak;
40 using line_breaker_test_helper::toString;
41 
42 class OptimalLineBreakerTest : public testing::Test {
43 public:
OptimalLineBreakerTest()44     OptimalLineBreakerTest() {}
45 
~OptimalLineBreakerTest()46     virtual ~OptimalLineBreakerTest() {}
47 
SetUp()48     virtual void SetUp() override {
49         mHyphenationPattern = readWholeFile("/system/usr/hyphen-data/hyph-en-us.hyb");
50         Hyphenator* hyphenator = Hyphenator::loadBinary(
51                 mHyphenationPattern.data(), 2 /* min prefix */, 2 /* min suffix */, "en-US");
52         HyphenatorMap::add("en-US", hyphenator);
53         HyphenatorMap::add("pl", Hyphenator::loadBinary(nullptr, 0, 0, "pl"));
54     }
55 
TearDown()56     virtual void TearDown() override { HyphenatorMap::clear(); }
57 
58 protected:
doLineBreak(const U16StringPiece & textBuffer,BreakStrategy strategy,HyphenationFrequency frequency,float charWidth,float lineWidth)59     LineBreakResult doLineBreak(const U16StringPiece& textBuffer, BreakStrategy strategy,
60                                 HyphenationFrequency frequency, float charWidth, float lineWidth) {
61         return doLineBreak(textBuffer, strategy, frequency, charWidth, "en-US", lineWidth);
62     }
63 
doLineBreak(const U16StringPiece & textBuffer,BreakStrategy strategy,HyphenationFrequency frequency,float charWidth,const std::string & lang,float lineWidth)64     LineBreakResult doLineBreak(const U16StringPiece& textBuffer, BreakStrategy strategy,
65                                 HyphenationFrequency frequency, float charWidth,
66                                 const std::string& lang, float lineWidth) {
67         MeasuredTextBuilder builder;
68         builder.addCustomRun<ConstantRun>(Range(0, textBuffer.size()), lang, charWidth);
69         std::unique_ptr<MeasuredText> measuredText = builder.build(
70                 textBuffer, true /* compute hyphenation */, false /* compute full layout */);
71         return doLineBreak(textBuffer, *measuredText, strategy, frequency, lineWidth);
72     }
73 
doLineBreak(const U16StringPiece & textBuffer,const MeasuredText & measuredText,BreakStrategy strategy,HyphenationFrequency frequency,float lineWidth)74     LineBreakResult doLineBreak(const U16StringPiece& textBuffer, const MeasuredText& measuredText,
75                                 BreakStrategy strategy, HyphenationFrequency frequency,
76                                 float lineWidth) {
77         RectangleLineWidth rectangleLineWidth(lineWidth);
78         return breakLineOptimal(textBuffer, measuredText, rectangleLineWidth, strategy, frequency,
79                                 false /* justified */);
80     }
81 
82 private:
83     std::vector<uint8_t> mHyphenationPattern;
84 };
85 
TEST_F(OptimalLineBreakerTest,testBreakWithoutHyphenation)86 TEST_F(OptimalLineBreakerTest, testBreakWithoutHyphenation) {
87     constexpr float CHAR_WIDTH = 10.0;
88     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
89     constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
90     constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
91     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
92     const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
93 
94     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
95     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
96     constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
97     // Note that disable clang-format everywhere since aligned expectation is more readable.
98     {
99         constexpr float LINE_WIDTH = 1000 * CHAR_WIDTH;
100         std::vector<LineBreakExpectation> expect = {
101                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
102         };
103 
104         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
105         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
106                                                    << " vs " << std::endl
107                                                    << toString(textBuf, actual);
108         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
109         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
110                                                    << " vs " << std::endl
111                                                    << toString(textBuf, actual);
112         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
113         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
114                                                    << " vs " << std::endl
115                                                    << toString(textBuf, actual);
116         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
117         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
118                                                    << " vs " << std::endl
119                                                    << toString(textBuf, actual);
120     }
121     {
122         constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
123         std::vector<LineBreakExpectation> expect = {
124                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
125         };
126         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
127         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
128                                                    << " vs " << std::endl
129                                                    << toString(textBuf, actual);
130         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
131         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
132                                                    << " vs " << std::endl
133                                                    << toString(textBuf, actual);
134         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
135         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
136                                                    << " vs " << std::endl
137                                                    << toString(textBuf, actual);
138         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
139         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
140                                                    << " vs " << std::endl
141                                                    << toString(textBuf, actual);
142     }
143     {
144         constexpr float LINE_WIDTH = 23 * CHAR_WIDTH;
145         // clang-format off
146         std::vector<LineBreakExpectation> expect = {
147                 { "This is an example " , 18 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
148                 { "text."               ,  5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
149         };
150         // clang-format on
151 
152         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
153         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
154                                                    << " vs " << std::endl
155                                                    << toString(textBuf, actual);
156         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
157         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
158                                                    << " vs " << std::endl
159                                                    << toString(textBuf, actual);
160 
161         // clang-format off
162         expect = {
163                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
164                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
165         };
166         // clang-format on
167         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
168         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
169                                                    << " vs " << std::endl
170                                                    << toString(textBuf, actual);
171         // clang-format off
172         expect = {
173                 { "This is an ex-" , 14 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
174                 { "ample text."    , 11 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
175         };
176         // clang-format on
177         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
178         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
179                                                    << " vs " << std::endl
180                                                    << toString(textBuf, actual);
181     }
182     {
183         constexpr float LINE_WIDTH = 17 * CHAR_WIDTH;
184         // clang-format off
185         std::vector<LineBreakExpectation> expect = {
186                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
187                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
188         };
189         // clang-format on
190 
191         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
192         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
193                                                    << " vs " << std::endl
194                                                    << toString(textBuf, actual);
195         // clang-format off
196         expect = {
197                 { "This is an exam-" , 16 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
198                 { "ple text."        ,  9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
199         };
200         // clang-format on
201         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
202         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
203                                                    << " vs " << std::endl
204                                                    << toString(textBuf, actual);
205         // clang-format off
206         expect = {
207                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
208                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
209         };
210         // clang-format on
211         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
212         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
213                                                    << " vs " << std::endl
214                                                    << toString(textBuf, actual);
215         // clang-format off
216         expect = {
217                 { "This is an ex-", 14 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
218                 { "ample text."   , 11 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
219         };
220         // clang-format on
221         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
222         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
223                                                    << " vs " << std::endl
224                                                    << toString(textBuf, actual);
225     }
226     {
227         constexpr float LINE_WIDTH = 16 * CHAR_WIDTH;
228         // clang-format off
229         std::vector<LineBreakExpectation> expect = {
230                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
231                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
232         };
233         // clang-format on
234 
235         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
236         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
237                                                    << " vs " << std::endl
238                                                    << toString(textBuf, actual);
239         // clang-format off
240         expect = {
241                 { "This is an exam-" , 16 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
242                 { "ple text."        ,  9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
243         };
244         // clang-format on
245         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
246         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
247                                                    << " vs " << std::endl
248                                                    << toString(textBuf, actual);
249         // clang-format off
250         expect = {
251                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
252                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
253         };
254         // clang-format on
255         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
256         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
257                                                    << " vs " << std::endl
258                                                    << toString(textBuf, actual);
259         // clang-format off
260         expect = {
261                 { "This is an ex-", 14 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
262                 { "ample text."   , 11 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
263         };
264         // clang-format on
265         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
266         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
267                                                    << " vs " << std::endl
268                                                    << toString(textBuf, actual);
269     }
270     {
271         constexpr float LINE_WIDTH = 15 * CHAR_WIDTH;
272         // clang-format off
273         std::vector<LineBreakExpectation> expect = {
274                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
275                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
276         };
277         // clang-format on
278 
279         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
280         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
281                                                    << " vs " << std::endl
282                                                    << toString(textBuf, actual);
283         // clang-format off
284         expect = {
285                 { "This is an ex-", 14 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
286                 { "ample text."   , 11 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
287         };
288         // clang-format on
289         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
290         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
291                                                    << " vs " << std::endl
292                                                    << toString(textBuf, actual);
293         // clang-format off
294         expect = {
295                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
296                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
297         };
298         // clang-format on
299         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
300         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
301                                                    << " vs " << std::endl
302                                                    << toString(textBuf, actual);
303         // clang-format off
304         expect = {
305                 { "This is an ex-", 14 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
306                 { "ample text."   , 11 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
307         };
308         // clang-format on
309         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
310         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
311                                                    << " vs " << std::endl
312                                                    << toString(textBuf, actual);
313     }
314     {
315         constexpr float LINE_WIDTH = 13 * CHAR_WIDTH;
316         // clang-format off
317         std::vector<LineBreakExpectation> expect = {
318                 { "This is an "   , 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
319                 { "example text." , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
320         };
321         // clang-format on
322 
323         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
324         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
325                                                    << " vs " << std::endl
326                                                    << toString(textBuf, actual);
327         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
328         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
329                                                    << " vs " << std::endl
330                                                    << toString(textBuf, actual);
331         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
332         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
333                                                    << " vs " << std::endl
334                                                    << toString(textBuf, actual);
335         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
336         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
337                                                    << " vs " << std::endl
338                                                    << toString(textBuf, actual);
339     }
340     {
341         constexpr float LINE_WIDTH = 12 * CHAR_WIDTH;
342         // clang-format off
343         std::vector<LineBreakExpectation> expect = {
344                 { "This is an ", 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
345                 { "example "   ,  7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
346                 { "text."      ,  5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
347         };
348         // clang-format on
349 
350         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
351         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
352                                                    << " vs " << std::endl
353                                                    << toString(textBuf, actual);
354         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
355         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
356                                                    << " vs " << std::endl
357                                                    << toString(textBuf, actual);
358         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
359         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
360                                                    << " vs " << std::endl
361                                                    << toString(textBuf, actual);
362         // clang-format off
363         expect = {
364                 { "This is " ,  7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
365                 { "an exam-" ,  8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
366                 { "ple text.",  9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
367         };
368         // clang-format on
369         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
370         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
371                                                    << " vs " << std::endl
372                                                    << toString(textBuf, actual);
373     }
374     {
375         constexpr float LINE_WIDTH = 9 * CHAR_WIDTH;
376         // clang-format off
377         std::vector<LineBreakExpectation> expect = {
378                 { "This "   , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
379                 { "is an "  , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
380                 { "example ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
381                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
382         };
383         // clang-format on
384 
385         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
386         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
387                                                    << " vs " << std::endl
388                                                    << toString(textBuf, actual);
389         // clang-format off
390         expect = {
391                 { "This is " , 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
392                 { "an exam-" , 8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
393                 { "ple text.", 9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
394         };
395         // clang-format on
396         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
397         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
398                                                    << " vs " << std::endl
399                                                    << toString(textBuf, actual);
400         // clang-format off
401         expect = {
402                 { "This "   , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
403                 { "is an "  , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
404                 { "example ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
405                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
406         };
407         // clang-format on
408         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
409         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
410                                                    << " vs " << std::endl
411                                                    << toString(textBuf, actual);
412         // clang-format off
413         expect = {
414                 { "This is " , 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
415                 { "an exam-" , 8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
416                 { "ple text.", 9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
417         };
418         // clang-format on
419         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
420         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
421                                                    << " vs " << std::endl
422                                                    << toString(textBuf, actual);
423     }
424     {
425         constexpr float LINE_WIDTH = 8 * CHAR_WIDTH;
426         // clang-format off
427         std::vector<LineBreakExpectation> expect = {
428                 { "This "   , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
429                 { "is an "  , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
430                 { "example ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
431                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
432         };
433         // clang-format on
434 
435         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
436         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
437                                                    << " vs " << std::endl
438                                                    << toString(textBuf, actual);
439         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
440         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
441                                                    << " vs " << std::endl
442                                                    << toString(textBuf, actual);
443         // clang-format off
444         expect = {
445                 { "This is ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
446                 { "an ex-"  , 6 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
447                 { "ample "  , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
448                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
449         };
450         // clang-format on
451         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
452         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
453                                                    << " vs " << std::endl
454                                                    << toString(textBuf, actual);
455         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
456         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
457                                                    << " vs " << std::endl
458                                                    << toString(textBuf, actual);
459     }
460     {
461         constexpr float LINE_WIDTH = 7 * CHAR_WIDTH;
462         // clang-format off
463         std::vector<LineBreakExpectation> expect = {
464                 { "This "   , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
465                 { "is an "  , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
466                 { "example ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
467                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
468         };
469         // clang-format on
470 
471         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
472         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
473                                                    << " vs " << std::endl
474                                                    << toString(textBuf, actual);
475         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
476         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
477                                                    << " vs " << std::endl
478                                                    << toString(textBuf, actual);
479         // clang-format off
480         expect = {
481                 { "This is ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
482                 { "an ex-"  , 6 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
483                 { "ample "  , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
484                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
485         };
486         // clang-format on
487         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
488         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
489                                                    << " vs " << std::endl
490                                                    << toString(textBuf, actual);
491         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
492         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
493                                                    << " vs " << std::endl
494                                                    << toString(textBuf, actual);
495     }
496     {
497         constexpr float LINE_WIDTH = 6 * CHAR_WIDTH;
498         // clang-format off
499         std::vector<LineBreakExpectation> expect = {
500                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
501                 { "is an ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
502                 // TODO: Is this desperate break working correctly?
503                 { "exa"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
504                 { "mple " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
505                 { "text." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
506         };
507         // clang-format on
508 
509         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
510         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
511                                                    << " vs " << std::endl
512                                                    << toString(textBuf, actual);
513         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
514         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
515                                                    << " vs " << std::endl
516                                                    << toString(textBuf, actual);
517         // clang-format off
518         expect = {
519                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
520                 { "is an ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
521                 { "exam-" , 5 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
522                 { "ple "  , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
523                 { "text." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
524         };
525         // clang-format on
526         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
527         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
528                                                    << " vs " << std::endl
529                                                    << toString(textBuf, actual);
530         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
531         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
532                                                    << " vs " << std::endl
533                                                    << toString(textBuf, actual);
534     }
535     {
536         constexpr float LINE_WIDTH = 5 * CHAR_WIDTH;
537         // clang-format off
538         std::vector<LineBreakExpectation> expect = {
539                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
540                 { "is an ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
541                 // TODO: Is this desperate break working correctly?
542                 { "exa"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
543                 { "mple " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
544                 { "text." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
545         };
546         // clang-format on
547 
548         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
549         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
550                                                    << " vs " << std::endl
551                                                    << toString(textBuf, actual);
552         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
553         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
554                                                    << " vs " << std::endl
555                                                    << toString(textBuf, actual);
556         // clang-format off
557         expect = {
558                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
559                 { "is an ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
560                 { "exam-" , 5 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
561                 { "ple "  , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
562                 { "text." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
563         };
564         // clang-format on
565         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
566         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
567                                                    << " vs " << std::endl
568                                                    << toString(textBuf, actual);
569         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
570         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
571                                                    << " vs " << std::endl
572                                                    << toString(textBuf, actual);
573     }
574     {
575         constexpr float LINE_WIDTH = 4 * CHAR_WIDTH;
576         // clang-format off
577         std::vector<LineBreakExpectation> expect = {
578                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
579                 { "is "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
580                 { "an "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
581                 // TODO: Is this desperate break working correctly?
582                 { "exa"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
583                 { "mple " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
584                 { "text"  , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
585                 { "."     , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
586         };
587         // clang-format on
588 
589         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
590         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
591                                                    << " vs " << std::endl
592                                                    << toString(textBuf, actual);
593         // clang-format off
594         expect = {
595                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
596                 { "is "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
597                 { "an "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
598                 // TODO: Is this desperate break working correctly?
599                 { "exa"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
600                 { "mple " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
601                 // TODO: Is this desperate break working correctly?
602                 { "t"     , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
603                 { "ext."  , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
604         };
605         // clang-format on
606         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
607         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
608                                                    << " vs " << std::endl
609                                                    << toString(textBuf, actual);
610         // clang-format off
611         expect = {
612                 { "This ", 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
613                 { "is "  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
614                 { "an "  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
615                 { "ex-"  , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
616                 { "am-"  , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
617                 { "ple " , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
618                 { "text" , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
619                 { "."    , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
620         };
621         // clang-format on
622         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
623         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
624                                                    << " vs " << std::endl
625                                                    << toString(textBuf, actual);
626         // clang-format off
627         expect = {
628                 { "This ", 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
629                 { "is "  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
630                 { "an "  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
631                 { "ex-"  , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
632                 { "am-"  , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
633                 { "ple " , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
634                 // TODO: Is this desperate break working correctly?
635                 { "te"   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
636                 { "xt."  , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
637         };
638         // clang-format on
639         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
640         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
641                                                    << " vs " << std::endl
642                                                    << toString(textBuf, actual);
643     }
644     {
645         constexpr float LINE_WIDTH = 3 * CHAR_WIDTH;
646         // clang-format off
647         std::vector<LineBreakExpectation> expect = {
648                 // TODO: Is this desperate break working correctly?
649                 { "T"   , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
650                 { "his ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
651                 { "is " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
652                 { "an " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
653                 // TODO: Is this desperate break working correctly?
654                 { "e"   , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
655                 { "xam" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
656                 { "ple ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
657                 { "tex" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
658                 { "t."  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
659         };
660         // clang-format on
661 
662         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
663         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
664                                                    << " vs " << std::endl
665                                                    << toString(textBuf, actual);
666         // clang-format off
667         expect = {
668                 // TODO: Is this desperate break working correctly?
669                 { "T"   , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
670                 { "his ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
671                 { "is " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
672                 { "an " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
673                 // TODO: Is this desperate break working correctly?
674                 { "e"   , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
675                 { "xam" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
676                 { "ple ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
677                 // TODO: Is this desperate break working correctly?
678                 { "te"  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
679                 { "xt." , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
680         };
681         // clang-format on
682         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
683         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
684                                                    << " vs " << std::endl
685                                                    << toString(textBuf, actual);
686         // clang-format off
687         expect = {
688                 // TODO: Is this desperate break working correctly?
689                 { "T"   , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
690                 { "his ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
691                 { "is " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
692                 { "an " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
693                 { "ex-" , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
694                 { "am-" , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
695                 { "ple ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
696                 { "tex" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
697                 { "t."  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
698         };
699         // clang-format on
700         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
701         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
702                                                    << " vs " << std::endl
703                                                    << toString(textBuf, actual);
704         // clang-format off
705         expect = {
706                 // TODO: Is this desperate break working correctly?
707                 {"T"   , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
708                 {"his ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
709                 {"is " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
710                 {"an " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
711                 {"ex-" , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN},
712                 {"am-" , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN},
713                 {"ple ", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
714                 // TODO: Is this desperate break working correctly?
715                 {"te"  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
716                 {"xt." , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
717         };
718         // clang-format on
719         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
720         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
721                                                    << " vs " << std::endl
722                                                    << toString(textBuf, actual);
723     }
724     {
725         constexpr float LINE_WIDTH = 2 * CHAR_WIDTH;
726         // clang-format off
727         std::vector<LineBreakExpectation> expect = {
728                 { "Th" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
729                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
730                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
731                 { "an ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
732                 // TODO: Is this desperate break working correctly?
733                 { "e"  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
734                 { "xa" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
735                 { "mp" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
736                 { "le ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
737                 { "te" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
738                 { "xt" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
739                 { "."  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
740         };
741         // clang-format on
742 
743         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
744         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
745                                                    << " vs " << std::endl
746                                                    << toString(textBuf, actual);
747         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
748         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
749                                                    << " vs " << std::endl
750                                                    << toString(textBuf, actual);
751         // clang-format off
752         expect = {
753                 { "Th" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
754                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
755                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
756                 { "an ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
757                 // TODO: Is this desperate break working correctly?
758                 { "e"  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
759                 { "xa" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
760                 { "mp" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
761                 { "le ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
762                 // TODO: Is this desperate break working correctly?
763                 { "t"  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
764                 { "ex" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
765                 { "t." , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
766         };
767         // clang-format on
768         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
769         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
770                                                    << " vs " << std::endl
771                                                    << toString(textBuf, actual);
772         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
773         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
774                                                    << " vs " << std::endl
775                                                    << toString(textBuf, actual);
776     }
777     {
778         constexpr float LINE_WIDTH = 1 * CHAR_WIDTH;
779         // clang-format off
780         std::vector<LineBreakExpectation> expect = {
781                 { "T" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
782                 { "h" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
783                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
784                 { "s ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
785                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
786                 { "s ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
787                 { "a" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
788                 { "n ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
789                 { "e" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
790                 { "x" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
791                 { "a" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
792                 { "m" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
793                 { "p" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
794                 { "l" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
795                 { "e ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
796                 { "t" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
797                 { "e" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
798                 { "x" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
799                 { "t" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
800                 { "." , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
801         };
802         // clang-format on
803 
804         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
805         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
806                                                    << " vs " << std::endl
807                                                    << toString(textBuf, actual);
808         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
809         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
810                                                    << " vs " << std::endl
811                                                    << toString(textBuf, actual);
812         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
813         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
814                                                    << " vs " << std::endl
815                                                    << toString(textBuf, actual);
816         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
817         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
818                                                    << " vs " << std::endl
819                                                    << toString(textBuf, actual);
820     }
821 }
822 
TEST_F(OptimalLineBreakerTest,testHyphenationStartLineChange)823 TEST_F(OptimalLineBreakerTest, testHyphenationStartLineChange) {
824     constexpr float CHAR_WIDTH = 10.0;
825     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
826     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
827     // "hyphenation" is hyphnated to "hy-phen-a-tion".
828     const std::vector<uint16_t> textBuf = utf8ToUtf16("czerwono-niebieska");
829 
830     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
831     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
832     constexpr StartHyphenEdit START_HYPHEN = StartHyphenEdit::INSERT_HYPHEN;
833 
834     // Note that disable clang-format everywhere since aligned expectation is more readable.
835     {
836         constexpr float LINE_WIDTH = 1000 * CHAR_WIDTH;
837         std::vector<LineBreakExpectation> expect = {
838                 {"czerwono-niebieska", 18 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
839         };
840 
841         const auto actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, "pl",
842                                         LINE_WIDTH);
843         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
844                                                    << " vs " << std::endl
845                                                    << toString(textBuf, actual);
846     }
847     {
848         constexpr float LINE_WIDTH = 18 * CHAR_WIDTH;
849         std::vector<LineBreakExpectation> expect = {
850                 {"czerwono-niebieska", 18 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
851         };
852 
853         const auto actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, "pl",
854                                         LINE_WIDTH);
855         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
856                                                    << " vs " << std::endl
857                                                    << toString(textBuf, actual);
858     }
859     {
860         constexpr float LINE_WIDTH = 13 * CHAR_WIDTH;
861         // clang-format off
862         std::vector<LineBreakExpectation> expect = {
863                 {"czerwono-" ,  9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
864                 {"-niebieska", 10 * CHAR_WIDTH,    START_HYPHEN, NO_END_HYPHEN},
865         };
866         // clang-format on
867 
868         const auto actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, "pl",
869                                         LINE_WIDTH);
870         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
871                                                    << " vs " << std::endl
872                                                    << toString(textBuf, actual);
873     }
874 }
875 
TEST_F(OptimalLineBreakerTest,testZeroWidthLine)876 TEST_F(OptimalLineBreakerTest, testZeroWidthLine) {
877     constexpr float CHAR_WIDTH = 10.0;
878     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
879     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
880     constexpr float LINE_WIDTH = 0 * CHAR_WIDTH;
881 
882     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
883     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
884 
885     {
886         const auto textBuf = utf8ToUtf16("");
887         std::vector<LineBreakExpectation> expect = {};
888         const auto actual =
889                 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
890         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
891                                                    << " vs " << std::endl
892                                                    << toString(textBuf, actual);
893     }
894     {
895         const auto textBuf = utf8ToUtf16("A");
896         std::vector<LineBreakExpectation> expect = {
897                 {"A", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
898         };
899         const auto actual =
900                 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
901         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
902                                                    << " vs " << std::endl
903                                                    << toString(textBuf, actual);
904     }
905     {
906         const auto textBuf = utf8ToUtf16("AB");
907         std::vector<LineBreakExpectation> expect = {
908                 {"A", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
909                 {"B", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
910         };
911         const auto actual =
912                 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
913         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
914                                                    << " vs " << std::endl
915                                                    << toString(textBuf, actual);
916     }
917 }
918 
TEST_F(OptimalLineBreakerTest,testZeroWidthCharacter)919 TEST_F(OptimalLineBreakerTest, testZeroWidthCharacter) {
920     constexpr float CHAR_WIDTH = 0.0;
921     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
922     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
923 
924     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
925     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
926     {
927         constexpr float LINE_WIDTH = 1.0;
928         const auto textBuf = utf8ToUtf16("This is an example text.");
929         std::vector<LineBreakExpectation> expect = {
930                 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN},
931         };
932         const auto actual =
933                 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
934         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
935                                                    << " vs " << std::endl
936                                                    << toString(textBuf, actual);
937     }
938     {
939         constexpr float LINE_WIDTH = 0.0;
940         const auto textBuf = utf8ToUtf16("This is an example text.");
941         std::vector<LineBreakExpectation> expect = {
942                 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN},
943         };
944         const auto actual =
945                 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
946         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
947                                                    << " vs " << std::endl
948                                                    << toString(textBuf, actual);
949     }
950 }
951 
TEST_F(OptimalLineBreakerTest,testLocaleSwitchTest)952 TEST_F(OptimalLineBreakerTest, testLocaleSwitchTest) {
953     constexpr float CHAR_WIDTH = 10.0;
954     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
955     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
956 
957     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
958     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
959 
960     constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
961     const auto textBuf = utf8ToUtf16("This is an example text.");
962     {
963         std::vector<LineBreakExpectation> expect = {
964                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
965         };
966 
967         MeasuredTextBuilder builder;
968         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
969         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "en-US", CHAR_WIDTH);
970         std::unique_ptr<MeasuredText> measuredText = builder.build(
971                 textBuf, true /* compute hyphenation */, false /* compute full layout */);
972 
973         const auto actual =
974                 doLineBreak(textBuf, *measuredText, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
975         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
976                                                    << " vs " << std::endl
977                                                    << toString(textBuf, actual);
978     }
979     {
980         std::vector<LineBreakExpectation> expect = {
981                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
982         };
983 
984         MeasuredTextBuilder builder;
985         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
986         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH);
987         std::unique_ptr<MeasuredText> measuredText = builder.build(
988                 textBuf, true /* compute hyphenation */, false /* compute full layout */);
989         const auto actual =
990                 doLineBreak(textBuf, *measuredText, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
991         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
992                                                    << " vs " << std::endl
993                                                    << toString(textBuf, actual);
994     }
995 }
996 
TEST_F(OptimalLineBreakerTest,testEmailOrUrl)997 TEST_F(OptimalLineBreakerTest, testEmailOrUrl) {
998     constexpr float CHAR_WIDTH = 10.0;
999     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
1000     constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
1001     constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
1002     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
1003 
1004     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1005     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1006     {
1007         constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
1008         const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
1009         // clang-format off
1010         std::vector<LineBreakExpectation> expect = {
1011                 // TODO: Fix this. Prefer not to break inside URL.
1012                 {"This is an url: http://a", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1013                 {".b",                        2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1014         };
1015         // clang-format on
1016         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1017         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1018                                                    << " vs " << std::endl
1019                                                    << toString(textBuf, actual);
1020         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1021         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1022                                                    << " vs " << std::endl
1023                                                    << toString(textBuf, actual);
1024         // clang-format off
1025         expect = {
1026                 {"This is an url: ", 15 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1027                 {"http://a.b",       10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1028         };
1029         // clang-format on
1030         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1031         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1032                                                    << " vs " << std::endl
1033                                                    << toString(textBuf, actual);
1034         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1035         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1036                                                    << " vs " << std::endl
1037                                                    << toString(textBuf, actual);
1038     }
1039     {
1040         constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
1041         const auto textBuf = utf8ToUtf16("This is an email: a@example.com");
1042         // clang-format off
1043         std::vector<LineBreakExpectation> expect = {
1044                 {"This is an email: ", 17 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1045                 {"a@example.com"     , 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1046         };
1047         // clang-format on
1048 
1049         auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1050         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1051                                                    << " vs " << std::endl
1052                                                    << toString(textBuf, actual);
1053         actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1054         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1055                                                    << " vs " << std::endl
1056                                                    << toString(textBuf, actual);
1057         actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1058         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1059                                                    << " vs " << std::endl
1060                                                    << toString(textBuf, actual);
1061         actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, CHAR_WIDTH, LINE_WIDTH);
1062         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1063                                                    << " vs " << std::endl
1064                                                    << toString(textBuf, actual);
1065     }
1066 }
1067 
TEST_F(OptimalLineBreakerTest,testLocaleSwitch_InEmailOrUrl)1068 TEST_F(OptimalLineBreakerTest, testLocaleSwitch_InEmailOrUrl) {
1069     constexpr float CHAR_WIDTH = 10.0;
1070     constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
1071     constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
1072     constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
1073     constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
1074 
1075     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1076     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1077 
1078     constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
1079     {
1080         const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
1081         MeasuredTextBuilder builder;
1082         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
1083         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH);
1084         std::unique_ptr<MeasuredText> measured = builder.build(
1085                 textBuf, true /* compute hyphenation */, false /* compute full layout */);
1086 
1087         // clang-format off
1088         std::vector<LineBreakExpectation> expect = {
1089                 // TODO: Fix this. Prefer not to break inside URL.
1090                 {"This is an url: http://a", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1091                 {".b",                        2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1092         };
1093         // clang-format on
1094 
1095         auto actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1096         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1097                                                    << " vs " << std::endl
1098                                                    << toString(textBuf, actual);
1099         actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1100         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1101                                                    << " vs " << std::endl
1102                                                    << toString(textBuf, actual);
1103 
1104         // clang-format off
1105         expect = {
1106                 {"This is an url: ", 15 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1107                 {"http://a.b",       10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1108         };
1109         // clang-format on
1110 
1111         actual = doLineBreak(textBuf, *measured, BALANCED, NO_HYPHENATION, LINE_WIDTH);
1112         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1113                                                    << " vs " << std::endl
1114                                                    << toString(textBuf, actual);
1115         actual = doLineBreak(textBuf, *measured, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
1116         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1117                                                    << " vs " << std::endl
1118                                                    << toString(textBuf, actual);
1119     }
1120     {
1121         const auto textBuf = utf8ToUtf16("This is an email: a@example.com");
1122         MeasuredTextBuilder builder;
1123         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
1124         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH);
1125         std::unique_ptr<MeasuredText> measured = builder.build(
1126                 textBuf, true /* compute hyphenation */, false /* compute full layout */);
1127 
1128         // clang-format off
1129         std::vector<LineBreakExpectation> expect = {
1130                 {"This is an email: ", 17 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1131                 {"a@example.com",      13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
1132         };
1133         // clang-format on
1134 
1135         auto actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1136         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1137                                                    << " vs " << std::endl
1138                                                    << toString(textBuf, actual);
1139         actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1140         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1141                                                    << " vs " << std::endl
1142                                                    << toString(textBuf, actual);
1143         actual = doLineBreak(textBuf, *measured, BALANCED, NO_HYPHENATION, LINE_WIDTH);
1144         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1145                                                    << " vs " << std::endl
1146                                                    << toString(textBuf, actual);
1147         actual = doLineBreak(textBuf, *measured, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
1148         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1149                                                    << " vs " << std::endl
1150                                                    << toString(textBuf, actual);
1151     }
1152 }
1153 
1154 }  // namespace
1155 }  // namespace minikin
1156