OptimalLineBreakerTest.cpp 111 KB

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