GreedyLineBreakerTest.cpp 81 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564
  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. #include <memory>
  17. #include <gtest/gtest.h>
  18. #include "minikin/Hyphenator.h"
  19. #include "FileUtils.h"
  20. #include "FontTestUtils.h"
  21. #include "GreedyLineBreaker.h"
  22. #include "HyphenatorMap.h"
  23. #include "LineBreakerTestHelper.h"
  24. #include "LocaleListCache.h"
  25. #include "MinikinInternal.h"
  26. #include "UnicodeUtils.h"
  27. #include "WordBreaker.h"
  28. namespace minikin {
  29. namespace {
  30. using line_breaker_test_helper::ConstantRun;
  31. using line_breaker_test_helper::LineBreakExpectation;
  32. using line_breaker_test_helper::RectangleLineWidth;
  33. using line_breaker_test_helper::sameLineBreak;
  34. using line_breaker_test_helper::toString;
  35. // The ascent/descent of Ascii.ttf with text size = 10.
  36. constexpr float ASCENT = -80.0f;
  37. constexpr float DESCENT = 20.0f;
  38. // The ascent/descent of CustomExtent.ttf with text size = 10.
  39. constexpr float CUSTOM_ASCENT = -160.0f;
  40. constexpr float CUSTOM_DESCENT = 40.0f;
  41. class GreedyLineBreakerTest : public testing::Test {
  42. public:
  43. GreedyLineBreakerTest() {}
  44. virtual ~GreedyLineBreakerTest() {}
  45. virtual void SetUp() override {
  46. mHyphenationPattern = readWholeFile("/system/usr/hyphen-data/hyph-en-us.hyb");
  47. Hyphenator* hyphenator = Hyphenator::loadBinary(
  48. mHyphenationPattern.data(), 2 /* min prefix */, 2 /* min suffix */, "en-US");
  49. HyphenatorMap::add("en-US", hyphenator);
  50. HyphenatorMap::add("pl", Hyphenator::loadBinary(nullptr, 0, 0, "pl"));
  51. }
  52. virtual void TearDown() override { HyphenatorMap::clear(); }
  53. protected:
  54. LineBreakResult doLineBreak(const U16StringPiece& textBuffer, bool doHyphenation,
  55. float lineWidth) {
  56. return doLineBreak(textBuffer, doHyphenation, "en-US", lineWidth);
  57. }
  58. LineBreakResult doLineBreak(const U16StringPiece& textBuffer, bool doHyphenation,
  59. const std::string& lang, float lineWidth) {
  60. MeasuredTextBuilder builder;
  61. auto family1 = buildFontFamily("Ascii.ttf");
  62. auto family2 = buildFontFamily("CustomExtent.ttf");
  63. std::vector<std::shared_ptr<FontFamily>> families = {family1, family2};
  64. auto fc = std::make_shared<FontCollection>(families);
  65. MinikinPaint paint(fc);
  66. paint.size = 10.0f; // Make 1em=10px
  67. paint.localeListId = LocaleListCache::getId(lang);
  68. builder.addStyleRun(0, textBuffer.size(), std::move(paint), false);
  69. std::unique_ptr<MeasuredText> measuredText =
  70. builder.build(textBuffer, false /* compute hyphenation */,
  71. false /* compute full layout */, nullptr /* no hint */);
  72. RectangleLineWidth rectangleLineWidth(lineWidth);
  73. TabStops tabStops(nullptr, 0, 10);
  74. return breakLineGreedy(textBuffer, *measuredText, rectangleLineWidth, tabStops,
  75. doHyphenation);
  76. }
  77. private:
  78. std::vector<uint8_t> mHyphenationPattern;
  79. };
  80. TEST_F(GreedyLineBreakerTest, testBreakWithoutHyphenation) {
  81. constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
  82. const std::vector<uint16_t> textBuf = utf8ToUtf16("This is an example text.");
  83. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  84. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  85. // Note that disable clang-format everywhere since aligned expectation is more readable.
  86. {
  87. constexpr float LINE_WIDTH = 1000;
  88. std::vector<LineBreakExpectation> expect = {
  89. {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  90. };
  91. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  92. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  93. << " vs " << std::endl
  94. << toString(textBuf, actual);
  95. }
  96. {
  97. constexpr float LINE_WIDTH = 240;
  98. std::vector<LineBreakExpectation> expect = {
  99. {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  100. };
  101. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  102. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  103. << " vs " << std::endl
  104. << toString(textBuf, actual);
  105. }
  106. {
  107. constexpr float LINE_WIDTH = 230;
  108. // clang-format off
  109. std::vector<LineBreakExpectation> expect = {
  110. { "This is an example ", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  111. { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  112. };
  113. // clang-format on
  114. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  115. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  116. << " vs " << std::endl
  117. << toString(textBuf, actual);
  118. }
  119. {
  120. constexpr float LINE_WIDTH = 80;
  121. // clang-format off
  122. std::vector<LineBreakExpectation> expect = {
  123. { "This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  124. { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  125. { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  126. { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  127. };
  128. // clang-format on
  129. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  130. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  131. << " vs " << std::endl
  132. << toString(textBuf, actual);
  133. }
  134. {
  135. constexpr float LINE_WIDTH = 70;
  136. // clang-format off
  137. std::vector<LineBreakExpectation> expect = {
  138. { "This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  139. { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  140. { "example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  141. { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  142. };
  143. // clang-format on
  144. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  145. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  146. << " vs " << std::endl
  147. << toString(textBuf, actual);
  148. }
  149. {
  150. constexpr float LINE_WIDTH = 60;
  151. // clang-format off
  152. std::vector<LineBreakExpectation> expect = {
  153. { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  154. { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  155. { "exampl", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  156. { "e " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  157. { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  158. };
  159. // clang-format on
  160. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  161. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  162. << " vs " << std::endl
  163. << toString(textBuf, actual);
  164. }
  165. {
  166. constexpr float LINE_WIDTH = 50;
  167. // clang-format off
  168. std::vector<LineBreakExpectation> expect = {
  169. { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  170. { "is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  171. { "examp" , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  172. { "le " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  173. { "text." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  174. };
  175. // clang-format on
  176. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  177. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  178. << " vs " << std::endl
  179. << toString(textBuf, actual);
  180. }
  181. {
  182. constexpr float LINE_WIDTH = 40;
  183. // clang-format off
  184. std::vector<LineBreakExpectation> expect = {
  185. { "This " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  186. { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  187. { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  188. { "exam" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  189. { "ple " , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  190. { "text" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  191. { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  192. };
  193. // clang-format on
  194. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  195. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  196. << " vs " << std::endl
  197. << toString(textBuf, actual);
  198. }
  199. {
  200. constexpr float LINE_WIDTH = 30;
  201. // clang-format off
  202. std::vector<LineBreakExpectation> expect = {
  203. { "Thi" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  204. { "s " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  205. { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  206. { "an " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  207. { "exa" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  208. { "mpl" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  209. { "e " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  210. { "tex" , 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  211. { "t." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  212. };
  213. // clang-format on
  214. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  215. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  216. << " vs " << std::endl
  217. << toString(textBuf, actual);
  218. }
  219. {
  220. constexpr float LINE_WIDTH = 20;
  221. // clang-format off
  222. std::vector<LineBreakExpectation> expect = {
  223. { "Th" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  224. { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  225. { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  226. { "an ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  227. { "ex" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  228. { "am" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  229. { "pl" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  230. { "e " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  231. { "te" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  232. { "xt" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  233. { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  234. };
  235. // clang-format on
  236. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  237. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  238. << " vs " << std::endl
  239. << toString(textBuf, actual);
  240. }
  241. {
  242. constexpr float LINE_WIDTH = 10;
  243. // clang-format off
  244. std::vector<LineBreakExpectation> expect = {
  245. { "T" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  246. { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  247. { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  248. { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  249. { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  250. { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  251. { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  252. { "n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  253. { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  254. { "x" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  255. { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  256. { "m" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  257. { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  258. { "l" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  259. { "e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  260. { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  261. { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  262. { "x" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  263. { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  264. { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  265. };
  266. // clang-format on
  267. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  268. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  269. << " vs " << std::endl
  270. << toString(textBuf, actual);
  271. }
  272. }
  273. TEST_F(GreedyLineBreakerTest, testBreakWithHyphenation) {
  274. constexpr bool NO_HYPHEN = true; // Do hyphenation in this test case.
  275. // "hyphenation" is hyphnated to "hy-phen-a-tion".
  276. const std::vector<uint16_t> textBuf = utf8ToUtf16("Hyphenation is hyphenation.");
  277. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  278. constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
  279. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  280. // Note that disable clang-format everywhere since aligned expectation is more readable.
  281. {
  282. constexpr float LINE_WIDTH = 1000;
  283. std::vector<LineBreakExpectation> expect = {
  284. {"Hyphenation is hyphenation.", 270, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT,
  285. DESCENT},
  286. };
  287. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  288. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  289. << " vs " << std::endl
  290. << toString(textBuf, actual);
  291. }
  292. {
  293. constexpr float LINE_WIDTH = 270;
  294. std::vector<LineBreakExpectation> expect = {
  295. {"Hyphenation is hyphenation.", 270, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT,
  296. DESCENT},
  297. };
  298. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  299. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  300. << " vs " << std::endl
  301. << toString(textBuf, actual);
  302. }
  303. {
  304. constexpr float LINE_WIDTH = 260;
  305. // clang-format off
  306. std::vector<LineBreakExpectation> expect = {
  307. { "Hyphenation is " , 140, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  308. { "hyphenation." , 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  309. };
  310. // clang-format on
  311. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  312. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  313. << " vs " << std::endl
  314. << toString(textBuf, actual);
  315. }
  316. {
  317. constexpr float LINE_WIDTH = 170;
  318. // clang-format off
  319. std::vector<LineBreakExpectation> expect = {
  320. { "Hyphenation is " , 140, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  321. { "hyphenation." , 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  322. };
  323. // clang-format on
  324. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  325. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  326. << " vs " << std::endl
  327. << toString(textBuf, actual);
  328. }
  329. {
  330. constexpr float LINE_WIDTH = 120;
  331. // clang-format off
  332. std::vector<LineBreakExpectation> expect = {
  333. { "Hyphenation " , 110, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  334. { "is " , 20 , NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  335. { "hyphenation." , 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  336. };
  337. // clang-format on
  338. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  339. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  340. << " vs " << std::endl
  341. << toString(textBuf, actual);
  342. }
  343. {
  344. constexpr float LINE_WIDTH = 100;
  345. // clang-format off
  346. std::vector<LineBreakExpectation> expect = {
  347. { "Hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  348. { "tion is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  349. { "hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  350. { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  351. };
  352. // clang-format on
  353. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  354. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  355. << " vs " << std::endl
  356. << toString(textBuf, actual);
  357. }
  358. {
  359. constexpr float LINE_WIDTH = 80;
  360. // clang-format off
  361. std::vector<LineBreakExpectation> expect = {
  362. { "Hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  363. { "tion is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  364. { "hyphena-", 80, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  365. { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  366. };
  367. // clang-format on
  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 = 70;
  375. // clang-format off
  376. std::vector<LineBreakExpectation> expect = {
  377. { "Hyphen-", 70, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  378. { "ation " , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  379. { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  380. { "hyphen-", 70, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  381. { "ation." , 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  382. };
  383. // clang-format on
  384. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  385. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  386. << " vs " << std::endl
  387. << toString(textBuf, actual);
  388. }
  389. {
  390. constexpr float LINE_WIDTH = 60;
  391. // clang-format off
  392. std::vector<LineBreakExpectation> expect = {
  393. { "Hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  394. { "phena-", 60, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  395. { "tion " , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  396. { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  397. { "hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  398. { "phena-", 60, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  399. { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  400. };
  401. // clang-format on
  402. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  403. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  404. << " vs " << std::endl
  405. << toString(textBuf, actual);
  406. }
  407. {
  408. constexpr float LINE_WIDTH = 50;
  409. // clang-format off
  410. std::vector<LineBreakExpectation> expect = {
  411. { "Hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  412. { "phen-" , 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  413. { "ation ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  414. { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  415. { "hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  416. { "phen-" , 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  417. { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  418. { "tion." , 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  419. };
  420. // clang-format on
  421. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  422. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  423. << " vs " << std::endl
  424. << toString(textBuf, actual);
  425. }
  426. {
  427. constexpr float LINE_WIDTH = 40;
  428. // clang-format off
  429. std::vector<LineBreakExpectation> expect = {
  430. { "Hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  431. { "phen" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  432. { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  433. { "tion ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  434. { "is " , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  435. { "hy-" , 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  436. { "phen" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  437. { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  438. { "tion" , 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  439. { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  440. };
  441. // clang-format on
  442. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  443. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  444. << " vs " << std::endl
  445. << toString(textBuf, actual);
  446. }
  447. {
  448. constexpr float LINE_WIDTH = 30;
  449. // clang-format off
  450. std::vector<LineBreakExpectation> expect = {
  451. { "Hy-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  452. { "phe", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  453. { "na-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  454. { "tio", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  455. { "n " , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  456. { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  457. { "hy-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  458. { "phe", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  459. { "na-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  460. { "tio", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  461. { "n." , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  462. };
  463. // clang-format on
  464. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  465. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  466. << " vs " << std::endl
  467. << toString(textBuf, actual);
  468. }
  469. {
  470. constexpr float LINE_WIDTH = 20;
  471. // clang-format off
  472. std::vector<LineBreakExpectation> expect = {
  473. { "Hy" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  474. { "ph" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  475. { "en" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  476. { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  477. { "ti" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  478. { "on ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  479. { "is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  480. { "hy" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  481. { "ph" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  482. { "en" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  483. { "a-" , 20, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT },
  484. { "ti" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  485. { "on" , 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  486. { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  487. };
  488. // clang-format on
  489. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  490. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  491. << " vs " << std::endl
  492. << toString(textBuf, actual);
  493. }
  494. {
  495. constexpr float LINE_WIDTH = 10;
  496. // clang-format off
  497. std::vector<LineBreakExpectation> expect = {
  498. { "H" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  499. { "y" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  500. { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  501. { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  502. { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  503. { "n" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  504. { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  505. { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  506. { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  507. { "o" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  508. { "n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  509. { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  510. { "s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  511. { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  512. { "y" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  513. { "p" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  514. { "h" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  515. { "e" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  516. { "n" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  517. { "a" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  518. { "t" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  519. { "i" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  520. { "o" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  521. { "n" , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  522. { "." , 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT },
  523. };
  524. // clang-format on
  525. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  526. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  527. << " vs " << std::endl
  528. << toString(textBuf, actual);
  529. }
  530. }
  531. TEST_F(GreedyLineBreakerTest, testHyphenationStartLineChange) {
  532. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  533. // "hyphenation" is hyphnated to "hy-phen-a-tion".
  534. const std::vector<uint16_t> textBuf = utf8ToUtf16("czerwono-niebieska");
  535. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  536. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  537. constexpr StartHyphenEdit START_HYPHEN = StartHyphenEdit::INSERT_HYPHEN;
  538. // Note that disable clang-format everywhere since aligned expectation is more readable.
  539. {
  540. constexpr float LINE_WIDTH = 1000;
  541. std::vector<LineBreakExpectation> expect = {
  542. {"czerwono-niebieska", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  543. };
  544. const auto actual = doLineBreak(textBuf, DO_HYPHEN, "pl", LINE_WIDTH);
  545. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  546. << " vs " << std::endl
  547. << toString(textBuf, actual);
  548. }
  549. {
  550. constexpr float LINE_WIDTH = 180;
  551. std::vector<LineBreakExpectation> expect = {
  552. {"czerwono-niebieska", 180, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  553. };
  554. const auto actual = doLineBreak(textBuf, DO_HYPHEN, "pl", LINE_WIDTH);
  555. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  556. << " vs " << std::endl
  557. << toString(textBuf, actual);
  558. }
  559. {
  560. constexpr float LINE_WIDTH = 130;
  561. // clang-format off
  562. std::vector<LineBreakExpectation> expect = {
  563. {"czerwono-" , 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  564. {"-niebieska", 100, START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  565. };
  566. // clang-format on
  567. const auto actual = doLineBreak(textBuf, DO_HYPHEN, "pl", LINE_WIDTH);
  568. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  569. << " vs " << std::endl
  570. << toString(textBuf, actual);
  571. }
  572. }
  573. TEST_F(GreedyLineBreakerTest, testZeroWidthLine) {
  574. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  575. constexpr float LINE_WIDTH = 0;
  576. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  577. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  578. {
  579. const auto textBuf = utf8ToUtf16("");
  580. std::vector<LineBreakExpectation> expect = {};
  581. const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
  582. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  583. << " vs " << std::endl
  584. << toString(textBuf, actual);
  585. }
  586. {
  587. const auto textBuf = utf8ToUtf16("A");
  588. std::vector<LineBreakExpectation> expect = {
  589. {"A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  590. };
  591. const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
  592. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  593. << " vs " << std::endl
  594. << toString(textBuf, actual);
  595. }
  596. {
  597. const auto textBuf = utf8ToUtf16("AB");
  598. std::vector<LineBreakExpectation> expect = {
  599. {"A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  600. {"B", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  601. };
  602. const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
  603. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  604. << " vs " << std::endl
  605. << toString(textBuf, actual);
  606. }
  607. }
  608. TEST_F(GreedyLineBreakerTest, testZeroWidthCharacter) {
  609. constexpr float CHAR_WIDTH = 0.0;
  610. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  611. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  612. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  613. {
  614. constexpr float LINE_WIDTH = 1.0;
  615. const auto textBuf = utf8ToUtf16("This is an example text.");
  616. std::vector<LineBreakExpectation> expect = {
  617. {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  618. };
  619. MeasuredTextBuilder builder;
  620. builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  621. DESCENT);
  622. std::unique_ptr<MeasuredText> measuredText =
  623. builder.build(textBuf, false /* compute hyphenation */,
  624. false /* compute full layout */, nullptr /* no hint */);
  625. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  626. TabStops tabStops(nullptr, 0, 10);
  627. const auto actual =
  628. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  629. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  630. << " vs " << std::endl
  631. << toString(textBuf, actual);
  632. }
  633. {
  634. constexpr float LINE_WIDTH = 0.0;
  635. const auto textBuf = utf8ToUtf16("This is an example text.");
  636. std::vector<LineBreakExpectation> expect = {
  637. {"This is an example text.", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  638. };
  639. MeasuredTextBuilder builder;
  640. builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  641. DESCENT);
  642. std::unique_ptr<MeasuredText> measuredText =
  643. builder.build(textBuf, false /* compute hyphenation */,
  644. false /* compute full layout */, nullptr /* no hint */);
  645. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  646. TabStops tabStops(nullptr, 0, 10);
  647. const auto actual =
  648. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  649. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  650. << " vs " << std::endl
  651. << toString(textBuf, actual);
  652. }
  653. }
  654. TEST_F(GreedyLineBreakerTest, testLocaleSwitchTest) {
  655. constexpr float CHAR_WIDTH = 10.0;
  656. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  657. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  658. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  659. constexpr float LINE_WIDTH = 240;
  660. const auto textBuf = utf8ToUtf16("This is an example text.");
  661. {
  662. std::vector<LineBreakExpectation> expect = {
  663. {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  664. };
  665. MeasuredTextBuilder builder;
  666. builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  667. builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  668. DESCENT);
  669. std::unique_ptr<MeasuredText> measuredText =
  670. builder.build(textBuf, false /* compute hyphenation */,
  671. false /* compute full layout */, nullptr /* no hint */);
  672. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  673. TabStops tabStops(nullptr, 0, 0);
  674. const auto actual =
  675. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  676. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  677. << " vs " << std::endl
  678. << toString(textBuf, actual);
  679. }
  680. {
  681. std::vector<LineBreakExpectation> expect = {
  682. {"This is an example text.", 240, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  683. };
  684. MeasuredTextBuilder builder;
  685. builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  686. builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
  687. DESCENT);
  688. std::unique_ptr<MeasuredText> measuredText =
  689. builder.build(textBuf, false /* compute hyphenation */,
  690. false /* compute full layout */, nullptr /* no hint */);
  691. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  692. TabStops tabStops(nullptr, 0, 0);
  693. const auto actual =
  694. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  695. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  696. << " vs " << std::endl
  697. << toString(textBuf, actual);
  698. }
  699. }
  700. TEST_F(GreedyLineBreakerTest, testEmailOrUrl) {
  701. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  702. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  703. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  704. {
  705. constexpr float LINE_WIDTH = 240;
  706. const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
  707. std::vector<LineBreakExpectation> expect = {
  708. {"This is an url: ", 150, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  709. {"http://a.b", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  710. };
  711. const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
  712. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  713. << " vs " << std::endl
  714. << toString(textBuf, actual);
  715. }
  716. {
  717. constexpr float LINE_WIDTH = 240;
  718. const auto textBuf = utf8ToUtf16("This is an email: [email protected]");
  719. std::vector<LineBreakExpectation> expect = {
  720. {"This is an email: ", 170, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  721. {"[email protected]", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  722. };
  723. const auto actual = doLineBreak(textBuf, DO_HYPHEN, LINE_WIDTH);
  724. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  725. << " vs " << std::endl
  726. << toString(textBuf, actual);
  727. }
  728. }
  729. TEST_F(GreedyLineBreakerTest, testLocaleSwitch_InEmailOrUrl) {
  730. constexpr float CHAR_WIDTH = 10.0;
  731. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  732. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  733. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  734. constexpr float LINE_WIDTH = 240;
  735. {
  736. const auto textBuf = utf8ToUtf16("This is an url: http://a.b");
  737. std::vector<LineBreakExpectation> expect = {
  738. {"This is an url: ", 150, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  739. {"http://a.b", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  740. };
  741. MeasuredTextBuilder builder;
  742. builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  743. builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
  744. DESCENT);
  745. std::unique_ptr<MeasuredText> measuredText =
  746. builder.build(textBuf, false /* compute hyphenation */,
  747. false /* compute full layout */, nullptr /* no hint */);
  748. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  749. TabStops tabStops(nullptr, 0, 0);
  750. const auto actual =
  751. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  752. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  753. << " vs " << std::endl
  754. << toString(textBuf, actual);
  755. }
  756. {
  757. const auto textBuf = utf8ToUtf16("This is an email: [email protected]");
  758. std::vector<LineBreakExpectation> expect = {
  759. {"This is an email: ", 170, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  760. {"[email protected]", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  761. };
  762. MeasuredTextBuilder builder;
  763. builder.addCustomRun<ConstantRun>(Range(0, 18), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  764. builder.addCustomRun<ConstantRun>(Range(18, textBuf.size()), "fr-FR", CHAR_WIDTH, ASCENT,
  765. DESCENT);
  766. std::unique_ptr<MeasuredText> measuredText =
  767. builder.build(textBuf, false /* compute hyphenation */,
  768. false /* compute full layout */, nullptr /* no hint */);
  769. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  770. TabStops tabStops(nullptr, 0, 0);
  771. const auto actual =
  772. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  773. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  774. << " vs " << std::endl
  775. << toString(textBuf, actual);
  776. }
  777. }
  778. // b/68669534
  779. TEST_F(GreedyLineBreakerTest, CrashFix_Space_Tab) {
  780. constexpr float CHAR_WIDTH = 10.0;
  781. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  782. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  783. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  784. {
  785. constexpr float LINE_WIDTH = 50;
  786. const auto textBuf = utf8ToUtf16("a \tb");
  787. std::vector<LineBreakExpectation> expect = {
  788. {"a \tb", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  789. };
  790. MeasuredTextBuilder builder;
  791. builder.addCustomRun<ConstantRun>(Range(0, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  792. DESCENT);
  793. std::unique_ptr<MeasuredText> measuredText =
  794. builder.build(textBuf, false /* compute hyphenation */,
  795. false /* compute full layout */, nullptr /* no hint */);
  796. RectangleLineWidth rectangleLineWidth(LINE_WIDTH);
  797. TabStops tabStops(nullptr, 0, CHAR_WIDTH);
  798. const auto actual =
  799. breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  800. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  801. << " vs " << std::endl
  802. << toString(textBuf, actual);
  803. }
  804. }
  805. TEST_F(GreedyLineBreakerTest, ExtentTest) {
  806. constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
  807. const std::vector<uint16_t> textBuf = utf8ToUtf16("The \u3042\u3044\u3046 is Japanese.");
  808. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  809. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  810. {
  811. constexpr float LINE_WIDTH = 1000;
  812. std::vector<LineBreakExpectation> expect = {
  813. {"The \u3042\u3044\u3046 is Japanese.", 200, NO_START_HYPHEN, NO_END_HYPHEN,
  814. CUSTOM_ASCENT, CUSTOM_DESCENT},
  815. };
  816. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  817. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  818. << " vs " << std::endl
  819. << toString(textBuf, actual);
  820. }
  821. {
  822. constexpr float LINE_WIDTH = 200;
  823. std::vector<LineBreakExpectation> expect = {
  824. {"The \u3042\u3044\u3046 is Japanese.", 200, NO_START_HYPHEN, NO_END_HYPHEN,
  825. CUSTOM_ASCENT, CUSTOM_DESCENT},
  826. };
  827. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  828. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  829. << " vs " << std::endl
  830. << toString(textBuf, actual);
  831. }
  832. {
  833. constexpr float LINE_WIDTH = 190;
  834. std::vector<LineBreakExpectation> expect = {
  835. {"The \u3042\u3044\u3046 is ", 100, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
  836. CUSTOM_DESCENT},
  837. {"Japanese.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  838. };
  839. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  840. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  841. << " vs " << std::endl
  842. << toString(textBuf, actual);
  843. }
  844. {
  845. constexpr float LINE_WIDTH = 90;
  846. std::vector<LineBreakExpectation> expect = {
  847. {"The \u3042\u3044\u3046 ", 70, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
  848. CUSTOM_DESCENT},
  849. {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  850. {"Japanese.", 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  851. };
  852. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  853. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  854. << " vs " << std::endl
  855. << toString(textBuf, actual);
  856. }
  857. {
  858. constexpr float LINE_WIDTH = 50;
  859. std::vector<LineBreakExpectation> expect = {
  860. {"The \u3042", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
  861. {"\u3044\u3046 is ", 50, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
  862. CUSTOM_DESCENT},
  863. {"Japan", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  864. {"ese.", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  865. };
  866. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  867. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  868. << " vs " << std::endl
  869. << toString(textBuf, actual);
  870. }
  871. {
  872. constexpr float LINE_WIDTH = 40;
  873. std::vector<LineBreakExpectation> expect = {
  874. {"The ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  875. {"\u3042\u3044\u3046 ", 30, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT,
  876. CUSTOM_DESCENT},
  877. {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  878. {"Japa", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  879. {"nese", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  880. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  881. };
  882. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  883. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  884. << " vs " << std::endl
  885. << toString(textBuf, actual);
  886. }
  887. {
  888. constexpr float LINE_WIDTH = 20;
  889. std::vector<LineBreakExpectation> expect = {
  890. {"Th", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  891. {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  892. {"\u3042\u3044", 20, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
  893. {"\u3046 ", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
  894. {"is ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  895. {"Ja", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  896. {"pa", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  897. {"ne", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  898. {"se", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  899. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  900. };
  901. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  902. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  903. << " vs " << std::endl
  904. << toString(textBuf, actual);
  905. }
  906. {
  907. constexpr float LINE_WIDTH = 10;
  908. std::vector<LineBreakExpectation> expect = {
  909. {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  910. {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  911. {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  912. {"\u3042", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
  913. {"\u3044", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
  914. {"\u3046 ", 10, NO_START_HYPHEN, NO_END_HYPHEN, CUSTOM_ASCENT, CUSTOM_DESCENT},
  915. {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  916. {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  917. {"J", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  918. {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  919. {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  920. {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  921. {"n", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  922. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  923. {"s", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  924. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  925. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  926. };
  927. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  928. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  929. << " vs " << std::endl
  930. << toString(textBuf, actual);
  931. }
  932. }
  933. TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_SingleChar) {
  934. constexpr float CHAR_WIDTH = 10.0;
  935. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  936. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  937. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  938. const auto textBuf = utf8ToUtf16("This is an example \u2639 text.");
  939. // In this test case, assign a replacement run for "U+2639" with 5 times of CHAR_WIDTH.
  940. auto doLineBreak = [=](float width) {
  941. MeasuredTextBuilder builder;
  942. builder.addCustomRun<ConstantRun>(Range(0, 19), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  943. builder.addReplacementRun(19, 20, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
  944. builder.addCustomRun<ConstantRun>(Range(20, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  945. DESCENT);
  946. std::unique_ptr<MeasuredText> measuredText =
  947. builder.build(textBuf, false /* compute hyphenation */,
  948. false /* compute full layout */, nullptr /* no hint */);
  949. RectangleLineWidth rectangleLineWidth(width);
  950. TabStops tabStops(nullptr, 0, 0);
  951. return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  952. };
  953. {
  954. constexpr float LINE_WIDTH = 100;
  955. // "is an" is a single replacement span. Do not break.
  956. // clang-format off
  957. std::vector<LineBreakExpectation> expect = {
  958. {"This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  959. {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  960. {"\u2639 ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  961. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  962. };
  963. // clang-format on
  964. const auto actual = doLineBreak(LINE_WIDTH);
  965. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  966. << " vs " << std::endl
  967. << toString(textBuf, actual);
  968. }
  969. {
  970. constexpr float LINE_WIDTH = 90;
  971. // "is an" is a single replacement span. Do not break.
  972. // clang-format off
  973. std::vector<LineBreakExpectation> expect = {
  974. {"This is ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  975. {"an ", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  976. {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  977. {"\u2639 ", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  978. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  979. };
  980. // clang-format on
  981. const auto actual = doLineBreak(LINE_WIDTH);
  982. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  983. << " vs " << std::endl
  984. << toString(textBuf, actual);
  985. }
  986. {
  987. constexpr float LINE_WIDTH = 10;
  988. // "is an" is a single replacement span. Do not break.
  989. // clang-format off
  990. std::vector<LineBreakExpectation> expect = {
  991. {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  992. {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  993. {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  994. {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  995. {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  996. {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  997. {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  998. {"n ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  999. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1000. {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1001. {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1002. {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1003. {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1004. {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1005. {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1006. // TODO: This should be "\u2639 " since should not count the trailing line end space
  1007. {"\u2639", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1008. {" ", 0, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1009. {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1010. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1011. {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1012. {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1013. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1014. };
  1015. // clang-format on
  1016. const auto actual = doLineBreak(LINE_WIDTH);
  1017. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1018. << " vs " << std::endl
  1019. << toString(textBuf, actual);
  1020. }
  1021. }
  1022. TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_MultipleChars) {
  1023. constexpr float CHAR_WIDTH = 10.0;
  1024. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  1025. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  1026. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  1027. const auto textBuf = utf8ToUtf16("This is an example text.");
  1028. // In this test case, assign a replacement run for "is an " with 5 times of CHAR_WIDTH.
  1029. auto doLineBreak = [=](float width) {
  1030. MeasuredTextBuilder builder;
  1031. builder.addCustomRun<ConstantRun>(Range(0, 5), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  1032. builder.addReplacementRun(5, 11, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
  1033. builder.addCustomRun<ConstantRun>(Range(11, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  1034. DESCENT);
  1035. std::unique_ptr<MeasuredText> measuredText =
  1036. builder.build(textBuf, false /* compute hyphenation */,
  1037. false /* compute full layout */, nullptr /* no hint */);
  1038. RectangleLineWidth rectangleLineWidth(width);
  1039. TabStops tabStops(nullptr, 0, 0);
  1040. return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  1041. };
  1042. {
  1043. constexpr float LINE_WIDTH = 100;
  1044. // "is an" is a single replacement span. Do not break.
  1045. // clang-format off
  1046. std::vector<LineBreakExpectation> expect = {
  1047. {"This is an ", 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1048. {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1049. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1050. };
  1051. // clang-format on
  1052. const auto actual = doLineBreak(LINE_WIDTH);
  1053. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1054. << " vs " << std::endl
  1055. << toString(textBuf, actual);
  1056. }
  1057. {
  1058. constexpr float LINE_WIDTH = 90;
  1059. // "is an" is a single replacement span. Do not break.
  1060. // clang-format off
  1061. std::vector<LineBreakExpectation> expect = {
  1062. {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1063. {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1064. {"example ",70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1065. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1066. };
  1067. // clang-format on
  1068. const auto actual = doLineBreak(LINE_WIDTH);
  1069. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1070. << " vs " << std::endl
  1071. << toString(textBuf, actual);
  1072. }
  1073. {
  1074. constexpr float LINE_WIDTH = 10;
  1075. // "is an" is a single replacement span. Do not break.
  1076. // clang-format off
  1077. std::vector<LineBreakExpectation> expect = {
  1078. {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1079. {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1080. {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1081. {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1082. {"is an ", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1083. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1084. {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1085. {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1086. {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1087. {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1088. {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1089. {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1090. {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1091. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1092. {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1093. {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1094. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1095. };
  1096. // clang-format on
  1097. const auto actual = doLineBreak(LINE_WIDTH);
  1098. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1099. << " vs " << std::endl
  1100. << toString(textBuf, actual);
  1101. }
  1102. }
  1103. TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_CJK) {
  1104. constexpr float CHAR_WIDTH = 10.0;
  1105. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  1106. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  1107. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  1108. // Example string: "Today is a sunny day." in Japanese.
  1109. const auto textBuf = utf8ToUtf16("\u672C\u65E5\u306F\u6674\u5929\u306A\u308A");
  1110. // In this test case, assign a replacement run for "\u6674\u5929" with 5 times of CHAR_WIDTH.
  1111. auto doLineBreak = [=](float width) {
  1112. MeasuredTextBuilder builder;
  1113. builder.addCustomRun<ConstantRun>(Range(0, 3), "ja-JP", CHAR_WIDTH, ASCENT, DESCENT);
  1114. builder.addReplacementRun(3, 5, 5 * CHAR_WIDTH, LocaleListCache::getId("ja-JP"));
  1115. builder.addCustomRun<ConstantRun>(Range(5, textBuf.size()), "ja-JP", CHAR_WIDTH, ASCENT,
  1116. DESCENT);
  1117. std::unique_ptr<MeasuredText> measuredText =
  1118. builder.build(textBuf, false /* compute hyphenation */,
  1119. false /* compute full layout */, nullptr /* no hint */);
  1120. RectangleLineWidth rectangleLineWidth(width);
  1121. TabStops tabStops(nullptr, 0, 0);
  1122. return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  1123. };
  1124. {
  1125. constexpr float LINE_WIDTH = 100;
  1126. // "\u6674\u5929" is a single replacement span. Do not break.
  1127. // clang-format off
  1128. std::vector<LineBreakExpectation> expect = {
  1129. {"\u672C\u65E5\u306F\u6674\u5929\u306A\u308A",
  1130. 100, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1131. };
  1132. // clang-format on
  1133. const auto actual = doLineBreak(LINE_WIDTH);
  1134. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1135. << " vs " << std::endl
  1136. << toString(textBuf, actual);
  1137. }
  1138. {
  1139. constexpr float LINE_WIDTH = 90;
  1140. // "\u6674\u5929" is a single replacement span. Do not break.
  1141. // clang-format off
  1142. std::vector<LineBreakExpectation> expect = {
  1143. {"\u672C\u65E5\u306F\u6674\u5929\u306A",
  1144. 90, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1145. {"\u308A",
  1146. 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1147. };
  1148. // clang-format on
  1149. const auto actual = doLineBreak(LINE_WIDTH);
  1150. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1151. << " vs " << std::endl
  1152. << toString(textBuf, actual);
  1153. }
  1154. {
  1155. constexpr float LINE_WIDTH = 80;
  1156. // "\u6674\u5929" is a single replacement span. Do not break.
  1157. // clang-format off
  1158. std::vector<LineBreakExpectation> expect = {
  1159. {"\u672C\u65E5\u306F\u6674\u5929",
  1160. 80, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1161. {"\u306A\u308A",
  1162. 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1163. };
  1164. // clang-format on
  1165. const auto actual = doLineBreak(LINE_WIDTH);
  1166. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1167. << " vs " << std::endl
  1168. << toString(textBuf, actual);
  1169. }
  1170. {
  1171. constexpr float LINE_WIDTH = 70;
  1172. // "\u6674\u5929" is a single replacement span. Do not break.
  1173. // clang-format off
  1174. std::vector<LineBreakExpectation> expect = {
  1175. {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1176. {"\u6674\u5929\u306A\u308A", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1177. };
  1178. // clang-format on
  1179. const auto actual = doLineBreak(LINE_WIDTH);
  1180. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1181. << " vs " << std::endl
  1182. << toString(textBuf, actual);
  1183. }
  1184. {
  1185. constexpr float LINE_WIDTH = 60;
  1186. // "\u6674\u5929" is a single replacement span. Do not break.
  1187. // clang-format off
  1188. std::vector<LineBreakExpectation> expect = {
  1189. {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1190. {"\u6674\u5929\u306A", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1191. {"\u308A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1192. };
  1193. // clang-format on
  1194. const auto actual = doLineBreak(LINE_WIDTH);
  1195. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1196. << " vs " << std::endl
  1197. << toString(textBuf, actual);
  1198. }
  1199. {
  1200. constexpr float LINE_WIDTH = 50;
  1201. // "\u6674\u5929" is a single replacement span. Do not break.
  1202. // clang-format off
  1203. std::vector<LineBreakExpectation> expect = {
  1204. {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1205. {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1206. {"\u306A\u308A", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1207. };
  1208. // clang-format on
  1209. const auto actual = doLineBreak(LINE_WIDTH);
  1210. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1211. << " vs " << std::endl
  1212. << toString(textBuf, actual);
  1213. }
  1214. {
  1215. constexpr float LINE_WIDTH = 40;
  1216. // "\u6674\u5929" is a single replacement span. Do not break.
  1217. // clang-format off
  1218. std::vector<LineBreakExpectation> expect = {
  1219. {"\u672C\u65E5\u306F", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1220. {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1221. {"\u306A\u308A", 20, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1222. };
  1223. // clang-format on
  1224. const auto actual = doLineBreak(LINE_WIDTH);
  1225. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1226. << " vs " << std::endl
  1227. << toString(textBuf, actual);
  1228. }
  1229. {
  1230. constexpr float LINE_WIDTH = 10;
  1231. // "\u6674\u5929" is a single replacement span. Do not break.
  1232. // clang-format off
  1233. std::vector<LineBreakExpectation> expect = {
  1234. {"\u672C", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1235. {"\u65E5", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1236. {"\u306F", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1237. {"\u6674\u5929", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1238. {"\u306A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1239. {"\u308A", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1240. };
  1241. // clang-format on
  1242. const auto actual = doLineBreak(LINE_WIDTH);
  1243. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1244. << " vs " << std::endl
  1245. << toString(textBuf, actual);
  1246. }
  1247. }
  1248. TEST_F(GreedyLineBreakerTest, testReplacementSpanNotBreakTest_with_punctuation) {
  1249. constexpr float CHAR_WIDTH = 10.0;
  1250. constexpr bool DO_HYPHEN = true; // Do hyphenation in this test case.
  1251. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  1252. constexpr EndHyphenEdit END_HYPHEN = EndHyphenEdit::INSERT_HYPHEN;
  1253. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  1254. const auto textBuf = utf8ToUtf16("This (is an) example text.");
  1255. // In this test case, assign a replacement run for "U+2639" with 5 times of CHAR_WIDTH.
  1256. auto doLineBreak = [=](float width) {
  1257. MeasuredTextBuilder builder;
  1258. builder.addCustomRun<ConstantRun>(Range(0, 6), "en-US", CHAR_WIDTH, ASCENT, DESCENT);
  1259. builder.addReplacementRun(6, 11, 5 * CHAR_WIDTH, LocaleListCache::getId("en-US"));
  1260. builder.addCustomRun<ConstantRun>(Range(11, textBuf.size()), "en-US", CHAR_WIDTH, ASCENT,
  1261. DESCENT);
  1262. std::unique_ptr<MeasuredText> measuredText =
  1263. builder.build(textBuf, false /* compute hyphenation */,
  1264. false /* compute full layout */, nullptr /* no hint */);
  1265. RectangleLineWidth rectangleLineWidth(width);
  1266. TabStops tabStops(nullptr, 0, 0);
  1267. return breakLineGreedy(textBuf, *measuredText, rectangleLineWidth, tabStops, DO_HYPHEN);
  1268. };
  1269. {
  1270. constexpr float LINE_WIDTH = 1000;
  1271. // "is an" is a single replacement span. Do not break.
  1272. // clang-format off
  1273. std::vector<LineBreakExpectation> expect = {
  1274. {"This (is an) example text.",
  1275. 260, 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. constexpr float LINE_WIDTH = 250;
  1285. // "is an" is a single replacement span. Do not break.
  1286. // clang-format off
  1287. std::vector<LineBreakExpectation> expect = {
  1288. {"This (is an) example ", 200, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1289. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1290. };
  1291. // clang-format on
  1292. const auto actual = doLineBreak(LINE_WIDTH);
  1293. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1294. << " vs " << std::endl
  1295. << toString(textBuf, actual);
  1296. }
  1297. {
  1298. constexpr float LINE_WIDTH = 190;
  1299. // "is an" is a single replacement span. Do not break.
  1300. // clang-format off
  1301. std::vector<LineBreakExpectation> expect = {
  1302. {"This (is an) ", 120, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1303. {"example text.", 130, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1304. };
  1305. // clang-format on
  1306. const auto actual = doLineBreak(LINE_WIDTH);
  1307. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1308. << " vs " << std::endl
  1309. << toString(textBuf, actual);
  1310. }
  1311. {
  1312. constexpr float LINE_WIDTH = 120;
  1313. // "is an" is a single replacement span. Do not break.
  1314. // clang-format off
  1315. std::vector<LineBreakExpectation> expect = {
  1316. {"This (is an) ", 120, 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 = 110;
  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) ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  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 = 60;
  1344. // "is an" is a single replacement span. Do not break.
  1345. // clang-format off
  1346. std::vector<LineBreakExpectation> expect = {
  1347. {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1348. {"(is an", 60, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1349. {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1350. {"exam-", 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
  1351. {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1352. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1353. };
  1354. // clang-format on
  1355. const auto actual = doLineBreak(LINE_WIDTH);
  1356. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1357. << " vs " << std::endl
  1358. << toString(textBuf, actual);
  1359. }
  1360. {
  1361. constexpr float LINE_WIDTH = 50;
  1362. // "is an" is a single replacement span. Do not break.
  1363. // clang-format off
  1364. std::vector<LineBreakExpectation> expect = {
  1365. {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1366. {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1367. {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1368. {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1369. {"exam-", 50, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
  1370. {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1371. {"text.", 50, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1372. };
  1373. // clang-format on
  1374. const auto actual = doLineBreak(LINE_WIDTH);
  1375. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1376. << " vs " << std::endl
  1377. << toString(textBuf, actual);
  1378. }
  1379. {
  1380. constexpr float LINE_WIDTH = 40;
  1381. // "is an" is a single replacement span. Do not break.
  1382. // clang-format off
  1383. std::vector<LineBreakExpectation> expect = {
  1384. {"This ", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1385. {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1386. {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1387. {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1388. {"ex-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
  1389. {"am-", 30, NO_START_HYPHEN, END_HYPHEN, ASCENT, DESCENT},
  1390. {"ple ", 30, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1391. {"text", 40, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1392. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1393. };
  1394. // clang-format on
  1395. const auto actual = doLineBreak(LINE_WIDTH);
  1396. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1397. << " vs " << std::endl
  1398. << toString(textBuf, actual);
  1399. }
  1400. {
  1401. constexpr float LINE_WIDTH = 10;
  1402. // "is an" is a single replacement span. Do not break.
  1403. // clang-format off
  1404. std::vector<LineBreakExpectation> expect = {
  1405. {"T", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1406. {"h", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1407. {"i", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1408. {"s ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1409. {"(", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1410. {"is an", 50, NO_START_HYPHEN, NO_END_HYPHEN, 0, 0},
  1411. {") ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1412. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1413. {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1414. {"a", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1415. {"m", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1416. {"p", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1417. {"l", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1418. {"e ", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1419. {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1420. {"e", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1421. {"x", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1422. {"t", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1423. {".", 10, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1424. };
  1425. // clang-format on
  1426. const auto actual = doLineBreak(LINE_WIDTH);
  1427. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1428. << " vs " << std::endl
  1429. << toString(textBuf, actual);
  1430. }
  1431. }
  1432. TEST_F(GreedyLineBreakerTest, testControllCharAfterSpace) {
  1433. constexpr bool NO_HYPHEN = false; // No hyphenation in this test case.
  1434. const std::vector<uint16_t> textBuf = utf8ToUtf16("example \u2066example");
  1435. constexpr StartHyphenEdit NO_START_HYPHEN = StartHyphenEdit::NO_EDIT;
  1436. constexpr EndHyphenEdit NO_END_HYPHEN = EndHyphenEdit::NO_EDIT;
  1437. {
  1438. constexpr float LINE_WIDTH = 90;
  1439. std::vector<LineBreakExpectation> expect = {
  1440. {"example ", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1441. {"\u2066example", 70, NO_START_HYPHEN, NO_END_HYPHEN, ASCENT, DESCENT},
  1442. };
  1443. const auto actual = doLineBreak(textBuf, NO_HYPHEN, LINE_WIDTH);
  1444. EXPECT_TRUE(sameLineBreak(expect, actual)) << toString(expect) << std::endl
  1445. << " vs " << std::endl
  1446. << toString(textBuf, actual);
  1447. }
  1448. }
  1449. } // namespace
  1450. } // namespace minikin