1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <com_android_text_flags.h>
18 #include <flag_macros.h>
19 #include <gtest/gtest.h>
20
21 #include <memory>
22
23 #include "FileUtils.h"
24 #include "FontTestUtils.h"
25 #include "GreedyLineBreaker.h"
26 #include "HyphenatorMap.h"
27 #include "LineBreakerTestHelper.h"
28 #include "LocaleListCache.h"
29 #include "MinikinInternal.h"
30 #include "UnicodeUtils.h"
31 #include "WordBreaker.h"
32 #include "minikin/Hyphenator.h"
33
34 namespace minikin {
35 namespace {
36
37 using line_breaker_test_helper::ConstantRun;
38 using line_breaker_test_helper::LineBreakExpectation;
39 using line_breaker_test_helper::RectangleLineWidth;
40 using line_breaker_test_helper::sameLineBreak;
41 using line_breaker_test_helper::toString;
42
43 // The ascent/descent of Ascii.ttf with text size = 10.
44 constexpr float ASCENT = -80.0f;
45 constexpr float DESCENT = 20.0f;
46
47 // The ascent/descent of CustomExtent.ttf with text size = 10.
48 constexpr float CUSTOM_ASCENT = -160.0f;
49 constexpr float CUSTOM_DESCENT = 40.0f;
50
51 // A test string for Japanese. The meaning is that "Today is a sunny day."
52 // The expected line break of phrase and non-phrase cases are:
53 // Phrase: | \u672C\u65E5\u306F | \u6674\u5929\u306A\u308A\u3002 |
54 // Non-Phrase: | \u672C | \u65E5 | \u306F | \u6674 | \u5929 | \u306A | \u308A\u3002 |
55 const char* JP_TEXT = "\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002";
56
57 // A test string for Korean. The meaning is that "I want to eat breakfast."
58 // The phrase based line break breaks at spaces, non-phrase based line break breaks at grapheme.
59 const char* KO_TEXT =
60 "\uC544\uCE68\uBC25\uC744\u0020\uBA39\uACE0\u0020\uC2F6\uC2B5\uB2C8\uB2E4\u002E";
61
62 class GreedyLineBreakerTest : public testing::Test {
63 public:
GreedyLineBreakerTest()64 GreedyLineBreakerTest() {}
65
~GreedyLineBreakerTest()66 virtual ~GreedyLineBreakerTest() {}
67
SetUp()68 virtual void SetUp() override {
69 mHyphenationPattern = readWholeFile("/system/usr/hyphen-data/hyph-en-us.hyb");
70 Hyphenator* hyphenator =
71 Hyphenator::loadBinary(mHyphenationPattern.data(), mHyphenationPattern.size(),
72 2 /* min prefix */, 2 /* min suffix */, "en-US");
73 HyphenatorMap::add("en-US", hyphenator);
74 HyphenatorMap::add("pl", Hyphenator::loadBinary(nullptr, 0, 0, 0, "pl"));
75 }
76
TearDown()77 virtual void TearDown() override { HyphenatorMap::clear(); }
78
79 protected:
doLineBreak(const U16StringPiece & textBuffer,bool doHyphenation,float lineWidth)80 LineBreakResult doLineBreak(const U16StringPiece& textBuffer, bool doHyphenation,
81 float lineWidth) {
82 return doLineBreak(textBuffer, doHyphenation, "en-US", lineWidth);
83 }
84
doLineBreakForJapanese(const U16StringPiece & textBuffer,LineBreakWordStyle lbwStyle,const std::string & lang,float lineWidth)85 LineBreakResult doLineBreakForJapanese(const U16StringPiece& textBuffer,
86 LineBreakWordStyle lbwStyle, const std::string& lang,
87 float lineWidth) {
88 MeasuredTextBuilder builder;
89 auto family = buildFontFamily("Japanese.ttf");
90 std::vector<std::shared_ptr<FontFamily>> families = {family};
91 auto fc = FontCollection::create(families);
92 MinikinPaint paint(fc);
93 paint.size = 10.0f; // Make 1em=10px
94 paint.localeListId = LocaleListCache::getId(lang);
95 builder.addStyleRun(0, textBuffer.size(), std::move(paint), (int)LineBreakStyle::None,
96 (int)lbwStyle, true, false);
97 std::unique_ptr<MeasuredText> measuredText = builder.build(
98 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
99 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
100 RectangleLineWidth rectangleLineWidth(lineWidth);
101 TabStops tabStops(nullptr, 0, 10);
102 return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops, false,
103 false);
104 }
105
doLineBreakForKorean(const U16StringPiece & textBuffer,LineBreakWordStyle lbwStyle,const std::string & lang,float lineWidth)106 LineBreakResult doLineBreakForKorean(const U16StringPiece& textBuffer,
107 LineBreakWordStyle lbwStyle, const std::string& lang,
108 float lineWidth) {
109 MeasuredTextBuilder builder;
110 auto family = buildFontFamily("Hangul.ttf");
111 std::vector<std::shared_ptr<FontFamily>> families = {family};
112 auto fc = FontCollection::create(families);
113 MinikinPaint paint(fc);
114 paint.size = 10.0f; // Make 1em=10px
115 paint.localeListId = LocaleListCache::getId(lang);
116 builder.addStyleRun(0, textBuffer.size(), std::move(paint), (int)LineBreakStyle::None,
117 (int)lbwStyle, true, false);
118 std::unique_ptr<MeasuredText> measuredText = builder.build(
119 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
120 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
121 RectangleLineWidth rectangleLineWidth(lineWidth);
122 TabStops tabStops(nullptr, 0, 10);
123 return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops, false,
124 false);
125 }
126
doLineBreak(const U16StringPiece & textBuffer,bool doHyphenation,const std::string & lang,float lineWidth)127 LineBreakResult doLineBreak(const U16StringPiece& textBuffer, bool doHyphenation,
128 const std::string& lang, float lineWidth) {
129 MeasuredTextBuilder builder;
130 auto family1 = buildFontFamily("Ascii.ttf");
131 auto family2 = buildFontFamily("CustomExtent.ttf");
132 std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
133 auto fc = FontCollection::create(families);
134 MinikinPaint paint(fc);
135 paint.size = 10.0f; // Make 1em=10px
136 paint.localeListId = LocaleListCache::getId(lang);
137 builder.addStyleRun(0, textBuffer.size(), std::move(paint), (int)LineBreakStyle::None,
138 (int)LineBreakWordStyle::None, true, false);
139 std::unique_ptr<MeasuredText> measuredText = builder.build(
140 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
141 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
142 RectangleLineWidth rectangleLineWidth(lineWidth);
143 TabStops tabStops(nullptr, 0, 10);
144 return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
145 doHyphenation, false);
146 }
147
doLineBreakWithNoHyphenSpan(const U16StringPiece & textBuffer,const Range & noHyphenRange,float lineWidth)148 LineBreakResult doLineBreakWithNoHyphenSpan(const U16StringPiece& textBuffer,
149 const Range& noHyphenRange, float lineWidth) {
150 MeasuredTextBuilder builder;
151 auto family1 = buildFontFamily("Ascii.ttf");
152 auto family2 = buildFontFamily("CustomExtent.ttf");
153 std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
154 auto fc = FontCollection::create(families);
155 if (noHyphenRange.getStart() != 0) {
156 MinikinPaint paint(fc);
157 paint.size = 10.0f; // Make 1em=10px
158 paint.localeListId = LocaleListCache::getId("en-US");
159 builder.addStyleRun(0, noHyphenRange.getStart(), std::move(paint),
160 (int)LineBreakStyle::None, (int)LineBreakWordStyle::None,
161 true /* hyphenation */, false);
162 }
163 MinikinPaint paint(fc);
164 paint.size = 10.0f; // Make 1em=10px
165 paint.localeListId = LocaleListCache::getId("en-US");
166 builder.addStyleRun(noHyphenRange.getStart(), noHyphenRange.getEnd(), std::move(paint),
167 (int)LineBreakStyle::None, (int)LineBreakWordStyle::None,
168 false /* hyphenation */, false);
169 if (noHyphenRange.getEnd() != textBuffer.size()) {
170 MinikinPaint paint(fc);
171 paint.size = 10.0f; // Make 1em=10px
172 paint.localeListId = LocaleListCache::getId("en-US");
173 builder.addStyleRun(noHyphenRange.getEnd(), textBuffer.size(), std::move(paint),
174 (int)LineBreakStyle::None, (int)LineBreakWordStyle::None,
175 true /* hyphenation */, false);
176 }
177
178 std::unique_ptr<MeasuredText> measuredText = builder.build(
179 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
180 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
181 RectangleLineWidth rectangleLineWidth(lineWidth);
182 TabStops tabStops(nullptr, 0, 10);
183 return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
184 true /* doHyphenation */, false);
185 }
186
doLineBreakForBounds(const U16StringPiece & textBuffer,bool doHyphenation,float lineWidth)187 LineBreakResult doLineBreakForBounds(const U16StringPiece& textBuffer, bool doHyphenation,
188 float lineWidth) {
189 MeasuredTextBuilder builder;
190 auto family1 = buildFontFamily("OvershootTest.ttf");
191 auto family2 = buildFontFamily("Ascii.ttf");
192 std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
193 auto fc = FontCollection::create(families);
194 MinikinPaint paint(fc);
195 paint.size = 10.0f; // Make 1em=10px
196 paint.localeListId = LocaleListCache::getId("en-US");
197 builder.addStyleRun(0, textBuffer.size(), std::move(paint), (int)LineBreakStyle::None,
198 (int)LineBreakWordStyle::None, true, false);
199 std::unique_ptr<MeasuredText> measuredText = builder.build(
200 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
201 true /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
202 RectangleLineWidth rectangleLineWidth(lineWidth);
203 TabStops tabStops(nullptr, 0, 10);
204 return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
205 doHyphenation, true);
206 }
207
doLineBreakForLetterSpacing(const U16StringPiece & textBuffer,float letterSpacing,float lineWidth)208 LineBreakResult doLineBreakForLetterSpacing(const U16StringPiece& textBuffer,
209 float letterSpacing, float lineWidth) {
210 MeasuredTextBuilder builder;
211 auto family1 = buildFontFamily("Ascii.ttf");
212 auto family2 = buildFontFamily("CustomExtent.ttf");
213 std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
214 auto fc = FontCollection::create(families);
215 MinikinPaint paint(fc);
216 paint.size = 10.0f; // Make 1em=10px
217 paint.letterSpacing = letterSpacing;
218 paint.scaleX = 1.0f;
219 paint.localeListId = LocaleListCache::getId("en-US");
220 builder.addStyleRun(0, textBuffer.size(), std::move(paint), (int)LineBreakStyle::None,
221 (int)LineBreakWordStyle::None, true, false);
222 std::unique_ptr<MeasuredText> measuredText = builder.build(
223 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
224 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
225 RectangleLineWidth rectangleLineWidth(lineWidth);
226 TabStops tabStops(nullptr, 0, 10);
227 return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
228 false /* hyphenation */, false);
229 }
230
231 private:
232 std::vector<uint8_t> mHyphenationPattern;
233 };
234
TEST_F(GreedyLineBreakerTest,roundingError)235 TEST_F(GreedyLineBreakerTest, roundingError) {
236 MeasuredTextBuilder builder;
237 auto family1 = buildFontFamily("Ascii.ttf");
238 std::vector<std::shared_ptr<FontFamily>> families = {family1};
239 auto fc = FontCollection::create(families);
240 MinikinPaint paint(fc);
241 paint.size = 56.0f; // Make 1em=56px
242 paint.scaleX = 1;
243 paint.letterSpacing = -0.093f;
244 paint.localeListId = LocaleListCache::getId("en-US");
245 const std::vector<uint16_t> textBuffer = utf8ToUtf16("8888888888888888888");
246
247 float measured = Layout::measureText(textBuffer, Range(0, textBuffer.size()), Bidi::LTR, paint,
248 StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, nullptr,
249 nullptr, nullptr, RunFlag::WHOLE_LINE);
250
251 builder.addStyleRun(0, textBuffer.size(), std::move(paint), (int)LineBreakStyle::None,
252 (int)LineBreakWordStyle::None, true, false);
253 std::unique_ptr<MeasuredText> measuredText = builder.build(
254 textBuffer, false /* compute hyphenation */, false /* compute full layout */,
255 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
256 RectangleLineWidth rectangleLineWidth(measured);
257 TabStops tabStops(nullptr, 0, 10);
258 LineBreakResult r = breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
259 false /* do hyphenation */, false /* useBoundsForWidth */);
260
261 EXPECT_EQ(1u, r.breakPoints.size());
262 }
263
TEST_F(GreedyLineBreakerTest,testBreakWithoutHyphenation)264 TEST_F(GreedyLineBreakerTest, testBreakWithoutHyphenation) {
265 constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
266 const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
267
268 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
269 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
270 // Note that disable clang-format everywhere since aligned expectation is more readable.
271 {
272 constexpr float LINE_WIDTH = 1000;
273 std::vector<LineBreakExpectation> expect = {
274 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
275 };
276
277 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
278 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
279 << " vs " << std::endl
280 << toString(textBuf, actual);
281 }
282 {
283 constexpr float LINE_WIDTH = 240;
284 std::vector<LineBreakExpectation> expect = {
285 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
286 };
287
288 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
289 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
290 << " vs " << std::endl
291 << toString(textBuf, actual);
292 }
293 {
294 constexpr float LINE_WIDTH = 230;
295 // clang-format off
296 std::vector<LineBreakExpectation> expect = {
297 { "This is an example ", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
298 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
299 };
300 // clang-format on
301
302 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
303 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
304 << " vs " << std::endl
305 << toString(textBuf, actual);
306 }
307 {
308 constexpr float LINE_WIDTH = 80;
309 // clang-format off
310 std::vector<LineBreakExpectation> expect = {
311 { "This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
312 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
313 { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
314 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
315 };
316 // clang-format on
317
318 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
319 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
320 << " vs " << std::endl
321 << toString(textBuf, actual);
322 }
323 {
324 constexpr float LINE_WIDTH = 70;
325 // clang-format off
326 std::vector<LineBreakExpectation> expect = {
327 { "This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
328 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
329 { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
330 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
331 };
332 // clang-format on
333
334 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
335 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
336 << " vs " << std::endl
337 << toString(textBuf, actual);
338 }
339 {
340 constexpr float LINE_WIDTH = 60;
341 // clang-format off
342 std::vector<LineBreakExpectation> expect = {
343 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
344 { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
345 { "exampl", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
346 { "e " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
347 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
348 };
349 // clang-format on
350
351 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
352 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
353 << " vs " << std::endl
354 << toString(textBuf, actual);
355 }
356 {
357 constexpr float LINE_WIDTH = 50;
358 // clang-format off
359 std::vector<LineBreakExpectation> expect = {
360 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
361 { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
362 { "examp" , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
363 { "le " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
364 { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
365 };
366 // clang-format on
367
368 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
369 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
370 << " vs " << std::endl
371 << toString(textBuf, actual);
372 }
373 {
374 constexpr float LINE_WIDTH = 40;
375 // clang-format off
376 std::vector<LineBreakExpectation> expect = {
377 { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
378 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
379 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
380 { "exam" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
381 { "ple " , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
382 { "text" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
383 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
384 };
385 // clang-format on
386
387 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
388 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
389 << " vs " << std::endl
390 << toString(textBuf, actual);
391 }
392 {
393 constexpr float LINE_WIDTH = 30;
394 // clang-format off
395 std::vector<LineBreakExpectation> expect = {
396 { "Thi" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
397 { "s " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
398 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
399 { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
400 { "exa" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
401 { "mpl" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
402 { "e " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
403 { "tex" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
404 { "t." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
405 };
406 // clang-format on
407
408 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
409 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
410 << " vs " << std::endl
411 << toString(textBuf, actual);
412 }
413 {
414 constexpr float LINE_WIDTH = 20;
415 // clang-format off
416 std::vector<LineBreakExpectation> expect = {
417 { "Th" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
418 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
419 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
420 { "an ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
421 { "ex" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
422 { "am" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
423 { "pl" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
424 { "e " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
425 { "te" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
426 { "xt" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
427 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
428 };
429 // clang-format on
430
431 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
432 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
433 << " vs " << std::endl
434 << toString(textBuf, actual);
435 }
436 {
437 constexpr float LINE_WIDTH = 10;
438 // clang-format off
439 std::vector<LineBreakExpectation> expect = {
440 { "T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
441 { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
442 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
443 { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
444 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
445 { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
446 { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
447 { "n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
448 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
449 { "x" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
450 { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
451 { "m" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
452 { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
453 { "l" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
454 { "e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
455 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
456 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
457 { "x" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
458 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
459 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
460 };
461 // clang-format on
462
463 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
464 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
465 << " vs " << std::endl
466 << toString(textBuf, actual);
467 }
468 }
469
TEST_F(GreedyLineBreakerTest,testBreakWithHyphenation)470 TEST_F(GreedyLineBreakerTest, testBreakWithHyphenation) {
471 constexpr bool NO_HYPHEN = true; // Do hyphenation in this test case.
472 // "hyphenation" is hyphnated to "hy-phen-a-tion".
473 const std::vector<uint16_t> textBuf = utf8ToUtf16("Hyphenation is hyphenation.");
474
475 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
476 constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
477 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
478
479 // Note that disable clang-format everywhere since aligned expectation is more readable.
480 {
481 constexpr float LINE_WIDTH = 1000;
482 std::vector<LineBreakExpectation> expect = {
483 {"Hyphenation is hyphenation.", 270, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT,
484 DESCENT},
485 };
486
487 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
488 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
489 << " vs " << std::endl
490 << toString(textBuf, actual);
491 }
492 {
493 constexpr float LINE_WIDTH = 270;
494 std::vector<LineBreakExpectation> expect = {
495 {"Hyphenation is hyphenation.", 270, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT,
496 DESCENT},
497 };
498
499 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
500 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
501 << " vs " << std::endl
502 << toString(textBuf, actual);
503 }
504 {
505 constexpr float LINE_WIDTH = 260;
506 // clang-format off
507 std::vector<LineBreakExpectation> expect = {
508 { "Hyphenation is " , 140, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
509 { "hyphenation." , 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
510 };
511 // clang-format on
512
513 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
514 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
515 << " vs " << std::endl
516 << toString(textBuf, actual);
517 }
518 {
519 constexpr float LINE_WIDTH = 170;
520 // clang-format off
521 std::vector<LineBreakExpectation> expect = {
522 { "Hyphenation is " , 140, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
523 { "hyphenation." , 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
524 };
525 // clang-format on
526
527 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
528 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
529 << " vs " << std::endl
530 << toString(textBuf, actual);
531 }
532 {
533 constexpr float LINE_WIDTH = 120;
534 // clang-format off
535 std::vector<LineBreakExpectation> expect = {
536 { "Hyphenation " , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
537 { "is " , 20 , NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
538 { "hyphenation." , 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
539 };
540 // clang-format on
541
542 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
543 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
544 << " vs " << std::endl
545 << toString(textBuf, actual);
546 }
547 {
548 constexpr float LINE_WIDTH = 100;
549 // clang-format off
550 std::vector<LineBreakExpectation> expect = {
551 { "Hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
552 { "tion is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
553 { "hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
554 { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
555 };
556 // clang-format on
557
558 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
559 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
560 << " vs " << std::endl
561 << toString(textBuf, actual);
562 }
563 {
564 constexpr float LINE_WIDTH = 80;
565 // clang-format off
566 std::vector<LineBreakExpectation> expect = {
567 { "Hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
568 { "tion is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
569 { "hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
570 { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
571 };
572 // clang-format on
573
574 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
575 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
576 << " vs " << std::endl
577 << toString(textBuf, actual);
578 }
579 {
580 constexpr float LINE_WIDTH = 70;
581 // clang-format off
582 std::vector<LineBreakExpectation> expect = {
583 { "Hyphen-", 70, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
584 { "ation " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
585 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
586 { "hyphen-", 70, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
587 { "ation." , 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
588 };
589 // clang-format on
590
591 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
592 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
593 << " vs " << std::endl
594 << toString(textBuf, actual);
595 }
596 {
597 constexpr float LINE_WIDTH = 60;
598 // clang-format off
599 std::vector<LineBreakExpectation> expect = {
600 { "Hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
601 { "phena-", 60, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
602 { "tion " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
603 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
604 { "hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
605 { "phena-", 60, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
606 { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
607 };
608 // clang-format on
609
610 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
611 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
612 << " vs " << std::endl
613 << toString(textBuf, actual);
614 }
615 {
616 constexpr float LINE_WIDTH = 50;
617 // clang-format off
618 std::vector<LineBreakExpectation> expect = {
619 { "Hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
620 { "phen-" , 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
621 { "ation ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
622 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
623 { "hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
624 { "phen-" , 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
625 { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
626 { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
627 };
628 // clang-format on
629
630 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
631 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
632 << " vs " << std::endl
633 << toString(textBuf, actual);
634 }
635 {
636 constexpr float LINE_WIDTH = 40;
637 // clang-format off
638 std::vector<LineBreakExpectation> expect = {
639 { "Hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
640 { "phen" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
641 { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
642 { "tion ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
643 { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
644 { "hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
645 { "phen" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
646 { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
647 { "tion" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
648 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
649 };
650 // clang-format on
651
652 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
653 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
654 << " vs " << std::endl
655 << toString(textBuf, actual);
656 }
657 {
658 constexpr float LINE_WIDTH = 30;
659 // clang-format off
660 std::vector<LineBreakExpectation> expect = {
661 { "Hy-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
662 { "phe", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
663 { "na-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
664 { "tio", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
665 { "n " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
666 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
667 { "hy-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
668 { "phe", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
669 { "na-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
670 { "tio", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
671 { "n." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
672 };
673 // clang-format on
674
675 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
676 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
677 << " vs " << std::endl
678 << toString(textBuf, actual);
679 }
680 {
681 constexpr float LINE_WIDTH = 20;
682 // clang-format off
683 std::vector<LineBreakExpectation> expect = {
684 { "Hy" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
685 { "ph" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
686 { "en" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
687 { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
688 { "ti" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
689 { "on ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
690 { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
691 { "hy" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
692 { "ph" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
693 { "en" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
694 { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
695 { "ti" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
696 { "on" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
697 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
698 };
699 // clang-format on
700
701 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
702 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
703 << " vs " << std::endl
704 << toString(textBuf, actual);
705 }
706 {
707 constexpr float LINE_WIDTH = 10;
708 // clang-format off
709 std::vector<LineBreakExpectation> expect = {
710 { "H" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
711 { "y" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
712 { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
713 { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
714 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
715 { "n" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
716 { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
717 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
718 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
719 { "o" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
720 { "n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
721 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
722 { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
723 { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
724 { "y" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
725 { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
726 { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
727 { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
728 { "n" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
729 { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
730 { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
731 { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
732 { "o" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
733 { "n" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
734 { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
735 };
736 // clang-format on
737
738 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
739 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
740 << " vs " << std::endl
741 << toString(textBuf, actual);
742 }
743 }
744
TEST_F(GreedyLineBreakerTest,testHyphenationStartLineChange)745 TEST_F(GreedyLineBreakerTest, testHyphenationStartLineChange) {
746 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
747 // "hyphenation" is hyphnated to "hy-phen-a-tion".
748 const std::vector<uint16_t> textBuf = utf8ToUtf16("czerwono-niebieska");
749
750 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
751 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
752 constexpr StartHyphenEdit START_HYPHEN = StartHyphenEdit::INSERT_HYPHEN;
753
754 // Note that disable clang-format everywhere since aligned expectation is more readable.
755 {
756 constexpr float LINE_WIDTH = 1000;
757 std::vector<LineBreakExpectation> expect = {
758 {"czerwono-niebieska", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
759 };
760
761 const auto actual = doLineBreak(textBuf, DO_HYPHEN, "pl", LINE_WIDTH);
762 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
763 << " vs " << std::endl
764 << toString(textBuf, actual);
765 }
766 {
767 constexpr float LINE_WIDTH = 180;
768 std::vector<LineBreakExpectation> expect = {
769 {"czerwono-niebieska", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
770 };
771
772 const auto actual = doLineBreak(textBuf, DO_HYPHEN, "pl", LINE_WIDTH);
773 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
774 << " vs " << std::endl
775 << toString(textBuf, actual);
776 }
777 {
778 constexpr float LINE_WIDTH = 130;
779 // clang-format off
780 std::vector<LineBreakExpectation> expect = {
781 {"czerwono-" , 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
782 {"-niebieska", 100, START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
783 };
784 // clang-format on
785
786 const auto actual = doLineBreak(textBuf, DO_HYPHEN, "pl", LINE_WIDTH);
787 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
788 << " vs " << std::endl
789 << toString(textBuf, actual);
790 }
791 }
792
TEST_F(GreedyLineBreakerTest,testZeroWidthLine)793 TEST_F(GreedyLineBreakerTest, testZeroWidthLine) {
794 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
795 constexpr float LINE_WIDTH = 0;
796
797 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
798 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
799
800 {
801 const auto textBuf = utf8ToUtf16("");
802 std::vector<LineBreakExpectation> expect = {};
803 const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
804 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
805 << " vs " << std::endl
806 << toString(textBuf, actual);
807 }
808 {
809 const auto textBuf = utf8ToUtf16("A");
810 std::vector<LineBreakExpectation> expect = {
811 {"A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
812 };
813 const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
814 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
815 << " vs " << std::endl
816 << toString(textBuf, actual);
817 }
818 {
819 const auto textBuf = utf8ToUtf16("AB");
820 std::vector<LineBreakExpectation> expect = {
821 {"A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
822 {"B", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
823 };
824 const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
825 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
826 << " vs " << std::endl
827 << toString(textBuf, actual);
828 }
829 }
830
TEST_F(GreedyLineBreakerTest,testZeroWidthCharacter)831 TEST_F(GreedyLineBreakerTest, testZeroWidthCharacter) {
832 constexpr float CHAR_WIDTH = 0.0;
833 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
834
835 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
836 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
837 {
838 constexpr float LINE_WIDTH = 1.0;
839 const auto textBuf = utf8ToUtf16("This is an example text.");
840 std::vector<LineBreakExpectation> expect = {
841 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
842 };
843
844 MeasuredTextBuilder builder;
845 builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
846 DESCENT);
847 std::unique_ptr<MeasuredText> measuredText = builder.build(
848 textBuf, false /* compute hyphenation */, false /* compute full layout */,
849 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
850 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
851 TabStops tabStops(nullptr, 0, 10);
852 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
853 DO_HYPHEN, false /* useBoundsForWidth */);
854 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
855 << " vs " << std::endl
856 << toString(textBuf, actual);
857 }
858 {
859 constexpr float LINE_WIDTH = 0.0;
860 const auto textBuf = utf8ToUtf16("This is an example text.");
861 std::vector<LineBreakExpectation> expect = {
862 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
863 };
864 MeasuredTextBuilder builder;
865 builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
866 DESCENT);
867 std::unique_ptr<MeasuredText> measuredText = builder.build(
868 textBuf, false /* compute hyphenation */, false /* compute full layout */,
869 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
870 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
871 TabStops tabStops(nullptr, 0, 10);
872 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
873 DO_HYPHEN, false /* useBoundsForWidth */);
874 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
875 << " vs " << std::endl
876 << toString(textBuf, actual);
877 }
878 }
879
TEST_F(GreedyLineBreakerTest,testLocaleSwitchTest)880 TEST_F(GreedyLineBreakerTest, testLocaleSwitchTest) {
881 constexpr float CHAR_WIDTH = 10.0;
882 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
883
884 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
885 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
886
887 constexpr float LINE_WIDTH = 240;
888 const auto textBuf = utf8ToUtf16("This is an example text.");
889 {
890 std::vector<LineBreakExpectation> expect = {
891 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
892 };
893
894 MeasuredTextBuilder builder;
895 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
896 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
897 DESCENT);
898 std::unique_ptr<MeasuredText> measuredText = builder.build(
899 textBuf, false /* compute hyphenation */, false /* compute full layout */,
900 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
901 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
902 TabStops tabStops(nullptr, 0, 0);
903
904 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
905 DO_HYPHEN, false /* useBoundsForWidth */);
906 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
907 << " vs " << std::endl
908 << toString(textBuf, actual);
909 }
910 {
911 std::vector<LineBreakExpectation> expect = {
912 {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
913 };
914
915 MeasuredTextBuilder builder;
916 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
917 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
918 DESCENT);
919 std::unique_ptr<MeasuredText> measuredText = builder.build(
920 textBuf, false /* compute hyphenation */, false /* compute full layout */,
921 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
922 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
923 TabStops tabStops(nullptr, 0, 0);
924
925 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
926 DO_HYPHEN, false /* useBoundsForWidth */);
927 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
928 << " vs " << std::endl
929 << toString(textBuf, actual);
930 }
931 }
932
TEST_F(GreedyLineBreakerTest,testEmailOrUrl)933 TEST_F(GreedyLineBreakerTest, testEmailOrUrl) {
934 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
935
936 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
937 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
938 {
939 constexpr float LINE_WIDTH = 240;
940 const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
941 std::vector<LineBreakExpectation> expect = {
942 {"This is an url: ", 150, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
943 {"http://a.b", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
944 };
945 const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
946 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
947 << " vs " << std::endl
948 << toString(textBuf, actual);
949 }
950 {
951 constexpr float LINE_WIDTH = 240;
952 const auto textBuf = utf8ToUtf16("This is an email: a@example.com");
953 std::vector<LineBreakExpectation> expect = {
954 {"This is an email: ", 170, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
955 {"a@example.com", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
956 };
957 const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
958 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
959 << " vs " << std::endl
960 << toString(textBuf, actual);
961 }
962 }
963
TEST_F(GreedyLineBreakerTest,testLocaleSwitch_InEmailOrUrl)964 TEST_F(GreedyLineBreakerTest, testLocaleSwitch_InEmailOrUrl) {
965 constexpr float CHAR_WIDTH = 10.0;
966 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
967
968 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
969 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
970
971 constexpr float LINE_WIDTH = 240;
972 {
973 const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
974 std::vector<LineBreakExpectation> expect = {
975 {"This is an url: ", 150, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
976 {"http://a.b", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
977 };
978
979 MeasuredTextBuilder builder;
980 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
981 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
982 DESCENT);
983 std::unique_ptr<MeasuredText> measuredText = builder.build(
984 textBuf, false /* compute hyphenation */, false /* compute full layout */,
985 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
986 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
987 TabStops tabStops(nullptr, 0, 0);
988
989 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
990 DO_HYPHEN, false /* useBoundsForWidth */);
991 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
992 << " vs " << std::endl
993 << toString(textBuf, actual);
994 }
995 {
996 const auto textBuf = utf8ToUtf16("This is an email: a@example.com");
997 std::vector<LineBreakExpectation> expect = {
998 {"This is an email: ", 170, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
999 {"a@example.com", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1000 };
1001
1002 MeasuredTextBuilder builder;
1003 builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1004 builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
1005 DESCENT);
1006 std::unique_ptr<MeasuredText> measuredText = builder.build(
1007 textBuf, false /* compute hyphenation */, false /* compute full layout */,
1008 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
1009 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
1010 TabStops tabStops(nullptr, 0, 0);
1011
1012 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
1013 DO_HYPHEN, false /* useBoundsForWidth */);
1014 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1015 << " vs " << std::endl
1016 << toString(textBuf, actual);
1017 }
1018 }
1019
1020 // b/68669534
TEST_F(GreedyLineBreakerTest,CrashFix_Space_Tab)1021 TEST_F(GreedyLineBreakerTest, CrashFix_Space_Tab) {
1022 constexpr float CHAR_WIDTH = 10.0;
1023 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
1024
1025 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1026 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1027 {
1028 constexpr float LINE_WIDTH = 50;
1029 const auto textBuf = utf8ToUtf16("a \tb");
1030 std::vector<LineBreakExpectation> expect = {
1031 {"a \tb", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1032 };
1033
1034 MeasuredTextBuilder builder;
1035 builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1036 DESCENT);
1037 std::unique_ptr<MeasuredText> measuredText = builder.build(
1038 textBuf, false /* compute hyphenation */, false /* compute full layout */,
1039 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
1040 RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
1041 TabStops tabStops(nullptr, 0, CHAR_WIDTH);
1042
1043 const auto actual = breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops,
1044 DO_HYPHEN, false /* useBoundsForWidth */);
1045 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1046 << " vs " << std::endl
1047 << toString(textBuf, actual);
1048 }
1049 }
1050
TEST_F(GreedyLineBreakerTest,ExtentTest)1051 TEST_F(GreedyLineBreakerTest, ExtentTest) {
1052 constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
1053 const std::vector<uint16_t> textBuf = utf8ToUtf16("The \u3042\u3044\u3046 is Japanese.");
1054
1055 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1056 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1057 {
1058 constexpr float LINE_WIDTH = 1000;
1059 std::vector<LineBreakExpectation> expect = {
1060 {"The \u3042\u3044\u3046 is Japanese.", 200, NO_START_HYPHEN, NO_END_HYPHEN,
1061 CUSTOM_ASCENT, CUSTOM_DESCENT},
1062 };
1063
1064 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1065 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1066 << " vs " << std::endl
1067 << toString(textBuf, actual);
1068 }
1069 {
1070 constexpr float LINE_WIDTH = 200;
1071 std::vector<LineBreakExpectation> expect = {
1072 {"The \u3042\u3044\u3046 is Japanese.", 200, NO_START_HYPHEN, NO_END_HYPHEN,
1073 CUSTOM_ASCENT, CUSTOM_DESCENT},
1074 };
1075
1076 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1077 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1078 << " vs " << std::endl
1079 << toString(textBuf, actual);
1080 }
1081 {
1082 constexpr float LINE_WIDTH = 190;
1083 std::vector<LineBreakExpectation> expect = {
1084 {"The \u3042\u3044\u3046 is ", 100, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1085 CUSTOM_DESCENT},
1086 {"Japanese.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1087 };
1088
1089 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1090 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1091 << " vs " << std::endl
1092 << toString(textBuf, actual);
1093 }
1094 {
1095 constexpr float LINE_WIDTH = 90;
1096 std::vector<LineBreakExpectation> expect = {
1097 {"The \u3042\u3044\u3046 ", 70, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1098 CUSTOM_DESCENT},
1099 {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1100 {"Japanese.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1101 };
1102
1103 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1104 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1105 << " vs " << std::endl
1106 << toString(textBuf, actual);
1107 }
1108 {
1109 constexpr float LINE_WIDTH = 50;
1110 std::vector<LineBreakExpectation> expect = {
1111 {"The \u3042", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1112 {"\u3044\u3046 is ", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1113 CUSTOM_DESCENT},
1114 {"Japan", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1115 {"ese.", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1116 };
1117
1118 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1119 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1120 << " vs " << std::endl
1121 << toString(textBuf, actual);
1122 }
1123 {
1124 constexpr float LINE_WIDTH = 40;
1125 std::vector<LineBreakExpectation> expect = {
1126 {"The ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1127 {"\u3042\u3044\u3046 ", 30, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
1128 CUSTOM_DESCENT},
1129 {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1130 {"Japa", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1131 {"nese", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1132 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1133 };
1134
1135 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1136 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1137 << " vs " << std::endl
1138 << toString(textBuf, actual);
1139 }
1140 {
1141 constexpr float LINE_WIDTH = 20;
1142 std::vector<LineBreakExpectation> expect = {
1143 {"Th", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1144 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1145 {"\u3042\u3044", 20, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1146 {"\u3046 ", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1147 {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1148 {"Ja", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1149 {"pa", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1150 {"ne", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1151 {"se", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1152 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1153 };
1154
1155 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1156 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1157 << " vs " << std::endl
1158 << toString(textBuf, actual);
1159 }
1160 {
1161 constexpr float LINE_WIDTH = 10;
1162 std::vector<LineBreakExpectation> expect = {
1163 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1164 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1165 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1166 {"\u3042", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1167 {"\u3044", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1168 {"\u3046 ", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
1169 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1170 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1171 {"J", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1172 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1173 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1174 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1175 {"n", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1176 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1177 {"s", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1178 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1179 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1180 };
1181
1182 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1183 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1184 << " vs " << std::endl
1185 << toString(textBuf, actual);
1186 }
1187 }
1188
TEST_F(GreedyLineBreakerTest,testReplacementSpanNotBreakTest_SingleChar)1189 TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_SingleChar) {
1190 constexpr float CHAR_WIDTH = 10.0;
1191 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
1192
1193 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1194 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1195
1196 const auto textBuf = utf8ToUtf16("This is an example \u2639 text.");
1197
1198 // In this test case, assign a replacement run for "U+2639" with 5 times of CHAR_WIDTH.
1199 auto doLineBreak = [=](float width) {
1200 MeasuredTextBuilder builder;
1201 builder.addCustomRun<ConstantRun>(Range(0, 19), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1202 builder.addReplacementRun(19, 20, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1203 builder.addCustomRun<ConstantRun>(Range(20, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1204 DESCENT);
1205
1206 std::unique_ptr<MeasuredText> measuredText = builder.build(
1207 textBuf, false /* compute hyphenation */, false /* compute full layout */,
1208 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
1209 RectangleLineWidth rectangleLineWidth(width);
1210 TabStops tabStops(nullptr, 0, 0);
1211 return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN,
1212 false /* useBoundsForWidth */);
1213 };
1214
1215 {
1216 constexpr float LINE_WIDTH = 100;
1217 // "is an" is a single replacement span. Do not break.
1218 // clang-format off
1219 std::vector<LineBreakExpectation> expect = {
1220 {"This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1221 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1222 {"\u2639 ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1223 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1224 };
1225 // clang-format on
1226 const auto actual = doLineBreak(LINE_WIDTH);
1227 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1228 << " vs " << std::endl
1229 << toString(textBuf, actual);
1230 }
1231 {
1232 constexpr float LINE_WIDTH = 90;
1233 // "is an" is a single replacement span. Do not break.
1234 // clang-format off
1235 std::vector<LineBreakExpectation> expect = {
1236 {"This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1237 {"an ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1238 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1239 {"\u2639 ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1240 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1241 };
1242 // clang-format on
1243 const auto actual = doLineBreak(LINE_WIDTH);
1244 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1245 << " vs " << std::endl
1246 << toString(textBuf, actual);
1247 }
1248 {
1249 constexpr float LINE_WIDTH = 10;
1250 // "is an" is a single replacement span. Do not break.
1251 // clang-format off
1252 std::vector<LineBreakExpectation> expect = {
1253 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1254 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1255 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1256 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1257 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1258 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1259 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1260 {"n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1261 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1262 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1263 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1264 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1265 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1266 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1267 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1268 // TODO: This should be "\u2639 " since should not count the trailing line end space
1269 {"\u2639", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1270 {" ", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1271 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1272 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1273 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1274 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1275 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1276 };
1277 // clang-format on
1278 const auto actual = doLineBreak(LINE_WIDTH);
1279 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1280 << " vs " << std::endl
1281 << toString(textBuf, actual);
1282 }
1283 }
1284
TEST_F(GreedyLineBreakerTest,testReplacementSpanNotBreakTest_MultipleChars)1285 TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_MultipleChars) {
1286 constexpr float CHAR_WIDTH = 10.0;
1287 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
1288
1289 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1290 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1291
1292 const auto textBuf = utf8ToUtf16("This is an example text.");
1293
1294 // In this test case, assign a replacement run for "is an " with 5 times of CHAR_WIDTH.
1295 auto doLineBreak = [=](float width) {
1296 MeasuredTextBuilder builder;
1297 builder.addCustomRun<ConstantRun>(Range(0, 5), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1298 builder.addReplacementRun(5, 11, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1299 builder.addCustomRun<ConstantRun>(Range(11, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1300 DESCENT);
1301
1302 std::unique_ptr<MeasuredText> measuredText = builder.build(
1303 textBuf, false /* compute hyphenation */, false /* compute full layout */,
1304 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
1305 RectangleLineWidth rectangleLineWidth(width);
1306 TabStops tabStops(nullptr, 0, 0);
1307 return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN,
1308 false /* useBoundsForWidth */);
1309 };
1310
1311 {
1312 constexpr float LINE_WIDTH = 100;
1313 // "is an" is a single replacement span. Do not break.
1314 // clang-format off
1315 std::vector<LineBreakExpectation> expect = {
1316 {"This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1317 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1318 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1319 };
1320 // clang-format on
1321 const auto actual = doLineBreak(LINE_WIDTH);
1322 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1323 << " vs " << std::endl
1324 << toString(textBuf, actual);
1325 }
1326 {
1327 constexpr float LINE_WIDTH = 90;
1328 // "is an" is a single replacement span. Do not break.
1329 // clang-format off
1330 std::vector<LineBreakExpectation> expect = {
1331 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1332 {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1333 {"example ",70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1334 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1335 };
1336 // clang-format on
1337 const auto actual = doLineBreak(LINE_WIDTH);
1338 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1339 << " vs " << std::endl
1340 << toString(textBuf, actual);
1341 }
1342 {
1343 constexpr float LINE_WIDTH = 10;
1344 // "is an" is a single replacement span. Do not break.
1345 // clang-format off
1346 std::vector<LineBreakExpectation> expect = {
1347 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1348 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1349 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1350 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1351 {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1352 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1353 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1354 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1355 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1356 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1357 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1358 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1359 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1360 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1361 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1362 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1363 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1364 };
1365 // clang-format on
1366 const auto actual = doLineBreak(LINE_WIDTH);
1367 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1368 << " vs " << std::endl
1369 << toString(textBuf, actual);
1370 }
1371 }
1372
TEST_F(GreedyLineBreakerTest,testReplacementSpanNotBreakTest_CJK)1373 TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_CJK) {
1374 constexpr float CHAR_WIDTH = 10.0;
1375 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
1376
1377 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1378 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1379
1380 // Example string: "Today is a sunny day." in Japanese.
1381 const auto textBuf = utf8ToUtf16("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A");
1382
1383 // In this test case, assign a replacement run for "\u6674\u5929" with 5 times of CHAR_WIDTH.
1384 auto doLineBreak = [=](float width) {
1385 MeasuredTextBuilder builder;
1386 builder.addCustomRun<ConstantRun>(Range(0, 3), "ja-JP", CHAR_WIDTH, ASCENT, DESCENT);
1387 builder.addReplacementRun(3, 5, 5 * CHAR_WIDTH, LocaleListCache::getId("ja-JP"));
1388 builder.addCustomRun<ConstantRun>(Range(5, textBuf.size()), "ja-JP", CHAR_WIDTH, ASCENT,
1389 DESCENT);
1390
1391 std::unique_ptr<MeasuredText> measuredText = builder.build(
1392 textBuf, false /* compute hyphenation */, false /* compute full layout */,
1393 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
1394 RectangleLineWidth rectangleLineWidth(width);
1395 TabStops tabStops(nullptr, 0, 0);
1396 return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN,
1397 false /* useBoundsForWidth */);
1398 };
1399
1400 {
1401 constexpr float LINE_WIDTH = 100;
1402 // "\u6674\u5929" is a single replacement span. Do not break.
1403 // clang-format off
1404 std::vector<LineBreakExpectation> expect = {
1405 {"\u672C\u65E5\u306F\u6674\u5929\u306A\u308A",
1406 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1407 };
1408 // clang-format on
1409 const auto actual = doLineBreak(LINE_WIDTH);
1410 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1411 << " vs " << std::endl
1412 << toString(textBuf, actual);
1413 }
1414 {
1415 constexpr float LINE_WIDTH = 90;
1416 // "\u6674\u5929" is a single replacement span. Do not break.
1417 // clang-format off
1418 std::vector<LineBreakExpectation> expect = {
1419 {"\u672C\u65E5\u306F\u6674\u5929\u306A",
1420 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1421 {"\u308A",
1422 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1423 };
1424 // clang-format on
1425 const auto actual = doLineBreak(LINE_WIDTH);
1426 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1427 << " vs " << std::endl
1428 << toString(textBuf, actual);
1429 }
1430 {
1431 constexpr float LINE_WIDTH = 80;
1432 // "\u6674\u5929" is a single replacement span. Do not break.
1433 // clang-format off
1434 std::vector<LineBreakExpectation> expect = {
1435 {"\u672C\u65E5\u306F\u6674\u5929",
1436 80, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1437 {"\u306A\u308A",
1438 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1439 };
1440 // clang-format on
1441 const auto actual = doLineBreak(LINE_WIDTH);
1442 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1443 << " vs " << std::endl
1444 << toString(textBuf, actual);
1445 }
1446 {
1447 constexpr float LINE_WIDTH = 70;
1448 // "\u6674\u5929" is a single replacement span. Do not break.
1449 // clang-format off
1450 std::vector<LineBreakExpectation> expect = {
1451 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1452 {"\u6674\u5929\u306A\u308A", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1453 };
1454 // clang-format on
1455 const auto actual = doLineBreak(LINE_WIDTH);
1456 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1457 << " vs " << std::endl
1458 << toString(textBuf, actual);
1459 }
1460 {
1461 constexpr float LINE_WIDTH = 60;
1462 // "\u6674\u5929" is a single replacement span. Do not break.
1463 // clang-format off
1464 std::vector<LineBreakExpectation> expect = {
1465 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1466 {"\u6674\u5929\u306A", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1467 {"\u308A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1468 };
1469 // clang-format on
1470 const auto actual = doLineBreak(LINE_WIDTH);
1471 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1472 << " vs " << std::endl
1473 << toString(textBuf, actual);
1474 }
1475 {
1476 constexpr float LINE_WIDTH = 50;
1477 // "\u6674\u5929" is a single replacement span. Do not break.
1478 // clang-format off
1479 std::vector<LineBreakExpectation> expect = {
1480 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1481 {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1482 {"\u306A\u308A", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1483 };
1484 // clang-format on
1485 const auto actual = doLineBreak(LINE_WIDTH);
1486 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1487 << " vs " << std::endl
1488 << toString(textBuf, actual);
1489 }
1490 {
1491 constexpr float LINE_WIDTH = 40;
1492 // "\u6674\u5929" is a single replacement span. Do not break.
1493 // clang-format off
1494 std::vector<LineBreakExpectation> expect = {
1495 {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1496 {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1497 {"\u306A\u308A", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1498 };
1499 // clang-format on
1500 const auto actual = doLineBreak(LINE_WIDTH);
1501 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1502 << " vs " << std::endl
1503 << toString(textBuf, actual);
1504 }
1505 {
1506 constexpr float LINE_WIDTH = 10;
1507 // "\u6674\u5929" is a single replacement span. Do not break.
1508 // clang-format off
1509 std::vector<LineBreakExpectation> expect = {
1510 {"\u672C", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1511 {"\u65E5", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1512 {"\u306F", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1513 {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1514 {"\u306A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1515 {"\u308A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1516 };
1517 // clang-format on
1518 const auto actual = doLineBreak(LINE_WIDTH);
1519 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1520 << " vs " << std::endl
1521 << toString(textBuf, actual);
1522 }
1523 }
1524
TEST_F(GreedyLineBreakerTest,testReplacementSpanNotBreakTest_with_punctuation)1525 TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_with_punctuation) {
1526 constexpr float CHAR_WIDTH = 10.0;
1527 constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
1528
1529 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1530 constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
1531 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1532
1533 const auto textBuf = utf8ToUtf16("This (is an) example text.");
1534
1535 // In this test case, assign a replacement run for "U+2639" with 5 times of CHAR_WIDTH.
1536 auto doLineBreak = [=](float width) {
1537 MeasuredTextBuilder builder;
1538 builder.addCustomRun<ConstantRun>(Range(0, 6), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
1539 builder.addReplacementRun(6, 11, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
1540 builder.addCustomRun<ConstantRun>(Range(11, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
1541 DESCENT);
1542
1543 std::unique_ptr<MeasuredText> measuredText = builder.build(
1544 textBuf, false /* compute hyphenation */, false /* compute full layout */,
1545 false /* computeBounds */, false /* ignore kerning */, nullptr /* no hint */);
1546 RectangleLineWidth rectangleLineWidth(width);
1547 TabStops tabStops(nullptr, 0, 0);
1548 return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN,
1549 false /* useBoundsForWidth */);
1550 };
1551
1552 {
1553 constexpr float LINE_WIDTH = 1000;
1554 // "is an" is a single replacement span. Do not break.
1555 // clang-format off
1556 std::vector<LineBreakExpectation> expect = {
1557 {"This (is an) example text.",
1558 260, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1559 };
1560 // clang-format on
1561 const auto actual = doLineBreak(LINE_WIDTH);
1562 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1563 << " vs " << std::endl
1564 << toString(textBuf, actual);
1565 }
1566 {
1567 constexpr float LINE_WIDTH = 250;
1568 // "is an" is a single replacement span. Do not break.
1569 // clang-format off
1570 std::vector<LineBreakExpectation> expect = {
1571 {"This (is an) example ", 200, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1572 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1573 };
1574 // clang-format on
1575 const auto actual = doLineBreak(LINE_WIDTH);
1576 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1577 << " vs " << std::endl
1578 << toString(textBuf, actual);
1579 }
1580 {
1581 constexpr float LINE_WIDTH = 190;
1582 // "is an" is a single replacement span. Do not break.
1583 // clang-format off
1584 std::vector<LineBreakExpectation> expect = {
1585 {"This (is an) ", 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1586 {"example text.", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1587 };
1588 // clang-format on
1589 const auto actual = doLineBreak(LINE_WIDTH);
1590 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1591 << " vs " << std::endl
1592 << toString(textBuf, actual);
1593 }
1594 {
1595 constexpr float LINE_WIDTH = 120;
1596 // "is an" is a single replacement span. Do not break.
1597 // clang-format off
1598 std::vector<LineBreakExpectation> expect = {
1599 {"This (is an) ", 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1600 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1601 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1602 };
1603 // clang-format on
1604 const auto actual = doLineBreak(LINE_WIDTH);
1605 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1606 << " vs " << std::endl
1607 << toString(textBuf, actual);
1608 }
1609 {
1610 constexpr float LINE_WIDTH = 110;
1611 // "is an" is a single replacement span. Do not break.
1612 // clang-format off
1613 std::vector<LineBreakExpectation> expect = {
1614 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1615 {"(is an) ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1616 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1617 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1618 };
1619 // clang-format on
1620 const auto actual = doLineBreak(LINE_WIDTH);
1621 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1622 << " vs " << std::endl
1623 << toString(textBuf, actual);
1624 }
1625 {
1626 constexpr float LINE_WIDTH = 60;
1627 // "is an" is a single replacement span. Do not break.
1628 // clang-format off
1629 std::vector<LineBreakExpectation> expect = {
1630 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1631 {"(is an", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1632 {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1633 {"exam-", 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
1634 {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1635 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1636 };
1637 // clang-format on
1638 const auto actual = doLineBreak(LINE_WIDTH);
1639 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1640 << " vs " << std::endl
1641 << toString(textBuf, actual);
1642 }
1643 {
1644 constexpr float LINE_WIDTH = 50;
1645 // "is an" is a single replacement span. Do not break.
1646 // clang-format off
1647 std::vector<LineBreakExpectation> expect = {
1648 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1649 {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1650 {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1651 {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1652 {"exam-", 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
1653 {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1654 {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1655 };
1656 // clang-format on
1657 const auto actual = doLineBreak(LINE_WIDTH);
1658 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1659 << " vs " << std::endl
1660 << toString(textBuf, actual);
1661 }
1662 {
1663 constexpr float LINE_WIDTH = 40;
1664 // "is an" is a single replacement span. Do not break.
1665 // clang-format off
1666 std::vector<LineBreakExpectation> expect = {
1667 {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1668 {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1669 {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1670 {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1671 {"ex-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
1672 {"am-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
1673 {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1674 {"text", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1675 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1676 };
1677 // clang-format on
1678 const auto actual = doLineBreak(LINE_WIDTH);
1679 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1680 << " vs " << std::endl
1681 << toString(textBuf, actual);
1682 }
1683 {
1684 constexpr float LINE_WIDTH = 10;
1685 // "is an" is a single replacement span. Do not break.
1686 // clang-format off
1687 std::vector<LineBreakExpectation> expect = {
1688 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1689 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1690 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1691 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1692 {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1693 {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
1694 {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1695 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1696 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1697 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1698 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1699 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1700 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1701 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1702 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1703 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1704 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1705 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1706 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1707 };
1708 // clang-format on
1709 const auto actual = doLineBreak(LINE_WIDTH);
1710 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1711 << " vs " << std::endl
1712 << toString(textBuf, actual);
1713 }
1714 }
1715
TEST_F(GreedyLineBreakerTest,testControllCharAfterSpace)1716 TEST_F(GreedyLineBreakerTest, testControllCharAfterSpace) {
1717 constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
1718 const std::vector<uint16_t> textBuf = utf8ToUtf16("example \u2066example");
1719
1720 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1721 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1722 {
1723 constexpr float LINE_WIDTH = 90;
1724 std::vector<LineBreakExpectation> expect = {
1725 {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1726 {"\u2066example", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1727 };
1728
1729 const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
1730 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1731 << " vs " << std::endl
1732 << toString(textBuf, actual);
1733 }
1734 }
1735
TEST_F(GreedyLineBreakerTest,testBreakWithoutBounds_trail)1736 TEST_F(GreedyLineBreakerTest, testBreakWithoutBounds_trail) {
1737 // The OvershootTest.ttf has following coverage, extent, width and bbox.
1738 // U+0061(a): 1em, ( 0, 0) - (1, 1)
1739 // U+0062(b): 1em, ( 0, 0) - (1.5, 1)
1740 // U+0063(c): 1em, ( 0, 0) - (2, 1)
1741 // U+0064(d): 1em, ( 0, 0) - (2.5, 1)
1742 // U+0065(e): 1em, (-0.5, 0) - (1, 1)
1743 // U+0066(f): 1em, (-1.0, 0) - (1, 1)
1744 // U+0067(g): 1em, (-1.5, 0) - (1, 1)
1745 constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
1746
1747 const std::vector<uint16_t> textBuf = utf8ToUtf16("dddd dddd dddd dddd");
1748 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1749 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1750 // Note that disable clang-format everywhere since aligned expectation is more readable.
1751 {
1752 constexpr float LINE_WIDTH = 1000;
1753 // clang-format off
1754 std::vector<LineBreakExpectation> expect = {
1755 {"dddd dddd dddd dddd", 190, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1756 };
1757 // clang-format on
1758
1759 const auto actual = doLineBreakForBounds(textBuf, NO_HYPHEN, LINE_WIDTH);
1760 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1761 << " vs " << std::endl
1762 << toString(textBuf, actual);
1763 EXPECT_EQ(MinikinRect(0, -10, 205, 0), actual.bounds[0]);
1764 }
1765 {
1766 constexpr float LINE_WIDTH = 110;
1767 // clang-format off
1768 std::vector<LineBreakExpectation> expect = {
1769 {"dddd dddd ", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1770 {"dddd dddd", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1771 };
1772 // clang-format on
1773
1774 const auto actual = doLineBreakForBounds(textBuf, NO_HYPHEN, LINE_WIDTH);
1775 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1776 << " vs " << std::endl
1777 << toString(textBuf, actual);
1778 EXPECT_EQ(MinikinRect(0, -10, 105, 0), actual.bounds[0]);
1779 EXPECT_EQ(MinikinRect(0, -10, 105, 0), actual.bounds[1]);
1780 }
1781 {
1782 constexpr float LINE_WIDTH = 100;
1783 // Even if the total advance of "dddd dddd" is 90, the width of bounding box of "dddd dddd"
1784 // is
1785 // Rect(0em, 1em, 10.5em, 0em). So "dddd dddd" is broken into two lines.
1786 // clang-format off
1787 std::vector<LineBreakExpectation> expect = {
1788 {"dddd ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1789 {"dddd ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1790 {"dddd ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1791 {"dddd", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1792 };
1793 // clang-format on
1794
1795 const auto actual = doLineBreakForBounds(textBuf, NO_HYPHEN, LINE_WIDTH);
1796 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1797 << " vs " << std::endl
1798 << toString(textBuf, actual);
1799 EXPECT_EQ(MinikinRect(0, -10, 55, 0), actual.bounds[0]);
1800 EXPECT_EQ(MinikinRect(0, -10, 55, 0), actual.bounds[1]);
1801 EXPECT_EQ(MinikinRect(0, -10, 55, 0), actual.bounds[2]);
1802 EXPECT_EQ(MinikinRect(0, -10, 55, 0), actual.bounds[3]);
1803 }
1804 }
1805
TEST_F(GreedyLineBreakerTest,testBreakWithoutBounds_preceding)1806 TEST_F(GreedyLineBreakerTest, testBreakWithoutBounds_preceding) {
1807 // The OvershootTest.ttf has following coverage, extent, width and bbox.
1808 // U+0061(a): 1em, ( 0, 0) - (1, 1)
1809 // U+0062(b): 1em, ( 0, 0) - (1.5, 1)
1810 // U+0063(c): 1em, ( 0, 0) - (2, 1)
1811 // U+0064(d): 1em, ( 0, 0) - (2.5, 1)
1812 // U+0065(e): 1em, (-0.5, 0) - (1, 1)
1813 // U+0066(f): 1em, (-1.0, 0) - (1, 1)
1814 // U+0067(g): 1em, (-1.5, 0) - (1, 1)
1815 constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
1816
1817 const std::vector<uint16_t> textBuf = utf8ToUtf16("gggg gggg gggg gggg");
1818 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1819 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1820 // Note that disable clang-format everywhere since aligned expectation is more readable.
1821 {
1822 constexpr float LINE_WIDTH = 1000;
1823 // clang-format off
1824 std::vector<LineBreakExpectation> expect = {
1825 {"gggg gggg gggg gggg", 190, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1826 };
1827 // clang-format on
1828
1829 const auto actual = doLineBreakForBounds(textBuf, NO_HYPHEN, LINE_WIDTH);
1830 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1831 << " vs " << std::endl
1832 << toString(textBuf, actual);
1833 EXPECT_EQ(MinikinRect(-15, -10, 190, 0), actual.bounds[0]);
1834 }
1835 {
1836 constexpr float LINE_WIDTH = 110;
1837 // clang-format off
1838 std::vector<LineBreakExpectation> expect = {
1839 {"gggg gggg ", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1840 {"gggg gggg" , 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1841 };
1842 // clang-format on
1843
1844 const auto actual = doLineBreakForBounds(textBuf, NO_HYPHEN, LINE_WIDTH);
1845 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1846 << " vs " << std::endl
1847 << toString(textBuf, actual);
1848 EXPECT_EQ(MinikinRect(-15, -10, 90, 0), actual.bounds[0]);
1849 EXPECT_EQ(MinikinRect(-15, -10, 90, 0), actual.bounds[1]);
1850 }
1851 {
1852 constexpr float LINE_WIDTH = 100;
1853 // Even if the total advance of "dddd dddd" is 90, the width of bounding box of "dddd dddd"
1854 // is
1855 // Rect(0em, 1em, 10.5em, 0em). So "dddd dddd" is broken into two lines.
1856 // clang-format off
1857 std::vector<LineBreakExpectation> expect = {
1858 {"gggg ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1859 {"gggg ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1860 {"gggg ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1861 {"gggg" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
1862 };
1863 // clang-format on
1864
1865 const auto actual = doLineBreakForBounds(textBuf, NO_HYPHEN, LINE_WIDTH);
1866 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1867 << " vs " << std::endl
1868 << toString(textBuf, actual);
1869 EXPECT_EQ(MinikinRect(-15, -10, 40, 0), actual.bounds[0]);
1870 EXPECT_EQ(MinikinRect(-15, -10, 40, 0), actual.bounds[1]);
1871 EXPECT_EQ(MinikinRect(-15, -10, 40, 0), actual.bounds[2]);
1872 EXPECT_EQ(MinikinRect(-15, -10, 40, 0), actual.bounds[3]);
1873 }
1874 }
1875
TEST_F(GreedyLineBreakerTest,testBreakWithHyphenation_NoHyphenationSpan)1876 TEST_F(GreedyLineBreakerTest, testBreakWithHyphenation_NoHyphenationSpan) {
1877 // "hyphenation" is hyphnated to "hy-phen-a-tion".
1878 const std::vector<uint16_t> textBuf = utf8ToUtf16("This is Android. Here is hyphenation.");
1879 const Range noHyphenRange(25, 37); // the range of the word "hyphenation".
1880
1881 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
1882 constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
1883 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
1884
1885 // Note that disable clang-format everywhere since aligned expectation is more readable.
1886 {
1887 constexpr float LINE_WIDTH = 100;
1888 // clang-format off
1889 std::vector<LineBreakExpectation> expect = {
1890 { "This is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1891 { "Android. " , 80, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1892 { "Here is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1893 { "hyphena-" , 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
1894 { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1895 };
1896 // clang-format on
1897
1898 const auto actual = doLineBreak(textBuf, true /* do hyphenation */, LINE_WIDTH);
1899 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1900 << " vs " << std::endl
1901 << toString(textBuf, actual);
1902 }
1903 {
1904 constexpr float LINE_WIDTH = 100;
1905 // clang-format off
1906 std::vector<LineBreakExpectation> expect = {
1907 { "This is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1908 { "Android. " , 80, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1909 { "Here is " , 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1910 // Prevent hyphenation of "hyphenation". Fallback to desperate break.
1911 { "hyphenatio" ,100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1912 { "n." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
1913 };
1914 // clang-format on
1915
1916 const auto actual = doLineBreakWithNoHyphenSpan(textBuf, noHyphenRange, LINE_WIDTH);
1917 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1918 << " vs " << std::endl
1919 << toString(textBuf, actual);
1920 }
1921 }
1922
TEST_F_WITH_FLAGS(GreedyLineBreakerTest,testPhraseBreakNone,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,word_style_auto)))1923 TEST_F_WITH_FLAGS(GreedyLineBreakerTest, testPhraseBreakNone,
1924 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
1925 word_style_auto))) {
1926 // For short hand of writing expectation for lines.
1927 auto line = [](std::string t, float w) -> LineBreakExpectation {
1928 return {t, w, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, ASCENT, DESCENT};
1929 };
1930
1931 // Note that disable clang-format everywhere since aligned expectation is more readable.
1932 {
1933 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 1));
1934 constexpr float LINE_WIDTH = 100;
1935 // clang-format off
1936 std::vector<LineBreakExpectation> expect = {
1937 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002" , 80),
1938 };
1939 // clang-format on
1940
1941 const auto actual =
1942 doLineBreakForJapanese(textBuf, LineBreakWordStyle::None, "ja-JP", LINE_WIDTH);
1943 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1944 << " vs " << std::endl
1945 << toString(textBuf, actual);
1946 }
1947 {
1948 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 2));
1949 constexpr float LINE_WIDTH = 100;
1950 // clang-format off
1951 std::vector<LineBreakExpectation> expect = {
1952 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5" , 100),
1953 line("\u306F\u6674\u5929\u306A\u308A\u3002" , 60),
1954 };
1955 // clang-format on
1956
1957 const auto actual =
1958 doLineBreakForJapanese(textBuf, LineBreakWordStyle::None, "ja-JP", LINE_WIDTH);
1959 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1960 << " vs " << std::endl
1961 << toString(textBuf, actual);
1962 }
1963 {
1964 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 3));
1965 constexpr float LINE_WIDTH = 100;
1966 // clang-format off
1967 std::vector<LineBreakExpectation> expect = {
1968 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5", 100),
1969 line("\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674", 100),
1970 line("\u5929\u306A\u308A\u3002", 40),
1971 };
1972 // clang-format on
1973
1974 const auto actual =
1975 doLineBreakForJapanese(textBuf, LineBreakWordStyle::None, "ja-JP", LINE_WIDTH);
1976 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1977 << " vs " << std::endl
1978 << toString(textBuf, actual);
1979 }
1980 {
1981 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 4));
1982 constexpr float LINE_WIDTH = 100;
1983 // clang-format off
1984 std::vector<LineBreakExpectation> expect = {
1985 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5", 100),
1986 line("\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674", 100),
1987 line("\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A", 100),
1988 line("\u308A\u3002" , 20),
1989 };
1990 // clang-format on
1991
1992 const auto actual =
1993 doLineBreakForJapanese(textBuf, LineBreakWordStyle::None, "ja-JP", LINE_WIDTH);
1994 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
1995 << " vs " << std::endl
1996 << toString(textBuf, actual);
1997 }
1998 {
1999 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 5));
2000 constexpr float LINE_WIDTH = 100;
2001 // clang-format off
2002 std::vector<LineBreakExpectation> expect = {
2003 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5", 100),
2004 line("\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674", 100),
2005 line("\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A", 100),
2006 line("\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 100),
2007 };
2008 // clang-format on
2009
2010 const auto actual =
2011 doLineBreakForJapanese(textBuf, LineBreakWordStyle::None, "ja-JP", LINE_WIDTH);
2012 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2013 << " vs " << std::endl
2014 << toString(textBuf, actual);
2015 }
2016 {
2017 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 6));
2018 constexpr float LINE_WIDTH = 100;
2019 // clang-format off
2020 std::vector<LineBreakExpectation> expect = {
2021 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5", 100),
2022 line("\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674", 100),
2023 line("\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A", 100),
2024 line("\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 100),
2025 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2026 };
2027 // clang-format on
2028
2029 const auto actual =
2030 doLineBreakForJapanese(textBuf, LineBreakWordStyle::None, "ja-JP", LINE_WIDTH);
2031 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2032 << " vs " << std::endl
2033 << toString(textBuf, actual);
2034 }
2035 }
2036
TEST_F_WITH_FLAGS(GreedyLineBreakerTest,testPhraseBreakPhrase,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,word_style_auto)))2037 TEST_F_WITH_FLAGS(GreedyLineBreakerTest, testPhraseBreakPhrase,
2038 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
2039 word_style_auto))) {
2040 // For short hand of writing expectation for lines.
2041 auto line = [](std::string t, float w) -> LineBreakExpectation {
2042 return {t, w, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, ASCENT, DESCENT};
2043 };
2044
2045 // Note that disable clang-format everywhere since aligned expectation is more readable.
2046 {
2047 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 1));
2048 constexpr float LINE_WIDTH = 100;
2049 // clang-format off
2050 std::vector<LineBreakExpectation> expect = {
2051 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2052 };
2053 // clang-format on
2054
2055 const auto actual =
2056 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Phrase, "ja-JP", LINE_WIDTH);
2057 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2058 << " vs " << std::endl
2059 << toString(textBuf, actual);
2060 }
2061 {
2062 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 2));
2063 constexpr float LINE_WIDTH = 100;
2064 // clang-format off
2065 std::vector<LineBreakExpectation> expect = {
2066 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2067 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2068 };
2069 // clang-format on
2070
2071 const auto actual =
2072 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Phrase, "ja-JP", LINE_WIDTH);
2073 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2074 << " vs " << std::endl
2075 << toString(textBuf, actual);
2076 }
2077 {
2078 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 3));
2079 constexpr float LINE_WIDTH = 100;
2080 // clang-format off
2081 std::vector<LineBreakExpectation> expect = {
2082 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2083 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2084 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2085 };
2086 // clang-format on
2087
2088 const auto actual =
2089 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Phrase, "ja-JP", LINE_WIDTH);
2090 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2091 << " vs " << std::endl
2092 << toString(textBuf, actual);
2093 }
2094 {
2095 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 4));
2096 constexpr float LINE_WIDTH = 100;
2097 // clang-format off
2098 std::vector<LineBreakExpectation> expect = {
2099 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2100 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2101 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2102 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2103 };
2104 // clang-format on
2105
2106 const auto actual =
2107 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Phrase, "ja-JP", LINE_WIDTH);
2108 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2109 << " vs " << std::endl
2110 << toString(textBuf, actual);
2111 }
2112 {
2113 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 5));
2114 constexpr float LINE_WIDTH = 100;
2115 // clang-format off
2116 std::vector<LineBreakExpectation> expect = {
2117 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2118 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2119 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2120 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2121 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2122 };
2123 // clang-format on
2124
2125 const auto actual =
2126 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Phrase, "ja-JP", LINE_WIDTH);
2127 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2128 << " vs " << std::endl
2129 << toString(textBuf, actual);
2130 }
2131 {
2132 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 6));
2133 constexpr float LINE_WIDTH = 100;
2134 // clang-format off
2135 std::vector<LineBreakExpectation> expect = {
2136 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2137 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2138 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2139 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2140 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2141 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2142 };
2143 // clang-format on
2144
2145 const auto actual =
2146 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Phrase, "ja-JP", LINE_WIDTH);
2147 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2148 << " vs " << std::endl
2149 << toString(textBuf, actual);
2150 }
2151 }
2152
TEST_F_WITH_FLAGS(GreedyLineBreakerTest,testPhraseBreakAuto,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,word_style_auto)))2153 TEST_F_WITH_FLAGS(GreedyLineBreakerTest, testPhraseBreakAuto,
2154 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
2155 word_style_auto))) {
2156 // For short hand of writing expectation for lines.
2157 auto line = [](std::string t, float w) -> LineBreakExpectation {
2158 return {t, w, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, ASCENT, DESCENT};
2159 };
2160
2161 // Note that disable clang-format everywhere since aligned expectation is more readable.
2162 {
2163 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 1));
2164 constexpr float LINE_WIDTH = 100;
2165 // clang-format off
2166 std::vector<LineBreakExpectation> expect = {
2167 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2168 };
2169 // clang-format on
2170
2171 const auto actual =
2172 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Auto, "ja-JP", LINE_WIDTH);
2173 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2174 << " vs " << std::endl
2175 << toString(textBuf, actual);
2176 }
2177 {
2178 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 2));
2179 constexpr float LINE_WIDTH = 100;
2180 // clang-format off
2181 std::vector<LineBreakExpectation> expect = {
2182 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2183 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2184 };
2185 // clang-format on
2186
2187 const auto actual =
2188 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Auto, "ja-JP", LINE_WIDTH);
2189 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2190 << " vs " << std::endl
2191 << toString(textBuf, actual);
2192 }
2193 {
2194 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 3));
2195 constexpr float LINE_WIDTH = 100;
2196 // clang-format off
2197 std::vector<LineBreakExpectation> expect = {
2198 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2199 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2200 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2201 };
2202 // clang-format on
2203
2204 const auto actual =
2205 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Auto, "ja-JP", LINE_WIDTH);
2206 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2207 << " vs " << std::endl
2208 << toString(textBuf, actual);
2209 }
2210 {
2211 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 4));
2212 constexpr float LINE_WIDTH = 100;
2213 // clang-format off
2214 std::vector<LineBreakExpectation> expect = {
2215 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2216 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2217 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2218 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 80),
2219 };
2220 // clang-format on
2221
2222 const auto actual =
2223 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Auto, "ja-JP", LINE_WIDTH);
2224 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2225 << " vs " << std::endl
2226 << toString(textBuf, actual);
2227 }
2228 // When the line becomes more or equal to 5, the phrase based line break is disabled.
2229 {
2230 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 5));
2231 constexpr float LINE_WIDTH = 100;
2232 // clang-format off
2233 std::vector<LineBreakExpectation> expect = {
2234 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5", 100),
2235 line("\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674", 100),
2236 line("\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A", 100),
2237 line("\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 100),
2238 };
2239 // clang-format on
2240
2241 const auto actual =
2242 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Auto, "ja-JP", LINE_WIDTH);
2243 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2244 << " vs " << std::endl
2245 << toString(textBuf, actual);
2246 }
2247 {
2248 const std::vector<uint16_t> textBuf = utf8ToUtf16(repeat(JP_TEXT, 6));
2249 constexpr float LINE_WIDTH = 100;
2250 // clang-format off
2251 std::vector<LineBreakExpectation> expect = {
2252 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5", 100),
2253 line("\u306F\u6674\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674", 100),
2254 line("\u5929\u306A\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A", 100),
2255 line("\u308A\u3002\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002", 100),
2256 line("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A\u3002" , 80),
2257 };
2258 // clang-format on
2259
2260 const auto actual =
2261 doLineBreakForJapanese(textBuf, LineBreakWordStyle::Auto, "ja-JP", LINE_WIDTH);
2262 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2263 << " vs " << std::endl
2264 << toString(textBuf, actual);
2265 }
2266 }
2267
TEST_F_WITH_FLAGS(GreedyLineBreakerTest,testPhraseBreak_Korean,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,word_style_auto)))2268 TEST_F_WITH_FLAGS(GreedyLineBreakerTest, testPhraseBreak_Korean,
2269 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
2270 word_style_auto))) {
2271 // For short hand of writing expectation for lines.
2272 auto line = [](std::string t, float w) -> LineBreakExpectation {
2273 return {t, w, StartHyphenEdit::NO_EDIT, EndHyphenEdit::NO_EDIT, ASCENT, DESCENT};
2274 };
2275
2276 // Note that disable clang-format everywhere since aligned expectation is more readable.
2277 {
2278 SCOPED_TRACE("LineBreakWOrdStyle::None should break with grapheme bounds");
2279 const std::vector<uint16_t> textBuf = utf8ToUtf16(KO_TEXT);
2280 constexpr float LINE_WIDTH = 100;
2281 // clang-format off
2282 std::vector<LineBreakExpectation> expect = {
2283 line("\uC544\uCE68\uBC25\uC744\u0020\uBA39\uACE0\u0020\uC2F6\uC2B5", 100),
2284 line("\uB2C8\uB2E4\u002E", 30),
2285 };
2286 // clang-format on
2287
2288 const auto actual =
2289 doLineBreakForKorean(textBuf, LineBreakWordStyle::None, "ko-KR", LINE_WIDTH);
2290 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2291 << " vs " << std::endl
2292 << toString(textBuf, actual);
2293 }
2294 {
2295 SCOPED_TRACE("LineBreakWOrdStyle::Phrase should break with spaces");
2296 const std::vector<uint16_t> textBuf = utf8ToUtf16(KO_TEXT);
2297 constexpr float LINE_WIDTH = 100;
2298 // clang-format off
2299 std::vector<LineBreakExpectation> expect = {
2300 line("\uC544\uCE68\uBC25\uC744\u0020\uBA39\uACE0\u0020", 70),
2301 line("\uC2F6\uC2B5\uB2C8\uB2E4\u002E", 50),
2302 };
2303 // clang-format on
2304
2305 const auto actual =
2306 doLineBreakForKorean(textBuf, LineBreakWordStyle::Phrase, "ko-KR", LINE_WIDTH);
2307 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2308 << " vs " << std::endl
2309 << toString(textBuf, actual);
2310 }
2311 {
2312 SCOPED_TRACE("LineBreakWOrdStyle::Auto should perform as phrase based line break.");
2313 const std::vector<uint16_t> textBuf = utf8ToUtf16(KO_TEXT);
2314 constexpr float LINE_WIDTH = 100;
2315 // clang-format off
2316 std::vector<LineBreakExpectation> expect = {
2317 line("\uC544\uCE68\uBC25\uC744\u0020\uBA39\uACE0\u0020", 70),
2318 line("\uC2F6\uC2B5\uB2C8\uB2E4\u002E", 50),
2319 };
2320 // clang-format on
2321
2322 const auto actual =
2323 doLineBreakForKorean(textBuf, LineBreakWordStyle::Auto, "ko-KR", LINE_WIDTH);
2324 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2325 << " vs " << std::endl
2326 << toString(textBuf, actual);
2327 }
2328 }
2329
TEST_F_WITH_FLAGS(GreedyLineBreakerTest,testBreakWithLetterSpacing,REQUIRES_FLAGS_ENABLED (ACONFIG_FLAG (com::android::text::flags,letter_spacing_justification)))2330 TEST_F_WITH_FLAGS(GreedyLineBreakerTest, testBreakWithLetterSpacing,
2331 REQUIRES_FLAGS_ENABLED(ACONFIG_FLAG(com::android::text::flags,
2332 letter_spacing_justification))) {
2333 const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
2334
2335 constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
2336 constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
2337 // Note that disable clang-format everywhere since aligned expectation is more readable.
2338 {
2339 constexpr float LINE_WIDTH = 1000;
2340 // clang-format off
2341 std::vector<LineBreakExpectation> expect = {
2342 {"This is an example text.", 470, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2343 };
2344 // clang-format on
2345 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2346 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2347 << " vs " << std::endl
2348 << toString(textBuf, actual);
2349 }
2350 {
2351 constexpr float LINE_WIDTH = 470;
2352 // clang-format off
2353 std::vector<LineBreakExpectation> expect = {
2354 {"This is an example text.", 470, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2355 };
2356 // clang-format on
2357 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2358 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2359 << " vs " << std::endl
2360 << toString(textBuf, actual);
2361 }
2362 {
2363 constexpr float LINE_WIDTH = 460;
2364 // clang-format off
2365 std::vector<LineBreakExpectation> expect = {
2366 {"This is an example ", 350, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2367 {"text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2368 };
2369 // clang-format on
2370 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2371 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2372 << " vs " << std::endl
2373 << toString(textBuf, actual);
2374 }
2375 {
2376 constexpr float LINE_WIDTH = 240;
2377 // clang-format off
2378 std::vector<LineBreakExpectation> expect = {
2379 {"This is an ", 190, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2380 {"example ", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2381 {"text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2382 };
2383 // clang-format on
2384 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2385 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2386 << " vs " << std::endl
2387 << toString(textBuf, actual);
2388 }
2389 {
2390 constexpr float LINE_WIDTH = 130;
2391 // clang-format off
2392 std::vector<LineBreakExpectation> expect = {
2393 {"This is ", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2394 {"an ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2395 {"example ", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2396 {"text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2397 };
2398 // clang-format on
2399 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2400 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2401 << " vs " << std::endl
2402 << toString(textBuf, actual);
2403 }
2404 {
2405 constexpr float LINE_WIDTH = 120;
2406 // clang-format off
2407 std::vector<LineBreakExpectation> expect = {
2408 {"This ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2409 {"is an ", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2410 {"exampl", 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2411 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2412 {"text.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2413 };
2414 // clang-format on
2415 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2416 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2417 << " vs " << std::endl
2418 << toString(textBuf, actual);
2419 }
2420 {
2421 constexpr float LINE_WIDTH = 30;
2422 // clang-format off
2423 std::vector<LineBreakExpectation> expect = {
2424 {"Th", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2425 {"is ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2426 {"is ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2427 {"an ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2428 {"ex", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2429 {"am", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2430 {"pl", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2431 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2432 {"te", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2433 {"xt", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2434 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2435 };
2436 // clang-format on
2437 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2438 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2439 << " vs " << std::endl
2440 << toString(textBuf, actual);
2441 }
2442 {
2443 constexpr float LINE_WIDTH = 10;
2444 // clang-format off
2445 std::vector<LineBreakExpectation> expect = {
2446 {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2447 {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2448 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2449 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2450 {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2451 {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2452 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2453 {"n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2454 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2455 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2456 {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2457 {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2458 {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2459 {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2460 {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2461 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2462 {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2463 {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2464 {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2465 {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
2466 };
2467 // clang-format on
2468 const auto actual = doLineBreakForLetterSpacing(textBuf, 1.0f, LINE_WIDTH);
2469 EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
2470 << " vs " << std::endl
2471 << toString(textBuf, actual);
2472 }
2473 }
2474
2475 } // namespace
2476 } // namespace minikin
2477