Home | History | Annotate | Download | only in unittest
      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 <memory>
     18 
     19 #include <gtest/gtest.h>
     20 
     21 #include "minikin/Hyphenator.h"
     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 
     33 namespace minikin {
     34 namespace {
     35 
     36 using line_breaker_test_helper::ConstantRun;
     37 using line_breaker_test_helper::LineBreakExpectation;
     38 using line_breaker_test_helper::RectangleLineWidth;
     39 using line_breaker_test_helper::sameLineBreak;
     40 using line_breaker_test_helper::toString;
     41 
     42 class GreedyLineBreakerTest : public testing::Test {
     43 public:
     44     GreedyLineBreakerTest() {}
     45 
     46     virtual ~GreedyLineBreakerTest() {}
     47 
     48     virtual void SetUp() override {
     49         mHyphenationPattern = readWholeFile("/system/usr/hyphen-data/hyph-en-us.hyb");
     50         Hyphenator* hyphenator = Hyphenator::loadBinary(
     51                 mHyphenationPattern.data(), 2 /* min prefix */, 2 /* min suffix */, "en-US");
     52         HyphenatorMap::add("en-US", hyphenator);
     53         HyphenatorMap::add("pl", Hyphenator::loadBinary(nullptr, 0, 0, "pl"));
     54     }
     55 
     56     virtual void TearDown() override { HyphenatorMap::clear(); }
     57 
     58 protected:
     59     LineBreakResult doLineBreak(const U16StringPiece& textBuffer, bool doHyphenation,
     60                                 float charWidth, float lineWidth) {
     61         return doLineBreak(textBuffer, doHyphenation, charWidth, "en-US", lineWidth);
     62     }
     63 
     64     LineBreakResult doLineBreak(const U16StringPiece& textBuffer, bool doHyphenation,
     65                                 float charWidth, const std::string& lang, float lineWidth) {
     66         MeasuredTextBuilder builder;
     67         builder.addCustomRun<ConstantRun>(Range(0, textBuffer.size()), lang, charWidth);
     68         std::unique_ptr<MeasuredText> measuredText = builder.build(
     69                 textBuffer, false /* compute hyphenation */, false /* compute full layout */);
     70         RectangleLineWidth rectangleLineWidth(lineWidth);
     71         TabStops tabStops(nullptr, 0, 10);
     72         return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
     73                                doHyphenation);
     74     }
     75 
     76 private:
     77     std::vector<uint8_t> mHyphenationPattern;
     78 };
     79 
     80 TEST_F(GreedyLineBreakerTest, testBreakWithoutHyphenation) {
     81     constexpr float CHAR_WIDTH = 10.0;
     82     constexpr bool NO_HYPHEN = false;  // No hyphenation in this test case.
     83     const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
     84 
     85     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
     86     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
     87     // Note that disable clang-format everywhere since aligned expectation is more readable.
     88     {
     89         constexpr float LINE_WIDTH = 1000 * CHAR_WIDTH;
     90         std::vector<LineBreakExpectation> expect = {
     91                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
     92         };
     93 
     94         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
     95         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
     96                                                    << " vs " << std::endl
     97                                                    << toString(textBuf, actual);
     98     }
     99     {
    100         constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
    101         std::vector<LineBreakExpectation> expect = {
    102                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    103         };
    104 
    105         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    106         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    107                                                    << " vs " << std::endl
    108                                                    << toString(textBuf, actual);
    109     }
    110     {
    111         constexpr float LINE_WIDTH = 23 * CHAR_WIDTH;
    112         // clang-format off
    113         std::vector<LineBreakExpectation> expect = {
    114                 { "This is an example ", 18 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    115                 { "text."              ,  5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    116         };
    117         // clang-format on
    118 
    119         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    120         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    121                                                    << " vs " << std::endl
    122                                                    << toString(textBuf, actual);
    123     }
    124     {
    125         constexpr float LINE_WIDTH = 8 * CHAR_WIDTH;
    126         // clang-format off
    127         std::vector<LineBreakExpectation> expect = {
    128                 { "This is ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    129                 { "an "     , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    130                 { "example ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    131                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    132         };
    133         // clang-format on
    134 
    135         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    136         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    137                                                    << " vs " << std::endl
    138                                                    << toString(textBuf, actual);
    139     }
    140     {
    141         constexpr float LINE_WIDTH = 7 * CHAR_WIDTH;
    142         // clang-format off
    143         std::vector<LineBreakExpectation> expect = {
    144                 { "This is ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    145                 { "an "     , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    146                 { "example ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    147                 { "text."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    148         };
    149         // clang-format on
    150 
    151         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    152         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    153                                                    << " vs " << std::endl
    154                                                    << toString(textBuf, actual);
    155     }
    156     {
    157         constexpr float LINE_WIDTH = 6 * CHAR_WIDTH;
    158         // clang-format off
    159         std::vector<LineBreakExpectation> expect = {
    160                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    161                 { "is an ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    162                 { "exampl", 6 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    163                 { "e "    , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    164                 { "text." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    165         };
    166         // clang-format on
    167 
    168         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    169         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    170                                                    << " vs " << std::endl
    171                                                    << toString(textBuf, actual);
    172     }
    173     {
    174         constexpr float LINE_WIDTH = 5 * CHAR_WIDTH;
    175         // clang-format off
    176         std::vector<LineBreakExpectation> expect = {
    177                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    178                 { "is an ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    179                 { "examp" , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    180                 { "le "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    181                 { "text." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    182         };
    183         // clang-format on
    184 
    185         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    186         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    187                                                    << " vs " << std::endl
    188                                                    << toString(textBuf, actual);
    189     }
    190     {
    191         constexpr float LINE_WIDTH = 4 * CHAR_WIDTH;
    192         // clang-format off
    193         std::vector<LineBreakExpectation> expect = {
    194                 { "This " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    195                 { "is "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    196                 { "an "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    197                 { "exam"  , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    198                 { "ple "  , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    199                 { "text"  , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    200                 { "."     , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    201         };
    202         // clang-format on
    203 
    204         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    205         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    206                                                    << " vs " << std::endl
    207                                                    << toString(textBuf, actual);
    208     }
    209     {
    210         constexpr float LINE_WIDTH = 3 * CHAR_WIDTH;
    211         // clang-format off
    212         std::vector<LineBreakExpectation> expect = {
    213                 { "Thi" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    214                 { "s "  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    215                 { "is " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    216                 { "an " , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    217                 { "exa" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    218                 { "mpl" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    219                 { "e "  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    220                 { "tex" , 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    221                 { "t."  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    222         };
    223         // clang-format on
    224 
    225         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    226         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    227                                                    << " vs " << std::endl
    228                                                    << toString(textBuf, actual);
    229     }
    230     {
    231         constexpr float LINE_WIDTH = 2 * CHAR_WIDTH;
    232         // clang-format off
    233         std::vector<LineBreakExpectation> expect = {
    234                 { "Th" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    235                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    236                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    237                 { "an ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    238                 { "ex" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    239                 { "am" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    240                 { "pl" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    241                 { "e " , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    242                 { "te" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    243                 { "xt" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    244                 { "."  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    245         };
    246         // clang-format on
    247 
    248         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    249         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    250                                                    << " vs " << std::endl
    251                                                    << toString(textBuf, actual);
    252     }
    253     {
    254         constexpr float LINE_WIDTH = 1 * CHAR_WIDTH;
    255         // clang-format off
    256         std::vector<LineBreakExpectation> expect = {
    257                 { "T" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    258                 { "h" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    259                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    260                 { "s ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    261                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    262                 { "s ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    263                 { "a" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    264                 { "n ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    265                 { "e" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    266                 { "x" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    267                 { "a" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    268                 { "m" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    269                 { "p" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    270                 { "l" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    271                 { "e ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    272                 { "t" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    273                 { "e" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    274                 { "x" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    275                 { "t" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    276                 { "." , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    277         };
    278         // clang-format on
    279 
    280         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    281         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    282                                                    << " vs " << std::endl
    283                                                    << toString(textBuf, actual);
    284     }
    285 }
    286 
    287 TEST_F(GreedyLineBreakerTest, testBreakWithHyphenation) {
    288     constexpr float CHAR_WIDTH = 10.0;
    289     constexpr bool NO_HYPHEN = true;  // Do hyphenation in this test case.
    290     // "hyphenation" is hyphnated to "hy-phen-a-tion".
    291     const std::vector<uint16_t> textBuf = utf8ToUtf16("Hyphenation is hyphenation.");
    292 
    293     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    294     constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
    295     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    296 
    297     // Note that disable clang-format everywhere since aligned expectation is more readable.
    298     {
    299         constexpr float LINE_WIDTH = 1000 * CHAR_WIDTH;
    300         std::vector<LineBreakExpectation> expect = {
    301                 {"Hyphenation is hyphenation.", 27 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    302         };
    303 
    304         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    305         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    306                                                    << " vs " << std::endl
    307                                                    << toString(textBuf, actual);
    308     }
    309     {
    310         constexpr float LINE_WIDTH = 27 * CHAR_WIDTH;
    311         std::vector<LineBreakExpectation> expect = {
    312                 {"Hyphenation is hyphenation.", 27 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    313         };
    314 
    315         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    316         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    317                                                    << " vs " << std::endl
    318                                                    << toString(textBuf, actual);
    319     }
    320     {
    321         constexpr float LINE_WIDTH = 26 * CHAR_WIDTH;
    322         // clang-format off
    323         std::vector<LineBreakExpectation> expect = {
    324                 { "Hyphenation is " , 14 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    325                 { "hyphenation."    , 12 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    326         };
    327         // clang-format on
    328 
    329         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    330         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    331                                                    << " vs " << std::endl
    332                                                    << toString(textBuf, actual);
    333     }
    334     {
    335         constexpr float LINE_WIDTH = 17 * CHAR_WIDTH;
    336         // clang-format off
    337         std::vector<LineBreakExpectation> expect = {
    338                 { "Hyphenation is " , 14 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    339                 { "hyphenation."    , 12 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    340         };
    341         // clang-format on
    342 
    343         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    344         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    345                                                    << " vs " << std::endl
    346                                                    << toString(textBuf, actual);
    347     }
    348     {
    349         constexpr float LINE_WIDTH = 12 * CHAR_WIDTH;
    350         // clang-format off
    351         std::vector<LineBreakExpectation> expect = {
    352                 { "Hyphenation " , 11 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    353                 { "is "          , 2  * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    354                 { "hyphenation." , 12 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    355         };
    356         // clang-format on
    357 
    358         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    359         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    360                                                    << " vs " << std::endl
    361                                                    << toString(textBuf, actual);
    362     }
    363     {
    364         constexpr float LINE_WIDTH = 10 * CHAR_WIDTH;
    365         // clang-format off
    366         std::vector<LineBreakExpectation> expect = {
    367                 { "Hyphena-", 8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    368                 { "tion is ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    369                 { "hyphena-", 8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    370                 { "tion."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    371         };
    372         // clang-format on
    373 
    374         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    375         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    376                                                    << " vs " << std::endl
    377                                                    << toString(textBuf, actual);
    378     }
    379     {
    380         constexpr float LINE_WIDTH = 8 * CHAR_WIDTH;
    381         // clang-format off
    382         std::vector<LineBreakExpectation> expect = {
    383                 { "Hyphena-", 8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    384                 { "tion is ", 7 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    385                 { "hyphena-", 8 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    386                 { "tion."   , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    387         };
    388         // clang-format on
    389 
    390         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    391         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    392                                                    << " vs " << std::endl
    393                                                    << toString(textBuf, actual);
    394     }
    395     {
    396         constexpr float LINE_WIDTH = 7 * CHAR_WIDTH;
    397         // clang-format off
    398         std::vector<LineBreakExpectation> expect = {
    399                 { "Hyphen-", 7 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    400                 { "ation " , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    401                 { "is "    , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    402                 { "hyphen-", 7 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    403                 { "ation." , 6 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    404         };
    405         // clang-format on
    406 
    407         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    408         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    409                                                    << " vs " << std::endl
    410                                                    << toString(textBuf, actual);
    411     }
    412     {
    413         constexpr float LINE_WIDTH = 6 * CHAR_WIDTH;
    414         // clang-format off
    415         std::vector<LineBreakExpectation> expect = {
    416                 { "Hy-"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    417                 { "phena-", 6 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    418                 { "tion " , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    419                 { "is "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    420                 { "hy-"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    421                 { "phena-", 6 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    422                 { "tion." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    423         };
    424         // clang-format on
    425 
    426         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    427         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    428                                                    << " vs " << std::endl
    429                                                    << toString(textBuf, actual);
    430     }
    431     {
    432         constexpr float LINE_WIDTH = 5 * CHAR_WIDTH;
    433         // clang-format off
    434         std::vector<LineBreakExpectation> expect = {
    435                 { "Hy-"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    436                 { "phen-" , 5 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    437                 { "ation ", 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    438                 { "is "   , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    439                 { "hy-"   , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    440                 { "phen-" , 5 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    441                 { "a-"    , 2 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    442                 { "tion." , 5 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    443         };
    444         // clang-format on
    445 
    446         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    447         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    448                                                    << " vs " << std::endl
    449                                                    << toString(textBuf, actual);
    450     }
    451     {
    452         constexpr float LINE_WIDTH = 4 * CHAR_WIDTH;
    453         // clang-format off
    454         std::vector<LineBreakExpectation> expect = {
    455                 { "Hy-"  , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    456                 { "phen" , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    457                 { "a-"   , 2 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    458                 { "tion ", 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    459                 { "is "  , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    460                 { "hy-"  , 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    461                 { "phen" , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    462                 { "a-"   , 2 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    463                 { "tion" , 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    464                 { "."    , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    465         };
    466         // clang-format on
    467 
    468         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    469         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    470                                                    << " vs " << std::endl
    471                                                    << toString(textBuf, actual);
    472     }
    473     {
    474         constexpr float LINE_WIDTH = 3 * CHAR_WIDTH;
    475         // clang-format off
    476         std::vector<LineBreakExpectation> expect = {
    477                 { "Hy-", 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    478                 { "phe", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    479                 { "na-", 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    480                 { "tio", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    481                 { "n " , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    482                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    483                 { "hy-", 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    484                 { "phe", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    485                 { "na-", 3 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    486                 { "tio", 3 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    487                 { "n." , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    488         };
    489         // clang-format on
    490 
    491         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    492         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    493                                                    << " vs " << std::endl
    494                                                    << toString(textBuf, actual);
    495     }
    496     {
    497         constexpr float LINE_WIDTH = 2 * CHAR_WIDTH;
    498         // clang-format off
    499         std::vector<LineBreakExpectation> expect = {
    500                 { "Hy" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    501                 { "ph" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    502                 { "en" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    503                 { "a-" , 2 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    504                 { "ti" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    505                 { "on ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    506                 { "is ", 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    507                 { "hy" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    508                 { "ph" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    509                 { "en" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    510                 { "a-" , 2 * CHAR_WIDTH, NO_START_HYPHEN, END_HYPHEN },
    511                 { "ti" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    512                 { "on" , 2 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    513                 { "."  , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    514         };
    515         // clang-format on
    516 
    517         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    518         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    519                                                    << " vs " << std::endl
    520                                                    << toString(textBuf, actual);
    521     }
    522     {
    523         constexpr float LINE_WIDTH = 1 * CHAR_WIDTH;
    524         // clang-format off
    525         std::vector<LineBreakExpectation> expect = {
    526                 { "H" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    527                 { "y" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    528                 { "p" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    529                 { "h" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    530                 { "e" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    531                 { "n" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    532                 { "a" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    533                 { "t" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    534                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    535                 { "o" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    536                 { "n ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    537                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    538                 { "s ", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    539                 { "h" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    540                 { "y" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    541                 { "p" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    542                 { "h" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    543                 { "e" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    544                 { "n" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    545                 { "a" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    546                 { "t" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    547                 { "i" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    548                 { "o" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    549                 { "n" , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    550                 { "." , 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN },
    551         };
    552         // clang-format on
    553 
    554         const auto actual = doLineBreak(textBuf, NO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    555         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    556                                                    << " vs " << std::endl
    557                                                    << toString(textBuf, actual);
    558     }
    559 }
    560 
    561 TEST_F(GreedyLineBreakerTest, testHyphenationStartLineChange) {
    562     constexpr float CHAR_WIDTH = 10.0;
    563     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    564     // "hyphenation" is hyphnated to "hy-phen-a-tion".
    565     const std::vector<uint16_t> textBuf = utf8ToUtf16("czerwono-niebieska");
    566 
    567     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    568     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    569     constexpr StartHyphenEdit START_HYPHEN = StartHyphenEdit::INSERT_HYPHEN;
    570 
    571     // Note that disable clang-format everywhere since aligned expectation is more readable.
    572     {
    573         constexpr float LINE_WIDTH = 1000 * CHAR_WIDTH;
    574         std::vector<LineBreakExpectation> expect = {
    575                 {"czerwono-niebieska", 18 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    576         };
    577 
    578         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, "pl", LINE_WIDTH);
    579         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    580                                                    << " vs " << std::endl
    581                                                    << toString(textBuf, actual);
    582     }
    583     {
    584         constexpr float LINE_WIDTH = 18 * CHAR_WIDTH;
    585         std::vector<LineBreakExpectation> expect = {
    586                 {"czerwono-niebieska", 18 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    587         };
    588 
    589         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, "pl", LINE_WIDTH);
    590         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    591                                                    << " vs " << std::endl
    592                                                    << toString(textBuf, actual);
    593     }
    594     {
    595         constexpr float LINE_WIDTH = 13 * CHAR_WIDTH;
    596         // clang-format off
    597         std::vector<LineBreakExpectation> expect = {
    598                 {"czerwono-" ,  9 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    599                 {"-niebieska", 10 * CHAR_WIDTH,    START_HYPHEN, NO_END_HYPHEN},
    600         };
    601         // clang-format on
    602 
    603         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, "pl", LINE_WIDTH);
    604         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    605                                                    << " vs " << std::endl
    606                                                    << toString(textBuf, actual);
    607     }
    608 }
    609 
    610 TEST_F(GreedyLineBreakerTest, testZeroWidthLine) {
    611     constexpr float CHAR_WIDTH = 10.0;
    612     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    613     constexpr float LINE_WIDTH = 0 * CHAR_WIDTH;
    614 
    615     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    616     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    617 
    618     {
    619         const auto textBuf = utf8ToUtf16("");
    620         std::vector<LineBreakExpectation> expect = {};
    621         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    622         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    623                                                    << " vs " << std::endl
    624                                                    << toString(textBuf, actual);
    625     }
    626     {
    627         const auto textBuf = utf8ToUtf16("A");
    628         std::vector<LineBreakExpectation> expect = {
    629                 {"A", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    630         };
    631         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    632         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    633                                                    << " vs " << std::endl
    634                                                    << toString(textBuf, actual);
    635     }
    636     {
    637         const auto textBuf = utf8ToUtf16("AB");
    638         std::vector<LineBreakExpectation> expect = {
    639                 {"A", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    640                 {"B", 1 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    641         };
    642         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    643         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    644                                                    << " vs " << std::endl
    645                                                    << toString(textBuf, actual);
    646     }
    647 }
    648 
    649 TEST_F(GreedyLineBreakerTest, testZeroWidthCharacter) {
    650     constexpr float CHAR_WIDTH = 0.0;
    651     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    652 
    653     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    654     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    655     {
    656         constexpr float LINE_WIDTH = 1.0;
    657         const auto textBuf = utf8ToUtf16("This is an example text.");
    658         std::vector<LineBreakExpectation> expect = {
    659                 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN},
    660         };
    661         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    662         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    663                                                    << " vs " << std::endl
    664                                                    << toString(textBuf, actual);
    665     }
    666     {
    667         constexpr float LINE_WIDTH = 0.0;
    668         const auto textBuf = utf8ToUtf16("This is an example text.");
    669         std::vector<LineBreakExpectation> expect = {
    670                 {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN},
    671         };
    672         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    673         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    674                                                    << " vs " << std::endl
    675                                                    << toString(textBuf, actual);
    676     }
    677 }
    678 
    679 TEST_F(GreedyLineBreakerTest, testLocaleSwitchTest) {
    680     constexpr float CHAR_WIDTH = 10.0;
    681     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    682 
    683     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    684     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    685 
    686     constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
    687     const auto textBuf = utf8ToUtf16("This is an example text.");
    688     {
    689         std::vector<LineBreakExpectation> expect = {
    690                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    691         };
    692 
    693         MeasuredTextBuilder builder;
    694         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
    695         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "en-US", CHAR_WIDTH);
    696         std::unique_ptr<MeasuredText> measuredText = builder.build(
    697                 textBuf, false /* compute hyphenation */, false /* compute full layout */);
    698         RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
    699         TabStops tabStops(nullptr, 0, 0);
    700 
    701         const auto actual =
    702                 breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
    703         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    704                                                    << " vs " << std::endl
    705                                                    << toString(textBuf, actual);
    706     }
    707     {
    708         std::vector<LineBreakExpectation> expect = {
    709                 {"This is an example text.", 24 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    710         };
    711 
    712         MeasuredTextBuilder builder;
    713         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
    714         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH);
    715         std::unique_ptr<MeasuredText> measuredText = builder.build(
    716                 textBuf, false /* compute hyphenation */, false /* compute full layout */);
    717         RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
    718         TabStops tabStops(nullptr, 0, 0);
    719 
    720         const auto actual =
    721                 breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
    722         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    723                                                    << " vs " << std::endl
    724                                                    << toString(textBuf, actual);
    725     }
    726 }
    727 
    728 TEST_F(GreedyLineBreakerTest, testEmailOrUrl) {
    729     constexpr float CHAR_WIDTH = 10.0;
    730     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    731 
    732     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    733     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    734     {
    735         constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
    736         const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
    737         std::vector<LineBreakExpectation> expect = {
    738                 {"This is an url: ", 15 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    739                 {"http://a.b", 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    740         };
    741         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    742         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    743                                                    << " vs " << std::endl
    744                                                    << toString(textBuf, actual);
    745     }
    746     {
    747         constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
    748         const auto textBuf = utf8ToUtf16("This is an email: a (at) example.com");
    749         std::vector<LineBreakExpectation> expect = {
    750                 {"This is an email: ", 17 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    751                 {"a (at) example.com", 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    752         };
    753         const auto actual = doLineBreak(textBuf, DO_HYPHEN, CHAR_WIDTH, LINE_WIDTH);
    754         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    755                                                    << " vs " << std::endl
    756                                                    << toString(textBuf, actual);
    757     }
    758 }
    759 
    760 TEST_F(GreedyLineBreakerTest, testLocaleSwitch_InEmailOrUrl) {
    761     constexpr float CHAR_WIDTH = 10.0;
    762     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    763 
    764     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    765     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    766 
    767     constexpr float LINE_WIDTH = 24 * CHAR_WIDTH;
    768     {
    769         const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
    770         std::vector<LineBreakExpectation> expect = {
    771                 {"This is an url: ", 15 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    772                 {"http://a.b", 10 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    773         };
    774 
    775         MeasuredTextBuilder builder;
    776         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
    777         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH);
    778         std::unique_ptr<MeasuredText> measuredText = builder.build(
    779                 textBuf, false /* compute hyphenation */, false /* compute full layout */);
    780         RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
    781         TabStops tabStops(nullptr, 0, 0);
    782 
    783         const auto actual =
    784                 breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
    785         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    786                                                    << " vs " << std::endl
    787                                                    << toString(textBuf, actual);
    788     }
    789     {
    790         const auto textBuf = utf8ToUtf16("This is an email: a (at) example.com");
    791         std::vector<LineBreakExpectation> expect = {
    792                 {"This is an email: ", 17 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    793                 {"a (at) example.com", 13 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    794         };
    795 
    796         MeasuredTextBuilder builder;
    797         builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH);
    798         builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH);
    799         std::unique_ptr<MeasuredText> measuredText = builder.build(
    800                 textBuf, false /* compute hyphenation */, false /* compute full layout */);
    801         RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
    802         TabStops tabStops(nullptr, 0, 0);
    803 
    804         const auto actual =
    805                 breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
    806         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    807                                                    << " vs " << std::endl
    808                                                    << toString(textBuf, actual);
    809     }
    810 }
    811 
    812 // b/68669534
    813 TEST_F(GreedyLineBreakerTest, CrashFix_Space_Tab) {
    814     constexpr float CHAR_WIDTH = 10.0;
    815     constexpr bool DO_HYPHEN = true;  // Do hyphenation in this test case.
    816 
    817     constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
    818     constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
    819     {
    820         constexpr float LINE_WIDTH = 5 * CHAR_WIDTH;
    821         const auto textBuf = utf8ToUtf16("a \tb");
    822         std::vector<LineBreakExpectation> expect = {
    823                 {"a \tb", 4 * CHAR_WIDTH, NO_START_HYPHEN, NO_END_HYPHEN},
    824         };
    825 
    826         MeasuredTextBuilder builder;
    827         builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH);
    828         std::unique_ptr<MeasuredText> measuredText = builder.build(
    829                 textBuf, false /* compute hyphenation */, false /* compute full layout */);
    830         RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
    831         TabStops tabStops(nullptr, 0, CHAR_WIDTH);
    832 
    833         const auto actual =
    834                 breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
    835         EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
    836                                                    << " vs " << std::endl
    837                                                    << toString(textBuf, actual);
    838     }
    839 }
    840 
    841 }  // namespace
    842 }  // namespace minikin
    843