OLD | NEW |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | 1 // Copyright 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "platform/fonts/shaping/ShapingLineBreaker.h" | 5 #include "platform/fonts/shaping/ShapingLineBreaker.h" |
6 | 6 |
7 #include <unicode/uscript.h> | 7 #include <unicode/uscript.h> |
8 #include "platform/fonts/Font.h" | 8 #include "platform/fonts/Font.h" |
9 #include "platform/fonts/FontCache.h" | 9 #include "platform/fonts/FontCache.h" |
10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" | 10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" |
(...skipping 26 matching lines...) Expand all Loading... |
37 static inline String To16Bit(const char* text, unsigned length) { | 37 static inline String To16Bit(const char* text, unsigned length) { |
38 return String::Make16BitFrom8BitSource(reinterpret_cast<const LChar*>(text), | 38 return String::Make16BitFrom8BitSource(reinterpret_cast<const LChar*>(text), |
39 length); | 39 length); |
40 } | 40 } |
41 | 41 |
42 TEST_F(ShapingLineBreakerTest, ShapeLineLatin) { | 42 TEST_F(ShapingLineBreakerTest, ShapeLineLatin) { |
43 String string = To16Bit( | 43 String string = To16Bit( |
44 "Test run with multiple words and breaking " | 44 "Test run with multiple words and breaking " |
45 "opportunities.", | 45 "opportunities.", |
46 56); | 46 56); |
47 const AtomicString locale = "en-US"; | 47 LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal); |
48 TextDirection direction = TextDirection::kLtr; | 48 TextDirection direction = TextDirection::kLtr; |
49 LineBreakType break_type = LineBreakType::kNormal; | |
50 | 49 |
51 HarfBuzzShaper shaper(string.Characters16(), 56); | 50 HarfBuzzShaper shaper(string.Characters16(), 56); |
52 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); | 51 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); |
53 | 52 |
54 // "Test run with multiple" | 53 // "Test run with multiple" |
55 RefPtr<ShapeResult> first4 = shaper.Shape(&font, direction, 0, 22); | 54 RefPtr<ShapeResult> first4 = shaper.Shape(&font, direction, 0, 22); |
56 ASSERT_LT(first4->SnappedWidth(), result->SnappedWidth()); | 55 ASSERT_LT(first4->SnappedWidth(), result->SnappedWidth()); |
57 | 56 |
58 // "Test run with" | 57 // "Test run with" |
59 RefPtr<ShapeResult> first3 = shaper.Shape(&font, direction, 0, 13); | 58 RefPtr<ShapeResult> first3 = shaper.Shape(&font, direction, 0, 13); |
60 ASSERT_LT(first3->SnappedWidth(), first4->SnappedWidth()); | 59 ASSERT_LT(first3->SnappedWidth(), first4->SnappedWidth()); |
61 | 60 |
62 // "Test run" | 61 // "Test run" |
63 RefPtr<ShapeResult> first2 = shaper.Shape(&font, direction, 0, 8); | 62 RefPtr<ShapeResult> first2 = shaper.Shape(&font, direction, 0, 8); |
64 ASSERT_LT(first2->SnappedWidth(), first3->SnappedWidth()); | 63 ASSERT_LT(first2->SnappedWidth(), first3->SnappedWidth()); |
65 | 64 |
66 // "Test" | 65 // "Test" |
67 RefPtr<ShapeResult> first1 = shaper.Shape(&font, direction, 0, 4); | 66 RefPtr<ShapeResult> first1 = shaper.Shape(&font, direction, 0, 4); |
68 ASSERT_LT(first1->SnappedWidth(), first2->SnappedWidth()); | 67 ASSERT_LT(first1->SnappedWidth(), first2->SnappedWidth()); |
69 | 68 |
70 ShapingLineBreaker breaker(&shaper, &font, result.Get(), locale, break_type); | 69 ShapingLineBreaker breaker(&shaper, &font, result.Get(), &break_iterator); |
71 RefPtr<ShapeResult> line; | 70 RefPtr<ShapeResult> line; |
72 unsigned break_offset = 0; | 71 unsigned break_offset = 0; |
73 | 72 |
74 // Test the case where the entire string fits. | 73 // Test the case where the entire string fits. |
75 line = breaker.ShapeLine(0, result->SnappedWidth(), &break_offset); | 74 line = breaker.ShapeLine(0, result->SnappedWidth(), &break_offset); |
76 EXPECT_EQ(56u, break_offset); // After the end of the string. | 75 EXPECT_EQ(56u, break_offset); // After the end of the string. |
77 EXPECT_EQ(result->SnappedWidth(), line->SnappedWidth()); | 76 EXPECT_EQ(result->SnappedWidth(), line->SnappedWidth()); |
78 | 77 |
79 // Test cases where we break between words. | 78 // Test cases where we break between words. |
80 line = breaker.ShapeLine(0, first4->SnappedWidth(), &break_offset); | 79 line = breaker.ShapeLine(0, first4->SnappedWidth(), &break_offset); |
(...skipping 29 matching lines...) Expand all Loading... |
110 EXPECT_EQ(first1->SnappedWidth(), line->SnappedWidth()); | 109 EXPECT_EQ(first1->SnappedWidth(), line->SnappedWidth()); |
111 | 110 |
112 // Test the case where we cannot break earlier. | 111 // Test the case where we cannot break earlier. |
113 line = breaker.ShapeLine(0, first1->SnappedWidth() - 1, &break_offset); | 112 line = breaker.ShapeLine(0, first1->SnappedWidth() - 1, &break_offset); |
114 EXPECT_EQ(4u, break_offset); // Between "Test" and "run" | 113 EXPECT_EQ(4u, break_offset); // Between "Test" and "run" |
115 EXPECT_EQ(first1->SnappedWidth(), line->SnappedWidth()); | 114 EXPECT_EQ(first1->SnappedWidth(), line->SnappedWidth()); |
116 } | 115 } |
117 | 116 |
118 TEST_F(ShapingLineBreakerTest, ShapeLineLatinMultiLine) { | 117 TEST_F(ShapingLineBreakerTest, ShapeLineLatinMultiLine) { |
119 String string = To16Bit("Line breaking test case.", 24); | 118 String string = To16Bit("Line breaking test case.", 24); |
120 const AtomicString locale = "en-US"; | 119 LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal); |
121 TextDirection direction = TextDirection::kLtr; | 120 TextDirection direction = TextDirection::kLtr; |
122 LineBreakType break_type = LineBreakType::kNormal; | |
123 | 121 |
124 HarfBuzzShaper shaper(string.Characters16(), 24); | 122 HarfBuzzShaper shaper(string.Characters16(), 24); |
125 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); | 123 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); |
126 RefPtr<ShapeResult> first = shaper.Shape(&font, direction, 0, 4); | 124 RefPtr<ShapeResult> first = shaper.Shape(&font, direction, 0, 4); |
127 RefPtr<ShapeResult> mid_third = shaper.Shape(&font, direction, 0, 16); | 125 RefPtr<ShapeResult> mid_third = shaper.Shape(&font, direction, 0, 16); |
128 | 126 |
129 ShapingLineBreaker breaker(&shaper, &font, result.Get(), locale, break_type); | 127 ShapingLineBreaker breaker(&shaper, &font, result.Get(), &break_iterator); |
130 unsigned break_offset = 0; | 128 unsigned break_offset = 0; |
131 | 129 |
132 breaker.ShapeLine(0, result->SnappedWidth() - 1, &break_offset); | 130 breaker.ShapeLine(0, result->SnappedWidth() - 1, &break_offset); |
133 EXPECT_EQ(18u, break_offset); | 131 EXPECT_EQ(18u, break_offset); |
134 | 132 |
135 breaker.ShapeLine(0, first->SnappedWidth(), &break_offset); | 133 breaker.ShapeLine(0, first->SnappedWidth(), &break_offset); |
136 EXPECT_EQ(4u, break_offset); | 134 EXPECT_EQ(4u, break_offset); |
137 | 135 |
138 breaker.ShapeLine(0, mid_third->SnappedWidth(), &break_offset); | 136 breaker.ShapeLine(0, mid_third->SnappedWidth(), &break_offset); |
139 EXPECT_EQ(13u, break_offset); | 137 EXPECT_EQ(13u, break_offset); |
140 | 138 |
141 breaker.ShapeLine(13u, mid_third->SnappedWidth(), &break_offset); | 139 breaker.ShapeLine(13u, mid_third->SnappedWidth(), &break_offset); |
142 EXPECT_EQ(24u, break_offset); | 140 EXPECT_EQ(24u, break_offset); |
143 } | 141 } |
144 | 142 |
145 TEST_F(ShapingLineBreakerTest, ShapeLineLatinBreakAll) { | 143 TEST_F(ShapingLineBreakerTest, ShapeLineLatinBreakAll) { |
146 String string = To16Bit("Testing break type-break all.", 29); | 144 String string = To16Bit("Testing break type-break all.", 29); |
147 const AtomicString locale = "en-US"; | 145 LazyLineBreakIterator break_iterator(string, "en-US", |
| 146 LineBreakType::kBreakAll); |
148 TextDirection direction = TextDirection::kLtr; | 147 TextDirection direction = TextDirection::kLtr; |
149 LineBreakType break_type = LineBreakType::kBreakAll; | |
150 | 148 |
151 HarfBuzzShaper shaper(string.Characters16(), 29); | 149 HarfBuzzShaper shaper(string.Characters16(), 29); |
152 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); | 150 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); |
153 RefPtr<ShapeResult> midpoint = shaper.Shape(&font, direction, 0, 16); | 151 RefPtr<ShapeResult> midpoint = shaper.Shape(&font, direction, 0, 16); |
154 | 152 |
155 ShapingLineBreaker breaker(&shaper, &font, result.Get(), locale, break_type); | 153 ShapingLineBreaker breaker(&shaper, &font, result.Get(), &break_iterator); |
156 RefPtr<ShapeResult> line; | 154 RefPtr<ShapeResult> line; |
157 unsigned break_offset = 0; | 155 unsigned break_offset = 0; |
158 | 156 |
159 line = breaker.ShapeLine(0, midpoint->SnappedWidth(), &break_offset); | 157 line = breaker.ShapeLine(0, midpoint->SnappedWidth(), &break_offset); |
160 EXPECT_EQ(16u, break_offset); | 158 EXPECT_EQ(16u, break_offset); |
161 EXPECT_EQ(midpoint->SnappedWidth(), line->SnappedWidth()); | 159 EXPECT_EQ(midpoint->SnappedWidth(), line->SnappedWidth()); |
162 | 160 |
163 line = breaker.ShapeLine(16u, result->SnappedWidth(), &break_offset); | 161 line = breaker.ShapeLine(16u, result->SnappedWidth(), &break_offset); |
164 EXPECT_EQ(29u, break_offset); | 162 EXPECT_EQ(29u, break_offset); |
165 EXPECT_GE(midpoint->SnappedWidth(), line->SnappedWidth()); | 163 EXPECT_GE(midpoint->SnappedWidth(), line->SnappedWidth()); |
166 } | 164 } |
167 | 165 |
| 166 TEST_F(ShapingLineBreakerTest, ShapeLineZeroAvailableWidth) { |
| 167 String string(u"Testing overflow line break."); |
| 168 LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal); |
| 169 TextDirection direction = TextDirection::kLtr; |
| 170 |
| 171 HarfBuzzShaper shaper(string.Characters16(), string.length()); |
| 172 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); |
| 173 |
| 174 ShapingLineBreaker breaker(&shaper, &font, result.Get(), &break_iterator); |
| 175 RefPtr<ShapeResult> line; |
| 176 unsigned break_offset = 0; |
| 177 LayoutUnit zero(0); |
| 178 |
| 179 line = breaker.ShapeLine(0, zero, &break_offset); |
| 180 EXPECT_EQ(7u, break_offset); |
| 181 |
| 182 line = breaker.ShapeLine(7, zero, &break_offset); |
| 183 EXPECT_EQ(16u, break_offset); |
| 184 |
| 185 line = breaker.ShapeLine(16, zero, &break_offset); |
| 186 EXPECT_EQ(21u, break_offset); |
| 187 |
| 188 line = breaker.ShapeLine(21, zero, &break_offset); |
| 189 EXPECT_EQ(28u, break_offset); |
| 190 } |
| 191 |
168 TEST_F(ShapingLineBreakerTest, ShapeLineArabicThaiHanLatinBreakAll) { | 192 TEST_F(ShapingLineBreakerTest, ShapeLineArabicThaiHanLatinBreakAll) { |
169 UChar mixed_string[] = {0x628, 0x20, 0x64A, 0x629, 0x20, 0xE20, 0x65E5, 0x62}; | 193 UChar mixed_string[] = {0x628, 0x20, 0x64A, 0x629, 0x20, |
170 const AtomicString locale = "ar_AE"; | 194 0xE20, 0x65E5, 0x62, 0}; |
| 195 LazyLineBreakIterator break_iterator(mixed_string, "ar_AE", |
| 196 LineBreakType::kBreakAll); |
171 TextDirection direction = TextDirection::kRtl; | 197 TextDirection direction = TextDirection::kRtl; |
172 LineBreakType break_type = LineBreakType::kBreakAll; | |
173 | 198 |
174 HarfBuzzShaper shaper(mixed_string, 8); | 199 HarfBuzzShaper shaper(mixed_string, 8); |
175 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); | 200 RefPtr<ShapeResult> result = shaper.Shape(&font, direction); |
| 201 RefPtr<ShapeResult> words[] = {shaper.Shape(&font, direction, 0, 1), |
| 202 shaper.Shape(&font, direction, 2, 4), |
| 203 shaper.Shape(&font, direction, 5, 6), |
| 204 shaper.Shape(&font, direction, 6, 7), |
| 205 shaper.Shape(&font, direction, 7, 8)}; |
| 206 const auto& longest_word = std::max_element( |
| 207 std::begin(words), std::end(words), |
| 208 [](const RefPtr<ShapeResult>& a, const RefPtr<ShapeResult>& b) { |
| 209 return a->SnappedWidth() < b->SnappedWidth(); |
| 210 }); |
| 211 LayoutUnit longest_word_width = (*longest_word)->SnappedWidth(); |
176 | 212 |
177 ShapingLineBreaker breaker(&shaper, &font, result.Get(), locale, break_type); | 213 ShapingLineBreaker breaker(&shaper, &font, result.Get(), &break_iterator); |
| 214 RefPtr<ShapeResult> line; |
178 unsigned break_offset = 0; | 215 unsigned break_offset = 0; |
179 breaker.ShapeLine(3, result->SnappedWidth() / LayoutUnit(2), &break_offset); | 216 |
| 217 breaker.ShapeLine(0, longest_word_width, &break_offset); |
| 218 EXPECT_EQ(1u, break_offset); |
| 219 |
| 220 breaker.ShapeLine(1, longest_word_width, &break_offset); |
| 221 EXPECT_EQ(4u, break_offset); |
| 222 |
| 223 breaker.ShapeLine(4, longest_word_width, &break_offset); |
| 224 EXPECT_EQ(6u, break_offset); |
| 225 |
| 226 breaker.ShapeLine(6, longest_word_width, &break_offset); |
| 227 EXPECT_EQ(7u, break_offset); |
| 228 |
| 229 breaker.ShapeLine(7, longest_word_width, &break_offset); |
| 230 EXPECT_EQ(8u, break_offset); |
180 } | 231 } |
181 | 232 |
| 233 TEST_F(ShapingLineBreakerTest, ShapeLineRangeEndMidWord) { |
| 234 String string(u"Mid word"); |
| 235 LazyLineBreakIterator break_iterator(string, "en-US", LineBreakType::kNormal); |
| 236 TextDirection direction = TextDirection::kLtr; |
| 237 |
| 238 HarfBuzzShaper shaper(string.Characters16(), string.length()); |
| 239 RefPtr<ShapeResult> result = shaper.Shape(&font, direction, 0, 2); |
| 240 |
| 241 ShapingLineBreaker breaker(&shaper, &font, result.Get(), &break_iterator); |
| 242 RefPtr<ShapeResult> line; |
| 243 unsigned break_offset = 0; |
| 244 |
| 245 line = breaker.ShapeLine(0, LayoutUnit::Max(), &break_offset); |
| 246 EXPECT_EQ(3u, break_offset); |
| 247 EXPECT_EQ(result->Width(), line->Width()); |
| 248 } |
182 } // namespace blink | 249 } // namespace blink |
OLD | NEW |