| 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 |