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