Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(120)

Side by Side Diff: third_party/WebKit/Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp

Issue 2686503003: Add support for shaping a substring to HarfBuzzShaper (Closed)
Patch Set: Clarify API and tests Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2014 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2014 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/HarfBuzzShaper.h" 5 #include "platform/fonts/shaping/HarfBuzzShaper.h"
6 6
7 #include "platform/fonts/Font.h" 7 #include "platform/fonts/Font.h"
8 #include "platform/fonts/FontCache.h" 8 #include "platform/fonts/FontCache.h"
9 #include "platform/fonts/shaping/ShapeResultTestInfo.h" 9 #include "platform/fonts/shaping/ShapeResultTestInfo.h"
10 #include "platform/text/TextRun.h" 10 #include "platform/text/TextRun.h"
(...skipping 25 matching lines...) Expand all
36 return static_cast<ShapeResultTestInfo*>(result.get()); 36 return static_cast<ShapeResultTestInfo*>(result.get());
37 } 37 }
38 38
39 static inline String to16Bit(const char* text, unsigned length) { 39 static inline String to16Bit(const char* text, unsigned length) {
40 return String::make16BitFrom8BitSource(reinterpret_cast<const LChar*>(text), 40 return String::make16BitFrom8BitSource(reinterpret_cast<const LChar*>(text),
41 length); 41 length);
42 } 42 }
43 43
44 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin) { 44 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLatin) {
45 String latinCommon = to16Bit("ABC DEF.", 8); 45 String latinCommon = to16Bit("ABC DEF.", 8);
46 HarfBuzzShaper shaper(latinCommon.characters16(), 8, TextDirection::kLtr); 46 HarfBuzzShaper shaper(latinCommon.characters16(), 8);
47 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 47 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
48 48
49 ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting()); 49 ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
50 ASSERT_TRUE( 50 ASSERT_TRUE(
51 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)); 51 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
52 EXPECT_EQ(0u, startIndex); 52 EXPECT_EQ(0u, startIndex);
53 EXPECT_EQ(8u, numGlyphs); 53 EXPECT_EQ(8u, numGlyphs);
54 EXPECT_EQ(HB_SCRIPT_LATIN, script); 54 EXPECT_EQ(HB_SCRIPT_LATIN, script);
55 } 55 }
56 56
57 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLeadingCommon) { 57 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsLeadingCommon) {
58 String leadingCommon = to16Bit("... test", 8); 58 String leadingCommon = to16Bit("... test", 8);
59 HarfBuzzShaper shaper(leadingCommon.characters16(), 8, TextDirection::kLtr); 59 HarfBuzzShaper shaper(leadingCommon.characters16(), 8);
60 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 60 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
61 61
62 ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting()); 62 ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
63 ASSERT_TRUE( 63 ASSERT_TRUE(
64 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)); 64 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
65 EXPECT_EQ(0u, startIndex); 65 EXPECT_EQ(0u, startIndex);
66 EXPECT_EQ(8u, numGlyphs); 66 EXPECT_EQ(8u, numGlyphs);
67 EXPECT_EQ(HB_SCRIPT_LATIN, script); 67 EXPECT_EQ(HB_SCRIPT_LATIN, script);
68 } 68 }
69 69
70 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsUnicodeVariants) { 70 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsUnicodeVariants) {
71 struct { 71 struct {
72 const char* name; 72 const char* name;
73 UChar string[4]; 73 UChar string[4];
74 unsigned length; 74 unsigned length;
75 hb_script_t script; 75 hb_script_t script;
76 } testlist[] = { 76 } testlist[] = {
77 {"Standard Variants text style", {0x30, 0xFE0E}, 2, HB_SCRIPT_COMMON}, 77 {"Standard Variants text style", {0x30, 0xFE0E}, 2, HB_SCRIPT_COMMON},
78 {"Standard Variants emoji style", {0x203C, 0xFE0F}, 2, HB_SCRIPT_COMMON}, 78 {"Standard Variants emoji style", {0x203C, 0xFE0F}, 2, HB_SCRIPT_COMMON},
79 {"Standard Variants of Ideograph", {0x4FAE, 0xFE00}, 2, HB_SCRIPT_HAN}, 79 {"Standard Variants of Ideograph", {0x4FAE, 0xFE00}, 2, HB_SCRIPT_HAN},
80 {"Ideographic Variants", {0x3402, 0xDB40, 0xDD00}, 3, HB_SCRIPT_HAN}, 80 {"Ideographic Variants", {0x3402, 0xDB40, 0xDD00}, 3, HB_SCRIPT_HAN},
81 {"Not-defined Variants", {0x41, 0xDB40, 0xDDEF}, 3, HB_SCRIPT_LATIN}, 81 {"Not-defined Variants", {0x41, 0xDB40, 0xDDEF}, 3, HB_SCRIPT_LATIN},
82 }; 82 };
83 for (auto& test : testlist) { 83 for (auto& test : testlist) {
84 HarfBuzzShaper shaper(test.string, test.length, TextDirection::kLtr); 84 HarfBuzzShaper shaper(test.string, test.length);
85 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 85 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
86 86
87 EXPECT_EQ(1u, testInfo(result)->numberOfRunsForTesting()) << test.name; 87 EXPECT_EQ(1u, testInfo(result)->numberOfRunsForTesting()) << test.name;
88 ASSERT_TRUE( 88 ASSERT_TRUE(
89 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)) 89 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script))
90 << test.name; 90 << test.name;
91 EXPECT_EQ(0u, startIndex) << test.name; 91 EXPECT_EQ(0u, startIndex) << test.name;
92 if (numGlyphs == 2) { 92 if (numGlyphs == 2) {
93 // If the specified VS is not in the font, it's mapped to .notdef. 93 // If the specified VS is not in the font, it's mapped to .notdef.
94 // then hb_ot_hide_default_ignorables() swaps it to a space with zero-advance. 94 // then hb_ot_hide_default_ignorables() swaps it to a space with zero-advance.
95 // http://lists.freedesktop.org/archives/harfbuzz/2015-May/004888.html 95 // http://lists.freedesktop.org/archives/harfbuzz/2015-May/004888.html
96 #if !OS(MACOSX) 96 #if !OS(MACOSX)
97 EXPECT_EQ(testInfo(result)->fontDataForTesting(0)->spaceGlyph(), 97 EXPECT_EQ(testInfo(result)->fontDataForTesting(0)->spaceGlyph(),
98 testInfo(result)->glyphForTesting(0, 1)) 98 testInfo(result)->glyphForTesting(0, 1))
99 << test.name; 99 << test.name;
100 #endif 100 #endif
101 EXPECT_EQ(0.f, testInfo(result)->advanceForTesting(0, 1)) << test.name; 101 EXPECT_EQ(0.f, testInfo(result)->advanceForTesting(0, 1)) << test.name;
102 } else { 102 } else {
103 EXPECT_EQ(1u, numGlyphs) << test.name; 103 EXPECT_EQ(1u, numGlyphs) << test.name;
104 } 104 }
105 EXPECT_EQ(test.script, script) << test.name; 105 EXPECT_EQ(test.script, script) << test.name;
106 } 106 }
107 } 107 }
108 108
109 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsDevanagariCommon) { 109 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsDevanagariCommon) {
110 UChar devanagariCommonString[] = {0x915, 0x94d, 0x930, 0x28, 0x20, 0x29}; 110 UChar devanagariCommonString[] = {0x915, 0x94d, 0x930, 0x28, 0x20, 0x29};
111 String devanagariCommonLatin(devanagariCommonString, 6); 111 String devanagariCommonLatin(devanagariCommonString, 6);
112 HarfBuzzShaper shaper(devanagariCommonLatin.characters16(), 6, 112 HarfBuzzShaper shaper(devanagariCommonLatin.characters16(), 6);
113 TextDirection::kLtr); 113 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
114 RefPtr<ShapeResult> result = shaper.shapeResult(&font);
115 114
116 ASSERT_EQ(2u, testInfo(result)->numberOfRunsForTesting()); 115 ASSERT_EQ(2u, testInfo(result)->numberOfRunsForTesting());
117 ASSERT_TRUE( 116 ASSERT_TRUE(
118 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)); 117 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
119 EXPECT_EQ(0u, startIndex); 118 EXPECT_EQ(0u, startIndex);
120 EXPECT_EQ(1u, numGlyphs); 119 EXPECT_EQ(1u, numGlyphs);
121 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script); 120 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
122 121
123 ASSERT_TRUE( 122 ASSERT_TRUE(
124 testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script)); 123 testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
125 EXPECT_EQ(3u, startIndex); 124 EXPECT_EQ(3u, startIndex);
126 EXPECT_EQ(3u, numGlyphs); 125 EXPECT_EQ(3u, numGlyphs);
127 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script); 126 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
128 } 127 }
129 128
130 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsDevanagariCommonLatinCommon) { 129 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsDevanagariCommonLatinCommon) {
131 UChar devanagariCommonLatinString[] = {0x915, 0x94d, 0x930, 0x20, 130 UChar devanagariCommonLatinString[] = {0x915, 0x94d, 0x930, 0x20,
132 0x61, 0x62, 0x2E}; 131 0x61, 0x62, 0x2E};
133 HarfBuzzShaper shaper(devanagariCommonLatinString, 7, TextDirection::kLtr); 132 HarfBuzzShaper shaper(devanagariCommonLatinString, 7);
134 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 133 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
135 134
136 ASSERT_EQ(3u, testInfo(result)->numberOfRunsForTesting()); 135 ASSERT_EQ(3u, testInfo(result)->numberOfRunsForTesting());
137 ASSERT_TRUE( 136 ASSERT_TRUE(
138 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)); 137 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
139 EXPECT_EQ(0u, startIndex); 138 EXPECT_EQ(0u, startIndex);
140 EXPECT_EQ(1u, numGlyphs); 139 EXPECT_EQ(1u, numGlyphs);
141 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script); 140 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
142 141
143 ASSERT_TRUE( 142 ASSERT_TRUE(
144 testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script)); 143 testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
145 EXPECT_EQ(3u, startIndex); 144 EXPECT_EQ(3u, startIndex);
146 EXPECT_EQ(1u, numGlyphs); 145 EXPECT_EQ(1u, numGlyphs);
147 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script); 146 EXPECT_EQ(HB_SCRIPT_DEVANAGARI, script);
148 147
149 ASSERT_TRUE( 148 ASSERT_TRUE(
150 testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script)); 149 testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script));
151 EXPECT_EQ(4u, startIndex); 150 EXPECT_EQ(4u, startIndex);
152 EXPECT_EQ(3u, numGlyphs); 151 EXPECT_EQ(3u, numGlyphs);
153 EXPECT_EQ(HB_SCRIPT_LATIN, script); 152 EXPECT_EQ(HB_SCRIPT_LATIN, script);
154 } 153 }
155 154
156 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabicThaiHanLatin) { 155 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabicThaiHanLatin) {
157 UChar mixedString[] = {0x628, 0x64A, 0x629, 0xE20, 0x65E5, 0x62}; 156 UChar mixedString[] = {0x628, 0x64A, 0x629, 0xE20, 0x65E5, 0x62};
158 HarfBuzzShaper shaper(mixedString, 6, TextDirection::kLtr); 157 HarfBuzzShaper shaper(mixedString, 6);
159 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 158 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
160 159
161 ASSERT_EQ(4u, testInfo(result)->numberOfRunsForTesting()); 160 ASSERT_EQ(4u, testInfo(result)->numberOfRunsForTesting());
162 ASSERT_TRUE( 161 ASSERT_TRUE(
163 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)); 162 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
164 EXPECT_EQ(0u, startIndex); 163 EXPECT_EQ(0u, startIndex);
165 EXPECT_EQ(3u, numGlyphs); 164 EXPECT_EQ(3u, numGlyphs);
166 EXPECT_EQ(HB_SCRIPT_ARABIC, script); 165 EXPECT_EQ(HB_SCRIPT_ARABIC, script);
167 166
168 ASSERT_TRUE( 167 ASSERT_TRUE(
169 testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script)); 168 testInfo(result)->runInfoForTesting(1, startIndex, numGlyphs, script));
170 EXPECT_EQ(3u, startIndex); 169 EXPECT_EQ(3u, startIndex);
171 EXPECT_EQ(1u, numGlyphs); 170 EXPECT_EQ(1u, numGlyphs);
172 EXPECT_EQ(HB_SCRIPT_THAI, script); 171 EXPECT_EQ(HB_SCRIPT_THAI, script);
173 172
174 ASSERT_TRUE( 173 ASSERT_TRUE(
175 testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script)); 174 testInfo(result)->runInfoForTesting(2, startIndex, numGlyphs, script));
176 EXPECT_EQ(4u, startIndex); 175 EXPECT_EQ(4u, startIndex);
177 EXPECT_EQ(1u, numGlyphs); 176 EXPECT_EQ(1u, numGlyphs);
178 EXPECT_EQ(HB_SCRIPT_HAN, script); 177 EXPECT_EQ(HB_SCRIPT_HAN, script);
179 178
180 ASSERT_TRUE( 179 ASSERT_TRUE(
181 testInfo(result)->runInfoForTesting(3, startIndex, numGlyphs, script)); 180 testInfo(result)->runInfoForTesting(3, startIndex, numGlyphs, script));
182 EXPECT_EQ(5u, startIndex); 181 EXPECT_EQ(5u, startIndex);
183 EXPECT_EQ(1u, numGlyphs); 182 EXPECT_EQ(1u, numGlyphs);
184 EXPECT_EQ(HB_SCRIPT_LATIN, script); 183 EXPECT_EQ(HB_SCRIPT_LATIN, script);
185 } 184 }
186 185
187 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabicThaiHanLatinTwice) { 186 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabicThaiHanLatinTwice) {
188 UChar mixedString[] = {0x628, 0x64A, 0x629, 0xE20, 0x65E5, 0x62}; 187 UChar mixedString[] = {0x628, 0x64A, 0x629, 0xE20, 0x65E5, 0x62};
189 HarfBuzzShaper shaper(mixedString, 6, TextDirection::kLtr); 188 HarfBuzzShaper shaper(mixedString, 6);
190 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 189 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kLtr);
191 ASSERT_EQ(4u, testInfo(result)->numberOfRunsForTesting()); 190 ASSERT_EQ(4u, testInfo(result)->numberOfRunsForTesting());
192 191
193 // Shape again on the same shape object and check the number of runs. 192 // Shape again on the same shape object and check the number of runs.
194 // Should be equal if no state was retained between shape calls. 193 // Should be equal if no state was retained between shape calls.
195 RefPtr<ShapeResult> result2 = shaper.shapeResult(&font); 194 RefPtr<ShapeResult> result2 = shaper.shape(&font, TextDirection::kLtr);
196 ASSERT_EQ(4u, testInfo(result2)->numberOfRunsForTesting()); 195 ASSERT_EQ(4u, testInfo(result2)->numberOfRunsForTesting());
197 } 196 }
198 197
199 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabic) { 198 TEST_F(HarfBuzzShaperTest, ResolveCandidateRunsArabic) {
200 UChar arabicString[] = {0x628, 0x64A, 0x629}; 199 UChar arabicString[] = {0x628, 0x64A, 0x629};
201 HarfBuzzShaper shaper(arabicString, 3, TextDirection::kRtl); 200 HarfBuzzShaper shaper(arabicString, 3);
202 RefPtr<ShapeResult> result = shaper.shapeResult(&font); 201 RefPtr<ShapeResult> result = shaper.shape(&font, TextDirection::kRtl);
203 202
204 ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting()); 203 ASSERT_EQ(1u, testInfo(result)->numberOfRunsForTesting());
205 ASSERT_TRUE( 204 ASSERT_TRUE(
206 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script)); 205 testInfo(result)->runInfoForTesting(0, startIndex, numGlyphs, script));
207 EXPECT_EQ(0u, startIndex); 206 EXPECT_EQ(0u, startIndex);
208 EXPECT_EQ(3u, numGlyphs); 207 EXPECT_EQ(3u, numGlyphs);
209 EXPECT_EQ(HB_SCRIPT_ARABIC, script); 208 EXPECT_EQ(HB_SCRIPT_ARABIC, script);
210 } 209 }
211 210
211 // This is a simplified test and doesn't accuratly reflect how the shape range
212 // is to be used. If you instead of the string you imagine the following HTML:
213 // <div>Hello <span>World</span>!</div>
214 // It better reflects the intended use where the range given to each shape call
215 // corresponds to the text content of a TextNode.
216 TEST_F(HarfBuzzShaperTest, ShapeLatinSegment) {
217 String string = to16Bit("Hello World!", 12);
218 TextDirection direction = TextDirection::kLtr;
219
220 HarfBuzzShaper shaper(string.characters16(), 12);
221 RefPtr<ShapeResult> combined = shaper.shape(&font, direction);
222 RefPtr<ShapeResult> first = shaper.shape(&font, direction, 0, 6);
223 RefPtr<ShapeResult> second = shaper.shape(&font, direction, 6, 11);
224 RefPtr<ShapeResult> third = shaper.shape(&font, direction, 11, 12);
225
226 HarfBuzzShaper shaper2(string.characters16(), 6);
227 RefPtr<ShapeResult> firstReference = shaper2.shape(&font, direction);
228
229 HarfBuzzShaper shaper3(string.characters16() + 6, 5);
230 RefPtr<ShapeResult> secondReference = shaper3.shape(&font, direction);
231
232 HarfBuzzShaper shaper4(string.characters16() + 11, 1);
233 RefPtr<ShapeResult> thirdReference = shaper4.shape(&font, direction);
234
235 // Width of each segment should be the same when shaped using start and end
236 // offset as it is when shaping the three segments using separate shaper
237 // instances.
238 // A full pixel is needed for tolerance to account for kerning on some
239 // platforms.
240 ASSERT_NEAR(firstReference->width(), first->width(), 1);
241 ASSERT_NEAR(secondReference->width(), second->width(), 1);
242 ASSERT_NEAR(thirdReference->width(), third->width(), 1);
243
244 // Width of shape results for the entire string should match the combined
245 // shape results from the three segments.
246 float totalWidth = first->width() + second->width() + third->width();
247 ASSERT_NEAR(combined->width(), totalWidth, 1);
248 }
249
250 // Represents the case where a part of a cluster has a different color.
251 // <div>0x647<span style="color: red;">0x64A</span></div>
252 // This test requires context-aware shaping which hasn't been implemented yet.
253 // See crbug.com/689155
254 TEST_F(HarfBuzzShaperTest, DISABLED_ShapeArabicWithContext) {
255 UChar arabicString[] = {0x647, 0x64A};
256 HarfBuzzShaper shaper(arabicString, 2);
257
258 RefPtr<ShapeResult> combined = shaper.shape(&font, TextDirection::kRtl);
259
260 RefPtr<ShapeResult> first = shaper.shape(&font, TextDirection::kRtl, 0, 1);
261 RefPtr<ShapeResult> second = shaper.shape(&font, TextDirection::kRtl, 1, 2);
262
263 // Combined width should be the same when shaping the two characters
264 // separately as when shaping them combined.
265 ASSERT_NEAR(combined->width(), first->width() + second->width(), 0.1);
266 }
267
212 } // namespace blink 268 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698