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 // The ascent/descent of Ascii.ttf with text size = 10.
43 constexpr float ASCENT = -80.0f;
44 constexpr float DESCENT = 20.0f;
45
46 // The ascent/descent of CustomExtent.ttf with text size = 10.
47 constexpr float CUSTOM_ASCENT = -160.0f;
48 constexpr float CUSTOM_DESCENT = 40.0f;
49
50 class OptimalLineBreakerTest : public testing::Test {
51 public:
OptimalLineBreakerTest()52 OptimalLineBreakerTest() {}
53
~OptimalLineBreakerTest()54 virtual ~OptimalLineBreakerTest() {}
55
SetUp()56 virtual void SetUp() override {
57 mHyphenationPattern = readWholeFile("/system/usr/hyphen-data/hyph-en-us.hyb");
58 Hyphenator* hyphenator = Hyphenator::loadBinary(
59 mHyphenationPattern.data(), 2 /* min prefix */, 2 /* min suffix */, "en-US");
60 HyphenatorMap::add("en-US", hyphenator);
61 HyphenatorMap::add("pl", Hyphenator::loadBinary(nullptr, 0, 0, "pl"));
62 }
63
TearDown()64 virtual void TearDown() override { HyphenatorMap::clear(); }
65
66 protected:
doLineBreak(const U16StringPiece & textBuffer,BreakStrategy strategy,HyphenationFrequency frequency,float lineWidth)67 LineBreakResult doLineBreak(const U16StringPiece& textBuffer, BreakStrategy strategy,
68 HyphenationFrequency frequency, float lineWidth) {
69 return doLineBreak(textBuffer, strategy, frequency, "en-US", lineWidth);
70 }
71
doLineBreak(const U16StringPiece & textBuffer,BreakStrategy strategy,HyphenationFrequency frequency,const std::string & lang,float lineWidth)72 LineBreakResult doLineBreak(const U16StringPiece& textBuffer, BreakStrategy strategy,
73 HyphenationFrequency frequency, const std::string& lang,
74 float lineWidth) {
75 MeasuredTextBuilder builder;
76 auto family1 = buildFontFamily("Ascii.ttf");
77 auto family2 = buildFontFamily("CustomExtent.ttf");
78 std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
79 auto fc = std::make_shared<FontCollection>(families);
80 MinikinPaint paint(fc);
81 paint.size = 10.0f; // Make 1em=1px
82 paint.localeListId = LocaleListCache::getId(lang);
83 builder.addStyleRun(0, textBuffer.size(), std::move(paint), false);
84 std::unique_ptr<MeasuredText> measuredText =
85 builder.build(textBuffer, true /* compute hyphenation */,
86 false /* compute full layout */, nullptr /* no hint */);
87 return doLineBreak(textBuffer, *measuredText, strategy, frequency, lineWidth);
88 }
89
doLineBreak(const U16StringPiece & textBuffer,const MeasuredText & measuredText,BreakStrategy strategy,HyphenationFrequency frequency,float lineWidth)90 LineBreakResult doLineBreak(const U16StringPiece& textBuffer, const MeasuredText& measuredText,
91 BreakStrategy strategy, HyphenationFrequency frequency,
92 float lineWidth) {
93 RectangleLineWidth rectangleLineWidth(lineWidth);
94 return breakLineOptimal(textBuffer, measuredText, rectangleLineWidth, strategy, frequency,
95 false /* justified */);
96 }
97
98 private:
99 std::vector<uint8_t> mHyphenationPattern;
100 };
101
TEST_F(OptimalLineBreakerTest,testBreakWithoutHyphenation)102 TEST_F(OptimalLineBreakerTest, testBreakWithoutHyphenation) {
103 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
104 constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
105 constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
106 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
107 const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
108
109 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
110 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
111 constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
112 // Note that disable clang-format everywhere since aligned expectation is more readable.
113 {
114 constexpr float LINE_WIDTH = 1000;
115 std::vector<LineBreakExpectation> expect = {
116 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
117 };
118
119 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
120 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
121 << " vs " << std::endl
122 << toString(textBuf, actual);
123 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
124 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
125 << " vs " << std::endl
126 << toString(textBuf, actual);
127 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
128 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
129 << " vs " << std::endl
130 << toString(textBuf, actual);
131 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
132 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
133 << " vs " << std::endl
134 << toString(textBuf, actual);
135 }
136 {
137 constexpr float LINE_WIDTH = 240;
138 std::vector<LineBreakExpectation> expect = {
139 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
140 };
141 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
142 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
143 << " vs " << std::endl
144 << toString(textBuf, actual);
145 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
146 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
147 << " vs " << std::endl
148 << toString(textBuf, actual);
149 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
150 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
151 << " vs " << std::endl
152 << toString(textBuf, actual);
153 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
154 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
155 << " vs " << std::endl
156 << toString(textBuf, actual);
157 }
158 {
159 constexpr float LINE_WIDTH = 230;
160 // clang-format off
161 std::vector<LineBreakExpectation> expect = {
162 { "This is an example " , 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
163 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
164 };
165 // clang-format on
166
167 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
168 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
169 << " vs " << std::endl
170 << toString(textBuf, actual);
171 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
172 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
173 << " vs " << std::endl
174 << toString(textBuf, actual);
175
176 // clang-format off
177 expect = {
178 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
179 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
180 };
181 // clang-format on
182 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
183 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
184 << " vs " << std::endl
185 << toString(textBuf, actual);
186 // clang-format off
187 expect = {
188 { "This is an ex-" , 140, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
189 { "ample text." , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
190 };
191 // clang-format on
192 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
193 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
194 << " vs " << std::endl
195 << toString(textBuf, actual);
196 }
197 {
198 constexpr float LINE_WIDTH = 170;
199 // clang-format off
200 std::vector<LineBreakExpectation> expect = {
201 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
202 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
203 };
204 // clang-format on
205
206 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
207 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
208 << " vs " << std::endl
209 << toString(textBuf, actual);
210 // clang-format off
211 expect = {
212 { "This is an exam-" , 160, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
213 { "ple text." , 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
214 };
215 // clang-format on
216 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
217 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
218 << " vs " << std::endl
219 << toString(textBuf, actual);
220 // clang-format off
221 expect = {
222 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
223 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
224 };
225 // clang-format on
226 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
227 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
228 << " vs " << std::endl
229 << toString(textBuf, actual);
230 // clang-format off
231 expect = {
232 { "This is an ex-", 140, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
233 { "ample text." , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
234 };
235 // clang-format on
236 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
237 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
238 << " vs " << std::endl
239 << toString(textBuf, actual);
240 }
241 {
242 constexpr float LINE_WIDTH = 160;
243 // clang-format off
244 std::vector<LineBreakExpectation> expect = {
245 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
246 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
247 };
248 // clang-format on
249
250 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
251 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
252 << " vs " << std::endl
253 << toString(textBuf, actual);
254 // clang-format off
255 expect = {
256 { "This is an exam-" , 160, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
257 { "ple text." , 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
258 };
259 // clang-format on
260 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
261 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
262 << " vs " << std::endl
263 << toString(textBuf, actual);
264 // clang-format off
265 expect = {
266 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
267 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
268 };
269 // clang-format on
270 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
271 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
272 << " vs " << std::endl
273 << toString(textBuf, actual);
274 // clang-format off
275 expect = {
276 { "This is an ex-", 140, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
277 { "ample text." , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
278 };
279 // clang-format on
280 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
281 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
282 << " vs " << std::endl
283 << toString(textBuf, actual);
284 }
285 {
286 constexpr float LINE_WIDTH = 150;
287 // clang-format off
288 std::vector<LineBreakExpectation> expect = {
289 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
290 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
291 };
292 // clang-format on
293
294 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
295 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
296 << " vs " << std::endl
297 << toString(textBuf, actual);
298 // clang-format off
299 expect = {
300 { "This is an ex-", 140, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
301 { "ample text." , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
302 };
303 // clang-format on
304 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
305 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
306 << " vs " << std::endl
307 << toString(textBuf, actual);
308 // clang-format off
309 expect = {
310 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
311 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
312 };
313 // clang-format on
314 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
315 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
316 << " vs " << std::endl
317 << toString(textBuf, actual);
318 // clang-format off
319 expect = {
320 { "This is an ex-", 140, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
321 { "ample text." , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
322 };
323 // clang-format on
324 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
325 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
326 << " vs " << std::endl
327 << toString(textBuf, actual);
328 }
329 {
330 constexpr float LINE_WIDTH = 130;
331 // clang-format off
332 std::vector<LineBreakExpectation> expect = {
333 { "This is an " , 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
334 { "example text." , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
335 };
336 // clang-format on
337
338 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
339 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
340 << " vs " << std::endl
341 << toString(textBuf, actual);
342 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
343 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
344 << " vs " << std::endl
345 << toString(textBuf, actual);
346 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
347 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
348 << " vs " << std::endl
349 << toString(textBuf, actual);
350 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
351 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
352 << " vs " << std::endl
353 << toString(textBuf, actual);
354 }
355 {
356 constexpr float LINE_WIDTH = 120;
357 // clang-format off
358 std::vector<LineBreakExpectation> expect = {
359 { "This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
360 { "example " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
361 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
362 };
363 // clang-format on
364
365 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
366 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
367 << " vs " << std::endl
368 << toString(textBuf, actual);
369 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
370 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
371 << " vs " << std::endl
372 << toString(textBuf, actual);
373 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
374 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
375 << " vs " << std::endl
376 << toString(textBuf, actual);
377 // clang-format off
378 expect = {
379 { "This is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
380 { "an exam-" , 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
381 { "ple text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
382 };
383 // clang-format on
384 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
385 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
386 << " vs " << std::endl
387 << toString(textBuf, actual);
388 }
389 {
390 constexpr float LINE_WIDTH = 90;
391 // clang-format off
392 std::vector<LineBreakExpectation> expect = {
393 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
394 { "is an " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
395 { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
396 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
397 };
398 // clang-format on
399
400 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
401 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
402 << " vs " << std::endl
403 << toString(textBuf, actual);
404 // clang-format off
405 expect = {
406 { "This is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
407 { "an exam-" , 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
408 { "ple text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
409 };
410 // clang-format on
411 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
412 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
413 << " vs " << std::endl
414 << toString(textBuf, actual);
415 // clang-format off
416 expect = {
417 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
418 { "is an " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
419 { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
420 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
421 };
422 // clang-format on
423 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
424 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
425 << " vs " << std::endl
426 << toString(textBuf, actual);
427 // clang-format off
428 expect = {
429 { "This is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
430 { "an exam-" , 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
431 { "ple text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
432 };
433 // clang-format on
434 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
435 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
436 << " vs " << std::endl
437 << toString(textBuf, actual);
438 }
439 {
440 constexpr float LINE_WIDTH = 80;
441 // clang-format off
442 std::vector<LineBreakExpectation> expect = {
443 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
444 { "is an " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
445 { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
446 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
447 };
448 // clang-format on
449
450 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
451 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
452 << " vs " << std::endl
453 << toString(textBuf, actual);
454 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
455 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
456 << " vs " << std::endl
457 << toString(textBuf, actual);
458 // clang-format off
459 expect = {
460 { "This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
461 { "an ex-" , 60, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
462 { "ample " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
463 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
464 };
465 // clang-format on
466 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
467 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
468 << " vs " << std::endl
469 << toString(textBuf, actual);
470 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
471 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
472 << " vs " << std::endl
473 << toString(textBuf, actual);
474 }
475 {
476 constexpr float LINE_WIDTH = 70;
477 // clang-format off
478 std::vector<LineBreakExpectation> expect = {
479 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
480 { "is an " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
481 { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
482 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
483 };
484 // clang-format on
485
486 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
487 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
488 << " vs " << std::endl
489 << toString(textBuf, actual);
490 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
491 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
492 << " vs " << std::endl
493 << toString(textBuf, actual);
494 // clang-format off
495 expect = {
496 { "This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
497 { "an ex-" , 60, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
498 { "ample " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
499 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
500 };
501 // clang-format on
502 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
503 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
504 << " vs " << std::endl
505 << toString(textBuf, actual);
506 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
507 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
508 << " vs " << std::endl
509 << toString(textBuf, actual);
510 }
511 {
512 constexpr float LINE_WIDTH = 60;
513 // clang-format off
514 std::vector<LineBreakExpectation> expect = {
515 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
516 { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
517 // TODO: Is this desperate break working correctly?
518 { "exa" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
519 { "mple " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
520 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
521 };
522 // clang-format on
523
524 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
525 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
526 << " vs " << std::endl
527 << toString(textBuf, actual);
528 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
529 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
530 << " vs " << std::endl
531 << toString(textBuf, actual);
532 // clang-format off
533 expect = {
534 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
535 { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
536 { "exam-" , 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
537 { "ple " , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
538 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
539 };
540 // clang-format on
541 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
542 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
543 << " vs " << std::endl
544 << toString(textBuf, actual);
545 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
546 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
547 << " vs " << std::endl
548 << toString(textBuf, actual);
549 }
550 {
551 constexpr float LINE_WIDTH = 50;
552 // clang-format off
553 std::vector<LineBreakExpectation> expect = {
554 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
555 { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
556 // TODO: Is this desperate break working correctly?
557 { "exa" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
558 { "mple " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
559 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
560 };
561 // clang-format on
562
563 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
564 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
565 << " vs " << std::endl
566 << toString(textBuf, actual);
567 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
568 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
569 << " vs " << std::endl
570 << toString(textBuf, actual);
571 // clang-format off
572 expect = {
573 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
574 { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
575 { "exam-" , 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
576 { "ple " , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
577 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
578 };
579 // clang-format on
580 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
581 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
582 << " vs " << std::endl
583 << toString(textBuf, actual);
584 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
585 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
586 << " vs " << std::endl
587 << toString(textBuf, actual);
588 }
589 {
590 constexpr float LINE_WIDTH = 40;
591 // clang-format off
592 std::vector<LineBreakExpectation> expect = {
593 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
594 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
595 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
596 // TODO: Is this desperate break working correctly?
597 { "exa" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
598 { "mple " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
599 { "text" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
600 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
601 };
602 // clang-format on
603
604 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
605 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
606 << " vs " << std::endl
607 << toString(textBuf, actual);
608 // clang-format off
609 expect = {
610 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
611 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
612 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
613 // TODO: Is this desperate break working correctly?
614 { "exa" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
615 { "mple " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
616 // TODO: Is this desperate break working correctly?
617 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
618 { "ext." , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
619 };
620 // clang-format on
621 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
622 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
623 << " vs " << std::endl
624 << toString(textBuf, actual);
625 // clang-format off
626 expect = {
627 { "This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
628 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
629 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
630 { "ex-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
631 { "am-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
632 { "ple " , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
633 { "text" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
634 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
635 };
636 // clang-format on
637 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
638 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
639 << " vs " << std::endl
640 << toString(textBuf, actual);
641 // clang-format off
642 expect = {
643 { "This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
644 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
645 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
646 { "ex-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
647 { "am-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
648 { "ple " , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
649 // TODO: Is this desperate break working correctly?
650 { "te" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
651 { "xt." , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
652 };
653 // clang-format on
654 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
655 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
656 << " vs " << std::endl
657 << toString(textBuf, actual);
658 }
659 {
660 constexpr float LINE_WIDTH = 30;
661 // clang-format off
662 std::vector<LineBreakExpectation> expect = {
663 // TODO: Is this desperate break working correctly?
664 { "T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
665 { "his ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
666 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
667 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
668 // TODO: Is this desperate break working correctly?
669 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
670 { "xam" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
671 { "ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
672 { "tex" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
673 { "t." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
674 };
675 // clang-format on
676
677 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
678 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
679 << " vs " << std::endl
680 << toString(textBuf, actual);
681 // clang-format off
682 expect = {
683 // TODO: Is this desperate break working correctly?
684 { "T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
685 { "his ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
686 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
687 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
688 // TODO: Is this desperate break working correctly?
689 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
690 { "xam" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
691 { "ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
692 // TODO: Is this desperate break working correctly?
693 { "te" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
694 { "xt." , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
695 };
696 // clang-format on
697 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
698 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
699 << " vs " << std::endl
700 << toString(textBuf, actual);
701 // clang-format off
702 expect = {
703 // TODO: Is this desperate break working correctly?
704 { "T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
705 { "his ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
706 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
707 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
708 { "ex-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
709 { "am-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
710 { "ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
711 { "tex" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
712 { "t." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
713 };
714 // clang-format on
715 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
716 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
717 << " vs " << std::endl
718 << toString(textBuf, actual);
719 // clang-format off
720 expect = {
721 // TODO: Is this desperate break working correctly?
722 {"T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
723 {"his ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
724 {"is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
725 {"an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
726 {"ex-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
727 {"am-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
728 {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
729 // TODO: Is this desperate break working correctly?
730 {"te" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
731 {"xt." , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
732 };
733 // clang-format on
734 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
735 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
736 << " vs " << std::endl
737 << toString(textBuf, actual);
738 }
739 {
740 constexpr float LINE_WIDTH = 20;
741 // clang-format off
742 std::vector<LineBreakExpectation> expect = {
743 { "Th" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
744 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
745 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
746 { "an ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
747 // TODO: Is this desperate break working correctly?
748 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
749 { "xa" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
750 { "mp" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
751 { "le ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
752 { "te" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
753 { "xt" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
754 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
755 };
756 // clang-format on
757
758 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
759 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
760 << " vs " << std::endl
761 << toString(textBuf, actual);
762 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
763 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
764 << " vs " << std::endl
765 << toString(textBuf, actual);
766 // clang-format off
767 expect = {
768 { "Th" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
769 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
770 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
771 { "an ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
772 // TODO: Is this desperate break working correctly?
773 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
774 { "xa" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
775 { "mp" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
776 { "le ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
777 // TODO: Is this desperate break working correctly?
778 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
779 { "ex" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
780 { "t." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
781 };
782 // clang-format on
783 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
784 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
785 << " vs " << std::endl
786 << toString(textBuf, actual);
787 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
788 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
789 << " vs " << std::endl
790 << toString(textBuf, actual);
791 }
792 {
793 constexpr float LINE_WIDTH = 10;
794 // clang-format off
795 std::vector<LineBreakExpectation> expect = {
796 { "T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
797 { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
798 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
799 { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
800 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
801 { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
802 { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
803 { "n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
804 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
805 { "x" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
806 { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
807 { "m" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
808 { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
809 { "l" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
810 { "e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
811 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
812 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
813 { "x" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
814 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
815 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
816 };
817 // clang-format on
818
819 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
820 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
821 << " vs " << std::endl
822 << toString(textBuf, actual);
823 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
824 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
825 << " vs " << std::endl
826 << toString(textBuf, actual);
827 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
828 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
829 << " vs " << std::endl
830 << toString(textBuf, actual);
831 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
832 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
833 << " vs " << std::endl
834 << toString(textBuf, actual);
835 }
836 }
837
TEST_F(OptimalLineBreakerTest,testHyphenationStartLineChange)838 TEST_F(OptimalLineBreakerTest, testHyphenationStartLineChange) {
839 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
840 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
841 // "hyphenation" is hyphnated to "hy-phen-a-tion".
842 const std::vector<uint16_t> textBuf = utf8ToUtf16("czerwono-niebieska");
843
844 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
845 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
846 constexpr StartHyphenEdit START_HYPHEN = StartHyphenEdit::INSERT_HYPHEN;
847
848 // Note that disable clang-format everywhere since aligned expectation is more readable.
849 {
850 constexpr float LINE_WIDTH = 1000;
851 std::vector<LineBreakExpectation> expect = {
852 {"czerwono-niebieska", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
853 };
854
855 const auto actual =
856 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, "pl", LINE_WIDTH);
857 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
858 << " vs " << std::endl
859 << toString(textBuf, actual);
860 }
861 {
862 constexpr float LINE_WIDTH = 180;
863 std::vector<LineBreakExpectation> expect = {
864 {"czerwono-niebieska", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
865 };
866
867 const auto actual =
868 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, "pl", LINE_WIDTH);
869 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
870 << " vs " << std::endl
871 << toString(textBuf, actual);
872 }
873 {
874 constexpr float LINE_WIDTH = 130;
875 // clang-format off
876 std::vector<LineBreakExpectation> expect = {
877 {"czerwono-" , 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
878 {"-niebieska", 100, START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
879 };
880 // clang-format on
881
882 const auto actual =
883 doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, "pl", LINE_WIDTH);
884 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
885 << " vs " << std::endl
886 << toString(textBuf, actual);
887 }
888 }
889
TEST_F(OptimalLineBreakerTest,testZeroWidthLine)890 TEST_F(OptimalLineBreakerTest, testZeroWidthLine) {
891 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
892 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
893 constexpr float LINE_WIDTH = 0;
894
895 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
896 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
897
898 {
899 const auto textBuf = utf8ToUtf16("");
900 std::vector<LineBreakExpectation> expect = {};
901 const auto actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
902 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
903 << " vs " << std::endl
904 << toString(textBuf, actual);
905 }
906 {
907 const auto textBuf = utf8ToUtf16("A");
908 std::vector<LineBreakExpectation> expect = {
909 {"A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
910 };
911 const auto actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
912 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
913 << " vs " << std::endl
914 << toString(textBuf, actual);
915 }
916 {
917 const auto textBuf = utf8ToUtf16("AB");
918 std::vector<LineBreakExpectation> expect = {
919 {"A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
920 {"B", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
921 };
922 const auto actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
923 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
924 << " vs " << std::endl
925 << toString(textBuf, actual);
926 }
927 }
928
TEST_F(OptimalLineBreakerTest,testZeroWidthCharacter)929 TEST_F(OptimalLineBreakerTest, testZeroWidthCharacter) {
930 constexpr float CHAR_WIDTH = 0.0;
931 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
932 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
933
934 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
935 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
936 {
937 constexpr float LINE_WIDTH = 1.0;
938 const auto textBuf = utf8ToUtf16("This is an example text.");
939 std::vector<LineBreakExpectation> expect = {
940 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
941 };
942 MeasuredTextBuilder builder;
943 builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
944 DESCENT);
945 std::unique_ptr<MeasuredText> measuredText =
946 builder.build(textBuf, true /* compute hyphenation */,
947 false /* compute full layout */, nullptr /* no hint */);
948
949 const auto actual =
950 doLineBreak(textBuf, *measuredText, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
951 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
952 << " vs " << std::endl
953 << toString(textBuf, actual);
954 }
955 {
956 constexpr float LINE_WIDTH = 0.0;
957 const auto textBuf = utf8ToUtf16("This is an example text.");
958 std::vector<LineBreakExpectation> expect = {
959 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
960 };
961 MeasuredTextBuilder builder;
962 builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
963 DESCENT);
964 std::unique_ptr<MeasuredText> measuredText =
965 builder.build(textBuf, true /* compute hyphenation */,
966 false /* compute full layout */, nullptr /* no hint */);
967
968 const auto actual =
969 doLineBreak(textBuf, *measuredText, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
970 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
971 << " vs " << std::endl
972 << toString(textBuf, actual);
973 }
974 }
975
TEST_F(OptimalLineBreakerTest,testLocaleSwitchTest)976 TEST_F(OptimalLineBreakerTest, testLocaleSwitchTest) {
977 constexpr float CHAR_WIDTH = 10.0;
978 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
979 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
980
981 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
982 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
983
984 constexpr float LINE_WIDTH = 240;
985 const auto textBuf = utf8ToUtf16("This is an example text.");
986 {
987 std::vector<LineBreakExpectation> expect = {
988 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
989 };
990
991 MeasuredTextBuilder builder;
992 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
993 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
994 DESCENT);
995 std::unique_ptr<MeasuredText> measuredText =
996 builder.build(textBuf, true /* compute hyphenation */,
997 false /* compute full layout */, nullptr /* no hint */);
998
999 const auto actual =
1000 doLineBreak(textBuf, *measuredText, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1001 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1002 << " vs " << std::endl
1003 << toString(textBuf, actual);
1004 }
1005 {
1006 std::vector<LineBreakExpectation> expect = {
1007 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1008 };
1009
1010 MeasuredTextBuilder builder;
1011 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1012 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
1013 DESCENT);
1014 std::unique_ptr<MeasuredText> measuredText =
1015 builder.build(textBuf, true /* compute hyphenation */,
1016 false /* compute full layout */, nullptr /* no hint */);
1017 const auto actual =
1018 doLineBreak(textBuf, *measuredText, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1019 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1020 << " vs " << std::endl
1021 << toString(textBuf, actual);
1022 }
1023 }
1024
TEST_F(OptimalLineBreakerTest,testEmailOrUrl)1025 TEST_F(OptimalLineBreakerTest, testEmailOrUrl) {
1026 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
1027 constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
1028 constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
1029 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
1030
1031 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1032 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1033 {
1034 constexpr float LINE_WIDTH = 240;
1035 const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
1036 // clang-format off
1037 std::vector<LineBreakExpectation> expect = {
1038 // TODO: Fix this. Prefer not to break inside URL.
1039 {"This is an url: http://a", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1040 {".b", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1041 };
1042 // clang-format on
1043 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1044 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1045 << " vs " << std::endl
1046 << toString(textBuf, actual);
1047 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1048 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1049 << " vs " << std::endl
1050 << toString(textBuf, actual);
1051 // clang-format off
1052 expect = {
1053 {"This is an url: ", 150, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1054 {"http://a.b", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1055 };
1056 // clang-format on
1057 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, 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, LINE_WIDTH);
1062 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1063 << " vs " << std::endl
1064 << toString(textBuf, actual);
1065 }
1066 {
1067 constexpr float LINE_WIDTH = 240;
1068 const auto textBuf = utf8ToUtf16("This is an email: a@example.com");
1069 // clang-format off
1070 std::vector<LineBreakExpectation> expect = {
1071 {"This is an email: ", 170, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1072 {"a@example.com" , 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1073 };
1074 // clang-format on
1075
1076 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1077 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1078 << " vs " << std::endl
1079 << toString(textBuf, actual);
1080 actual = doLineBreak(textBuf, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1081 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1082 << " vs " << std::endl
1083 << toString(textBuf, actual);
1084 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
1085 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1086 << " vs " << std::endl
1087 << toString(textBuf, actual);
1088 actual = doLineBreak(textBuf, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
1089 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1090 << " vs " << std::endl
1091 << toString(textBuf, actual);
1092 }
1093 }
1094
TEST_F(OptimalLineBreakerTest,testLocaleSwitch_InEmailOrUrl)1095 TEST_F(OptimalLineBreakerTest, testLocaleSwitch_InEmailOrUrl) {
1096 constexpr float CHAR_WIDTH = 10.0;
1097 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
1098 constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
1099 constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
1100 constexpr HyphenationFrequency NORMAL_HYPHENATION = HyphenationFrequency::Normal;
1101
1102 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1103 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1104
1105 constexpr float LINE_WIDTH = 240;
1106 {
1107 const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
1108 MeasuredTextBuilder builder;
1109 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1110 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
1111 DESCENT);
1112 std::unique_ptr<MeasuredText> measured =
1113 builder.build(textBuf, true /* compute hyphenation */,
1114 false /* compute full layout */, nullptr /* no hint */);
1115
1116 // clang-format off
1117 std::vector<LineBreakExpectation> expect = {
1118 // TODO: Fix this. Prefer not to break inside URL.
1119 {"This is an url: http://a", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1120 {".b", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1121 };
1122 // clang-format on
1123
1124 auto actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1125 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1126 << " vs " << std::endl
1127 << toString(textBuf, actual);
1128 actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1129 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1130 << " vs " << std::endl
1131 << toString(textBuf, actual);
1132
1133 // clang-format off
1134 expect = {
1135 {"This is an url: ", 150, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1136 {"http://a.b", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1137 };
1138 // clang-format on
1139
1140 actual = doLineBreak(textBuf, *measured, BALANCED, NO_HYPHENATION, LINE_WIDTH);
1141 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1142 << " vs " << std::endl
1143 << toString(textBuf, actual);
1144 actual = doLineBreak(textBuf, *measured, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
1145 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1146 << " vs " << std::endl
1147 << toString(textBuf, actual);
1148 }
1149 {
1150 const auto textBuf = utf8ToUtf16("This is an email: a@example.com");
1151 MeasuredTextBuilder builder;
1152 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1153 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
1154 DESCENT);
1155 std::unique_ptr<MeasuredText> measured =
1156 builder.build(textBuf, true /* compute hyphenation */,
1157 false /* compute full layout */, nullptr /* no hint */);
1158
1159 // clang-format off
1160 std::vector<LineBreakExpectation> expect = {
1161 {"This is an email: ", 170, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1162 {"a@example.com", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1163 };
1164 // clang-format on
1165
1166 auto actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1167 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1168 << " vs " << std::endl
1169 << toString(textBuf, actual);
1170 actual = doLineBreak(textBuf, *measured, HIGH_QUALITY, NORMAL_HYPHENATION, LINE_WIDTH);
1171 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1172 << " vs " << std::endl
1173 << toString(textBuf, actual);
1174 actual = doLineBreak(textBuf, *measured, BALANCED, NO_HYPHENATION, LINE_WIDTH);
1175 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1176 << " vs " << std::endl
1177 << toString(textBuf, actual);
1178 actual = doLineBreak(textBuf, *measured, BALANCED, NORMAL_HYPHENATION, LINE_WIDTH);
1179 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1180 << " vs " << std::endl
1181 << toString(textBuf, actual);
1182 }
1183 }
1184
TEST_F(OptimalLineBreakerTest,ExtentTest)1185 TEST_F(OptimalLineBreakerTest, ExtentTest) {
1186 constexpr HyphenationFrequency NO_HYPHEN = HyphenationFrequency::None;
1187 const std::vector<uint16_t> textBuf = utf8ToUtf16("The \u3042\u3044\u3046 is Japanese.");
1188
1189 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
1190 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1191 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1192 {
1193 constexpr float LINE_WIDTH = 1000;
1194 std::vector<LineBreakExpectation> expect = {
1195 {"The \u3042\u3044\u3046 is Japanese.", 200, NO_START_HYPHEN, NO_END_HYPHEN,
1196 CUSTOM_ASCENT, CUSTOM_DESCENT},
1197 };
1198
1199 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1200 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1201 << " vs " << std::endl
1202 << toString(textBuf, actual);
1203 }
1204 {
1205 constexpr float LINE_WIDTH = 200;
1206 std::vector<LineBreakExpectation> expect = {
1207 {"The \u3042\u3044\u3046 is Japanese.", 200, NO_START_HYPHEN, NO_END_HYPHEN,
1208 CUSTOM_ASCENT, CUSTOM_DESCENT},
1209 };
1210
1211 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1212 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1213 << " vs " << std::endl
1214 << toString(textBuf, actual);
1215 }
1216 {
1217 constexpr float LINE_WIDTH = 190;
1218 std::vector<LineBreakExpectation> expect = {
1219 {"The \u3042\u3044\u3046 is ", 100, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1220 CUSTOM_DESCENT},
1221 {"Japanese.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1222 };
1223 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1224 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1225 << " vs " << std::endl
1226 << toString(textBuf, actual);
1227 }
1228 {
1229 constexpr float LINE_WIDTH = 90;
1230 std::vector<LineBreakExpectation> expect = {
1231 {"The \u3042", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1232 {"\u3044\u3046 is ", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1233 CUSTOM_DESCENT},
1234 {"Japanese.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1235 };
1236 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1237 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1238 << " vs " << std::endl
1239 << toString(textBuf, actual);
1240 }
1241 {
1242 constexpr float LINE_WIDTH = 50;
1243 std::vector<LineBreakExpectation> expect = {
1244 {"The \u3042", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1245 {"\u3044\u3046 is ", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1246 CUSTOM_DESCENT},
1247 {"Japan", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1248 {"ese.", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1249 };
1250 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1251 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1252 << " vs " << std::endl
1253 << toString(textBuf, actual);
1254 }
1255 {
1256 constexpr float LINE_WIDTH = 40;
1257 std::vector<LineBreakExpectation> expect = {
1258 {"The ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1259 {"\u3042\u3044", 20, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1260 {"\u3046 is ", 40, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1261 {"Japa", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1262 {"nese", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1263 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1264 };
1265 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1266 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1267 << " vs " << std::endl
1268 << toString(textBuf, actual);
1269 }
1270 {
1271 constexpr float LINE_WIDTH = 20;
1272 std::vector<LineBreakExpectation> expect = {
1273 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1274 {"he ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1275 {"\u3042", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1276 {"\u3044\u3046 ", 20, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1277 CUSTOM_DESCENT},
1278 {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1279 {"Ja", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1280 {"pa", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1281 {"ne", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1282 {"se", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1283 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1284 };
1285 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1286 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1287 << " vs " << std::endl
1288 << toString(textBuf, actual);
1289 }
1290 {
1291 constexpr float LINE_WIDTH = 10;
1292 std::vector<LineBreakExpectation> expect = {
1293 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1294 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1295 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1296 {"\u3042", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1297 {"\u3044", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1298 {"\u3046 ", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1299 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1300 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1301 {"J", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1302 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1303 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1304 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1305 {"n", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1306 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1307 {"s", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1308 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1309 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1310 };
1311 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHEN, LINE_WIDTH);
1312 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1313 << " vs " << std::endl
1314 << toString(textBuf, actual);
1315 }
1316 }
1317
TEST_F(OptimalLineBreakerTest,testReplacementSpanNotBreakTest_SingleChar)1318 TEST_F(OptimalLineBreakerTest, testReplacementSpanNotBreakTest_SingleChar) {
1319 constexpr float CHAR_WIDTH = 10.0;
1320
1321 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1322 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1323
1324 const auto textBuf = utf8ToUtf16("This is an example \u2639 text.");
1325
1326 // In this test case, assign a replacement run for "U+2639" with 5 times of CHAR_WIDTH.
1327 auto doLineBreak = [=](float width) {
1328 MeasuredTextBuilder builder;
1329 builder.addCustomRun<ConstantRun>(Range(0, 19), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1330 builder.addReplacementRun(19, 21, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1331 builder.addCustomRun<ConstantRun>(Range(21, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1332 DESCENT);
1333
1334 std::unique_ptr<MeasuredText> measuredText =
1335 builder.build(textBuf, false /* compute hyphenation */,
1336 false /* compute full layout */, nullptr /* no hint */);
1337 RectangleLineWidth rectangleLineWidth(width);
1338 TabStops tabStops(nullptr, 0, 0);
1339 return breakLineOptimal(textBuf, *measuredText, rectangleLineWidth,
1340 BreakStrategy::HighQuality, HyphenationFrequency::None,
1341 false /* justified */);
1342 };
1343
1344 {
1345 constexpr float LINE_WIDTH = 100;
1346 // "is an" is a single replacement span. Do not break.
1347 // clang-format off
1348 std::vector<LineBreakExpectation> expect = {
1349 {"This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1350 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1351 {"\u2639 text.", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1352 };
1353 // clang-format on
1354 const auto actual = doLineBreak(LINE_WIDTH);
1355 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1356 << " vs " << std::endl
1357 << toString(textBuf, actual);
1358 }
1359 {
1360 constexpr float LINE_WIDTH = 90;
1361 // "is an" is a single replacement span. Do not break.
1362 // clang-format off
1363 std::vector<LineBreakExpectation> expect = {
1364 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1365 {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1366 {"example ",70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1367 {"\u2639 ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1368 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1369 };
1370 // clang-format on
1371 const auto actual = doLineBreak(LINE_WIDTH);
1372 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1373 << " vs " << std::endl
1374 << toString(textBuf, actual);
1375 }
1376 {
1377 constexpr float LINE_WIDTH = 10;
1378 // "is an" is a single replacement span. Do not break.
1379 // clang-format off
1380 std::vector<LineBreakExpectation> expect = {
1381 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1382 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1383 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1384 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1385 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1386 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1387 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1388 {"n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1389 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1390 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1391 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1392 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1393 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1394 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1395 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1396 {"\u2639 ",50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1397 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1398 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1399 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1400 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1401 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1402 };
1403 // clang-format on
1404 const auto actual = doLineBreak(LINE_WIDTH);
1405 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1406 << " vs " << std::endl
1407 << toString(textBuf, actual);
1408 }
1409 }
1410
TEST_F(OptimalLineBreakerTest,testReplacementSpanNotBreakTest_MultipleChars)1411 TEST_F(OptimalLineBreakerTest, testReplacementSpanNotBreakTest_MultipleChars) {
1412 constexpr float CHAR_WIDTH = 10.0;
1413
1414 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1415 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1416
1417 const auto textBuf = utf8ToUtf16("This is an example text.");
1418
1419 // In this test case, assign a replacement run for "is an " with 5 times of CHAR_WIDTH.
1420 auto doLineBreak = [=](float width) {
1421 MeasuredTextBuilder builder;
1422 builder.addCustomRun<ConstantRun>(Range(0, 5), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1423 builder.addReplacementRun(5, 11, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1424 builder.addCustomRun<ConstantRun>(Range(11, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1425 DESCENT);
1426
1427 std::unique_ptr<MeasuredText> measuredText =
1428 builder.build(textBuf, false /* compute hyphenation */,
1429 false /* compute full layout */, nullptr /* no hint */);
1430 RectangleLineWidth rectangleLineWidth(width);
1431 TabStops tabStops(nullptr, 0, 0);
1432 return breakLineOptimal(textBuf, *measuredText, rectangleLineWidth,
1433 BreakStrategy::HighQuality, HyphenationFrequency::None,
1434 false /* justified */);
1435 };
1436
1437 {
1438 constexpr float LINE_WIDTH = 100;
1439 // "is an" is a single replacement span. Do not break.
1440 // clang-format off
1441 std::vector<LineBreakExpectation> expect = {
1442 {"This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1443 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1444 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1445 };
1446 // clang-format on
1447 const auto actual = doLineBreak(LINE_WIDTH);
1448 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1449 << " vs " << std::endl
1450 << toString(textBuf, actual);
1451 }
1452 {
1453 constexpr float LINE_WIDTH = 90;
1454 // "is an" is a single replacement span. Do not break.
1455 // clang-format off
1456 std::vector<LineBreakExpectation> expect = {
1457 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1458 {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1459 {"example ",70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1460 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1461 };
1462 // clang-format on
1463 const auto actual = doLineBreak(LINE_WIDTH);
1464 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1465 << " vs " << std::endl
1466 << toString(textBuf, actual);
1467 }
1468 {
1469 constexpr float LINE_WIDTH = 10;
1470 // "is an" is a single replacement span. Do not break.
1471 // clang-format off
1472 std::vector<LineBreakExpectation> expect = {
1473 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1474 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1475 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1476 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1477 {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1478 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1479 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1480 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1481 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1482 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1483 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1484 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1485 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1486 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1487 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1488 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1489 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1490 };
1491 // clang-format on
1492 const auto actual = doLineBreak(LINE_WIDTH);
1493 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1494 << " vs " << std::endl
1495 << toString(textBuf, actual);
1496 }
1497 }
1498
TEST_F(OptimalLineBreakerTest,testReplacementSpanNotBreakTest_CJK)1499 TEST_F(OptimalLineBreakerTest, testReplacementSpanNotBreakTest_CJK) {
1500 constexpr float CHAR_WIDTH = 10.0;
1501
1502 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1503 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1504
1505 // Example string: "Today is a sunny day." in Japanese.
1506 const auto textBuf = utf8ToUtf16("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A");
1507
1508 // In this test case, assign a replacement run for "\u6674\u5929" with 5 times of CHAR_WIDTH.
1509 auto doLineBreak = [=](float width) {
1510 MeasuredTextBuilder builder;
1511 builder.addCustomRun<ConstantRun>(Range(0, 3), "ja-JP", CHAR_WIDTH, ASCENT, DESCENT);
1512 builder.addReplacementRun(3, 5, 5 * CHAR_WIDTH, LocaleListCache::getId("ja-JP"));
1513 builder.addCustomRun<ConstantRun>(Range(5, textBuf.size()), "ja-JP", CHAR_WIDTH, ASCENT,
1514 DESCENT);
1515
1516 std::unique_ptr<MeasuredText> measuredText =
1517 builder.build(textBuf, false /* compute hyphenation */,
1518 false /* compute full layout */, nullptr /* no hint */);
1519 RectangleLineWidth rectangleLineWidth(width);
1520 TabStops tabStops(nullptr, 0, 0);
1521 return breakLineOptimal(textBuf, *measuredText, rectangleLineWidth,
1522 BreakStrategy::HighQuality, HyphenationFrequency::None,
1523 false /* justified */);
1524 };
1525
1526 {
1527 constexpr float LINE_WIDTH = 100;
1528 // "\u6674\u5929" is a single replacement span. Do not break.
1529 // clang-format off
1530 std::vector<LineBreakExpectation> expect = {
1531 {"\u672C\u65E5\u306F\u6674\u5929\u306A\u308A",
1532 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1533 };
1534 // clang-format on
1535 const auto actual = doLineBreak(LINE_WIDTH);
1536 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1537 << " vs " << std::endl
1538 << toString(textBuf, actual);
1539 }
1540 {
1541 constexpr float LINE_WIDTH = 90;
1542 // "\u6674\u5929" is a single replacement span. Do not break.
1543 // clang-format off
1544 std::vector<LineBreakExpectation> expect = {
1545 {"\u672C\u65E5\u306F\u6674\u5929\u306A",
1546 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1547 {"\u308A",
1548 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1549 };
1550 // clang-format on
1551 const auto actual = doLineBreak(LINE_WIDTH);
1552 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1553 << " vs " << std::endl
1554 << toString(textBuf, actual);
1555 }
1556 {
1557 constexpr float LINE_WIDTH = 80;
1558 // "\u6674\u5929" is a single replacement span. Do not break.
1559 // clang-format off
1560 std::vector<LineBreakExpectation> expect = {
1561 {"\u672C\u65E5\u306F\u6674\u5929",
1562 80, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1563 {"\u306A\u308A",
1564 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1565 };
1566 // clang-format on
1567 const auto actual = doLineBreak(LINE_WIDTH);
1568 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1569 << " vs " << std::endl
1570 << toString(textBuf, actual);
1571 }
1572 {
1573 constexpr float LINE_WIDTH = 70;
1574 // "\u6674\u5929" is a single replacement span. Do not break.
1575 // clang-format off
1576 std::vector<LineBreakExpectation> expect = {
1577 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1578 {"\u6674\u5929\u306A\u308A", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1579 };
1580 // clang-format on
1581 const auto actual = doLineBreak(LINE_WIDTH);
1582 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1583 << " vs " << std::endl
1584 << toString(textBuf, actual);
1585 }
1586 {
1587 constexpr float LINE_WIDTH = 60;
1588 // "\u6674\u5929" is a single replacement span. Do not break.
1589 // clang-format off
1590 std::vector<LineBreakExpectation> expect = {
1591 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1592 {"\u6674\u5929\u306A", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1593 {"\u308A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1594 };
1595 // clang-format on
1596 const auto actual = doLineBreak(LINE_WIDTH);
1597 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1598 << " vs " << std::endl
1599 << toString(textBuf, actual);
1600 }
1601 {
1602 constexpr float LINE_WIDTH = 50;
1603 // "\u6674\u5929" is a single replacement span. Do not break.
1604 // clang-format off
1605 std::vector<LineBreakExpectation> expect = {
1606 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1607 {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1608 {"\u306A\u308A", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1609 };
1610 // clang-format on
1611 const auto actual = doLineBreak(LINE_WIDTH);
1612 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1613 << " vs " << std::endl
1614 << toString(textBuf, actual);
1615 }
1616 {
1617 constexpr float LINE_WIDTH = 40;
1618 // "\u6674\u5929" is a single replacement span. Do not break.
1619 // clang-format off
1620 std::vector<LineBreakExpectation> expect = {
1621 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1622 {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1623 {"\u306A\u308A", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1624 };
1625 // clang-format on
1626 const auto actual = doLineBreak(LINE_WIDTH);
1627 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1628 << " vs " << std::endl
1629 << toString(textBuf, actual);
1630 }
1631 {
1632 constexpr float LINE_WIDTH = 10;
1633 // "\u6674\u5929" is a single replacement span. Do not break.
1634 // clang-format off
1635 std::vector<LineBreakExpectation> expect = {
1636 {"\u672C", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1637 {"\u65E5", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1638 {"\u306F", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1639 {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1640 {"\u306A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1641 {"\u308A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1642 };
1643 // clang-format on
1644 const auto actual = doLineBreak(LINE_WIDTH);
1645 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1646 << " vs " << std::endl
1647 << toString(textBuf, actual);
1648 }
1649 }
1650
1651 // http://b/119657685
1652 // Following test case is for verifying that the ReplacementSpan should not be broken into multiple
1653 // pieces. The actual break point is not a part of expectation. For example, it would be good to
1654 // break the starting offset of the ReplacementSpan for some case.
TEST_F(OptimalLineBreakerTest,testReplacementSpan_GraphemeLineBreakWithMultipleRepalcementSpans)1655 TEST_F(OptimalLineBreakerTest, testReplacementSpan_GraphemeLineBreakWithMultipleRepalcementSpans) {
1656 constexpr float CHAR_WIDTH = 10.0;
1657
1658 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1659 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1660
1661 const auto textBuf = utf8ToUtf16("ab de\u00A0\u00A0fg ij\u00A0\u00A0kl no\u00A0\u00A0pq st");
1662
1663 auto doLineBreak = [=](float width) {
1664 MeasuredTextBuilder builder;
1665 builder.addReplacementRun(0, 5, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1666 builder.addCustomRun<ConstantRun>(Range(5, 7), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1667 builder.addReplacementRun(7, 12, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1668 builder.addCustomRun<ConstantRun>(Range(12, 14), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1669 builder.addReplacementRun(14, 19, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1670 builder.addCustomRun<ConstantRun>(Range(19, 21), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1671 builder.addReplacementRun(21, 26, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1672
1673 std::unique_ptr<MeasuredText> measuredText =
1674 builder.build(textBuf, false /* compute hyphenation */,
1675 false /* compute full layout */, nullptr /* no hint */);
1676 RectangleLineWidth rectangleLineWidth(width);
1677 TabStops tabStops(nullptr, 0, 0);
1678 return breakLineOptimal(textBuf, *measuredText, rectangleLineWidth,
1679 BreakStrategy::HighQuality, HyphenationFrequency::None,
1680 false /* justified */);
1681 };
1682
1683 {
1684 constexpr float LINE_WIDTH = 1000;
1685 // clang-format off
1686 std::vector<LineBreakExpectation> expect = {
1687 {"ab de\u00A0\u00A0fg ij\u00A0\u00A0kl no\u00A0\u00A0pq st",
1688 260, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1689 };
1690 // clang-format on
1691 const auto actual = doLineBreak(LINE_WIDTH);
1692 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1693 << " vs " << std::endl
1694 << toString(textBuf, actual);
1695 }
1696 {
1697 constexpr float LINE_WIDTH = 250;
1698 // clang-format off
1699 std::vector<LineBreakExpectation> expect = {
1700 {"ab de\u00A0\u00A0fg ij\u00A0\u00A0kl no\u00A0\u00A0",
1701 210, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1702 {"pq st",
1703 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1704 };
1705 // clang-format on
1706 const auto actual = doLineBreak(LINE_WIDTH);
1707 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1708 << " vs " << std::endl
1709 << toString(textBuf, actual);
1710 }
1711 {
1712 constexpr float LINE_WIDTH = 180;
1713 // clang-format off
1714 std::vector<LineBreakExpectation> expect = {
1715 {"ab de\u00A0\u00A0fg ij\u00A0\u00A0",
1716 140, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1717 {"kl no\u00A0\u00A0pq st",
1718 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1719 };
1720 // clang-format on
1721 const auto actual = doLineBreak(LINE_WIDTH);
1722 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1723 << " vs " << std::endl
1724 << toString(textBuf, actual);
1725 }
1726 {
1727 constexpr float LINE_WIDTH = 130;
1728 // clang-format off
1729 std::vector<LineBreakExpectation> expect = {
1730 {"ab de\u00A0\u00A0fg ij\u00A0",
1731 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1732 {"\u00A0kl no\u00A0\u00A0pq st",
1733 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1734 };
1735 // clang-format on
1736 const auto actual = doLineBreak(LINE_WIDTH);
1737 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1738 << " vs " << std::endl
1739 << toString(textBuf, actual);
1740 }
1741 {
1742 constexpr float LINE_WIDTH = 110;
1743 // clang-format off
1744 std::vector<LineBreakExpectation> expect = {
1745 {"ab de\u00A0", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1746 {"\u00A0fg ij\u00A0\u00A0", 80, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1747 {"kl no\u00A0\u00A0", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1748 {"pq st", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1749 };
1750 // clang-format on
1751 const auto actual = doLineBreak(LINE_WIDTH);
1752 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1753 << " vs " << std::endl
1754 << toString(textBuf, actual);
1755 }
1756 {
1757 constexpr float LINE_WIDTH = 60;
1758 // clang-format off
1759 std::vector<LineBreakExpectation> expect = {
1760 {"ab de\u00A0", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1761 {"\u00A0fg ij", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1762 {"\u00A0\u00A0", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1763 {"kl no\u00A0", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1764 {"\u00A0pq st", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1765 };
1766 // clang-format on
1767 const auto actual = doLineBreak(LINE_WIDTH);
1768 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1769 << " vs " << std::endl
1770 << toString(textBuf, actual);
1771 }
1772 {
1773 constexpr float LINE_WIDTH = 50;
1774 // clang-format off
1775 std::vector<LineBreakExpectation> expect = {
1776 {"ab de", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1777 {"\u00A0\u00A0", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1778 {"fg ij", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1779 {"\u00A0\u00A0", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1780 {"kl no", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1781 {"\u00A0\u00A0", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1782 {"pq st", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1783 };
1784 // clang-format on
1785 const auto actual = doLineBreak(LINE_WIDTH);
1786 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1787 << " vs " << std::endl
1788 << toString(textBuf, actual);
1789 }
1790 }
1791
TEST_F(OptimalLineBreakerTest,testReplacementSpanNotBreakTest_with_punctuation)1792 TEST_F(OptimalLineBreakerTest, testReplacementSpanNotBreakTest_with_punctuation) {
1793 constexpr float CHAR_WIDTH = 10.0;
1794
1795 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1796 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1797
1798 const auto textBuf = utf8ToUtf16("This (is an) example text.");
1799
1800 // In this test case, assign a replacement run for "U+2639" with 5 times of CHAR_WIDTH.
1801 auto doLineBreak = [=](float width) {
1802 MeasuredTextBuilder builder;
1803 builder.addCustomRun<ConstantRun>(Range(0, 6), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1804 builder.addReplacementRun(6, 11, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1805 builder.addCustomRun<ConstantRun>(Range(11, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1806 DESCENT);
1807
1808 std::unique_ptr<MeasuredText> measuredText =
1809 builder.build(textBuf, false /* compute hyphenation */,
1810 false /* compute full layout */, nullptr /* no hint */);
1811 RectangleLineWidth rectangleLineWidth(width);
1812 TabStops tabStops(nullptr, 0, 0);
1813 return breakLineOptimal(textBuf, *measuredText, rectangleLineWidth,
1814 BreakStrategy::HighQuality, HyphenationFrequency::Normal,
1815 false /* justified */);
1816 };
1817
1818 {
1819 constexpr float LINE_WIDTH = 1000;
1820 // "is an" is a single replacement span. Do not break.
1821 // clang-format off
1822 std::vector<LineBreakExpectation> expect = {
1823 {"This (is an) example text.",
1824 260, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1825 };
1826 // clang-format on
1827 const auto actual = doLineBreak(LINE_WIDTH);
1828 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1829 << " vs " << std::endl
1830 << toString(textBuf, actual);
1831 }
1832 {
1833 constexpr float LINE_WIDTH = 250;
1834 // "is an" is a single replacement span. Do not break.
1835 // clang-format off
1836 std::vector<LineBreakExpectation> expect = {
1837 {"This (is an) example ", 200, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1838 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1839 };
1840 // clang-format on
1841 const auto actual = doLineBreak(LINE_WIDTH);
1842 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1843 << " vs " << std::endl
1844 << toString(textBuf, actual);
1845 }
1846 {
1847 constexpr float LINE_WIDTH = 190;
1848 // "is an" is a single replacement span. Do not break.
1849 // clang-format off
1850 std::vector<LineBreakExpectation> expect = {
1851 {"This (is an) ", 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1852 {"example text.", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1853 };
1854 // clang-format on
1855 const auto actual = doLineBreak(LINE_WIDTH);
1856 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1857 << " vs " << std::endl
1858 << toString(textBuf, actual);
1859 }
1860 {
1861 constexpr float LINE_WIDTH = 120;
1862 // "is an" is a single replacement span. Do not break.
1863 // clang-format off
1864 std::vector<LineBreakExpectation> expect = {
1865 {"This (is an) ", 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1866 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1867 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1868 };
1869 // clang-format on
1870 const auto actual = doLineBreak(LINE_WIDTH);
1871 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1872 << " vs " << std::endl
1873 << toString(textBuf, actual);
1874 }
1875 {
1876 constexpr float LINE_WIDTH = 110;
1877 // "is an" is a single replacement span. Do not break.
1878 // clang-format off
1879 std::vector<LineBreakExpectation> expect = {
1880 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1881 {"(is an) ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1882 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1883 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1884 };
1885 // clang-format on
1886 const auto actual = doLineBreak(LINE_WIDTH);
1887 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1888 << " vs " << std::endl
1889 << toString(textBuf, actual);
1890 }
1891 {
1892 constexpr float LINE_WIDTH = 60;
1893 // "is an" is a single replacement span. Do not break.
1894 // clang-format off
1895 std::vector<LineBreakExpectation> expect = {
1896 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1897 {"(is an", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1898 {") ex", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1899 {"ample ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1900 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1901 };
1902 // clang-format on
1903 const auto actual = doLineBreak(LINE_WIDTH);
1904 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1905 << " vs " << std::endl
1906 << toString(textBuf, actual);
1907 }
1908 {
1909 constexpr float LINE_WIDTH = 50;
1910 // "is an" is a single replacement span. Do not break.
1911 // clang-format off
1912 std::vector<LineBreakExpectation> expect = {
1913 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1914 {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1915 {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1916 {") ex", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1917 {"ample ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1918 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1919 };
1920 // clang-format on
1921 const auto actual = doLineBreak(LINE_WIDTH);
1922 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1923 << " vs " << std::endl
1924 << toString(textBuf, actual);
1925 }
1926 {
1927 constexpr float LINE_WIDTH = 40;
1928 // "is an" is a single replacement span. Do not break.
1929 // clang-format off
1930 std::vector<LineBreakExpectation> expect = {
1931 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1932 // TODO(nona): This might be wrongly broken. "(is an" should be broken into "(" and
1933 // "is an" as the desperate break.
1934 {"(is an", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1935 {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1936 {"exa", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1937 {"mple ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1938 {"text", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1939 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1940 };
1941 // clang-format on
1942 const auto actual = doLineBreak(LINE_WIDTH);
1943 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1944 << " vs " << std::endl
1945 << toString(textBuf, actual);
1946 }
1947 {
1948 constexpr float LINE_WIDTH = 10;
1949 // "is an" is a single replacement span. Do not break.
1950 // clang-format off
1951 std::vector<LineBreakExpectation> expect = {
1952 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1953 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1954 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1955 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1956 // TODO(nona): This might be wrongly broken. "(is an" should be broken into "(" and
1957 // "is an" as the desperate break.
1958 {"(is an", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1959 {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1960 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1961 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1962 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1963 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1964 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1965 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1966 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1967 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1968 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1969 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1970 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1971 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1972 };
1973 // clang-format on
1974 const auto actual = doLineBreak(LINE_WIDTH);
1975 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1976 << " vs " << std::endl
1977 << toString(textBuf, actual);
1978 }
1979 }
1980
TEST_F(OptimalLineBreakerTest,testControllCharAfterSpace)1981 TEST_F(OptimalLineBreakerTest, testControllCharAfterSpace) {
1982 constexpr BreakStrategy HIGH_QUALITY = BreakStrategy::HighQuality;
1983 constexpr BreakStrategy BALANCED = BreakStrategy::Balanced;
1984 constexpr HyphenationFrequency NO_HYPHENATION = HyphenationFrequency::None;
1985 const std::vector<uint16_t> textBuf = utf8ToUtf16("example \u2066example");
1986
1987 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1988 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1989 {
1990 constexpr float LINE_WIDTH = 90;
1991 // Note that HarfBuzz assigns 0px for control characters regardless of glyph existence in
1992 // the font.
1993 std::vector<LineBreakExpectation> expect = {
1994 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1995 {"\u2066example", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1996 };
1997
1998 auto actual = doLineBreak(textBuf, HIGH_QUALITY, NO_HYPHENATION, LINE_WIDTH);
1999 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2000 << " vs " << std::endl
2001 << toString(textBuf, actual);
2002 actual = doLineBreak(textBuf, BALANCED, NO_HYPHENATION, LINE_WIDTH);
2003 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2004 << " vs " << std::endl
2005 << toString(textBuf, actual);
2006 }
2007 }
2008 } // namespace
2009 } // namespace minikin
2010