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