OLD | NEW |
---|---|
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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/ShapeResultBuffer.h" | 5 #include "platform/fonts/shaping/ShapeResultBuffer.h" |
6 | 6 |
7 #include "platform/fonts/CharacterRange.h" | 7 #include "platform/fonts/CharacterRange.h" |
8 #include "platform/fonts/GlyphBuffer.h" | 8 #include "platform/fonts/GlyphBuffer.h" |
9 #include "platform/fonts/SimpleFontData.h" | 9 #include "platform/fonts/SimpleFontData.h" |
10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" | 10 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" |
11 #include "platform/geometry/FloatPoint.h" | 11 #include "platform/geometry/FloatPoint.h" |
12 #include "platform/text/Character.h" | 12 #include "platform/text/Character.h" |
13 #include "platform/text/TextBreakIterator.h" | 13 #include "platform/text/TextBreakIterator.h" |
14 #include "platform/text/TextDirection.h" | 14 #include "platform/text/TextDirection.h" |
15 | 15 |
16 namespace blink { | 16 namespace blink { |
17 | 17 |
18 namespace { | 18 namespace { |
19 | 19 |
20 inline void addIsSkipInkException(GlyphBuffer* glyphBuffer, | |
21 const TextRun& run, | |
22 unsigned characterIndex) { | |
23 DCHECK(!run.is8Bit()) << "8Bit() is always false, better to avoid to call"; | |
24 UChar32 baseCharacter = run.codepointAt(characterIndex); | |
25 UBlockCode blockCode = ublock_getCode(baseCharacter); | |
drott
2017/01/02 15:07:46
I'd very much prefer if we could reuse the isCJKId
| |
26 switch (blockCode) { | |
27 case UBLOCK_BOPOMOFO: | |
28 case UBLOCK_BOPOMOFO_EXTENDED: | |
29 case UBLOCK_CJK_COMPATIBILITY: | |
30 case UBLOCK_CJK_COMPATIBILITY_FORMS: | |
31 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS: | |
32 case UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT: | |
33 case UBLOCK_CJK_RADICALS_SUPPLEMENT: | |
34 case UBLOCK_CJK_STROKES: | |
35 case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: | |
36 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS: | |
37 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A: | |
38 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B: | |
39 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C: | |
40 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D: | |
41 case UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_E: | |
42 case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: | |
43 case UBLOCK_ENCLOSED_IDEOGRAPHIC_SUPPLEMENT: | |
44 case UBLOCK_HANGUL_COMPATIBILITY_JAMO: | |
45 case UBLOCK_HANGUL_JAMO: | |
46 case UBLOCK_HANGUL_JAMO_EXTENDED_A: | |
47 case UBLOCK_HANGUL_JAMO_EXTENDED_B: | |
48 case UBLOCK_HANGUL_SYLLABLES: | |
49 case UBLOCK_HIRAGANA: | |
50 case UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS: | |
51 case UBLOCK_IDEOGRAPHIC_SYMBOLS_AND_PUNCTUATION: | |
52 case UBLOCK_KATAKANA: | |
53 case UBLOCK_LINEAR_B_IDEOGRAMS: | |
54 case UBLOCK_TANGUT: | |
55 case UBLOCK_TANGUT_COMPONENTS: | |
56 glyphBuffer->addIsSkipInkException(true); | |
57 break; | |
58 default: | |
59 glyphBuffer->addIsSkipInkException(false); | |
60 break; | |
61 } | |
62 } | |
63 | |
20 inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, | 64 inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, |
21 float advance, | 65 float advance, |
22 hb_direction_t direction, | 66 hb_direction_t direction, |
23 const SimpleFontData* fontData, | 67 const SimpleFontData* fontData, |
24 const HarfBuzzRunGlyphData& glyphData) { | 68 const HarfBuzzRunGlyphData& glyphData, |
69 const TextRun& run, | |
70 unsigned characterIndex) { | |
25 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction) | 71 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction) |
26 ? FloatPoint(advance, 0) | 72 ? FloatPoint(advance, 0) |
27 : FloatPoint(0, advance); | 73 : FloatPoint(0, advance); |
28 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset); | 74 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset); |
75 if (glyphBuffer->shouldSaveSkipInkExceptions() && !run.is8Bit()) | |
76 addIsSkipInkException(glyphBuffer, run, characterIndex); | |
29 } | 77 } |
30 | 78 |
31 inline void addEmphasisMark(GlyphBuffer* buffer, | 79 inline void addEmphasisMark(GlyphBuffer* buffer, |
32 const GlyphData* emphasisData, | 80 const GlyphData* emphasisData, |
33 FloatPoint glyphCenter, | 81 FloatPoint glyphCenter, |
34 float midGlyphOffset) { | 82 float midGlyphOffset) { |
35 ASSERT(buffer); | 83 ASSERT(buffer); |
36 ASSERT(emphasisData); | 84 ASSERT(emphasisData); |
37 | 85 |
38 const SimpleFontData* emphasisFontData = emphasisData->fontData; | 86 const SimpleFontData* emphasisFontData = emphasisData->fontData; |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
71 numGraphemes++; | 119 numGraphemes++; |
72 } | 120 } |
73 return std::max(0, numGraphemes); | 121 return std::max(0, numGraphemes); |
74 } | 122 } |
75 | 123 |
76 } // anonymous namespace | 124 } // anonymous namespace |
77 | 125 |
78 template <TextDirection direction> | 126 template <TextDirection direction> |
79 float ShapeResultBuffer::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer, | 127 float ShapeResultBuffer::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer, |
80 const ShapeResult::RunInfo* run, | 128 const ShapeResult::RunInfo* run, |
129 const TextRun& textRun, | |
81 float initialAdvance, | 130 float initialAdvance, |
82 unsigned from, | 131 unsigned from, |
83 unsigned to, | 132 unsigned to, |
84 unsigned runOffset) { | 133 unsigned runOffset) { |
85 if (!run) | 134 if (!run) |
86 return 0; | 135 return 0; |
87 float advanceSoFar = initialAdvance; | 136 float advanceSoFar = initialAdvance; |
88 const unsigned numGlyphs = run->m_glyphData.size(); | 137 const unsigned numGlyphs = run->m_glyphData.size(); |
89 for (unsigned i = 0; i < numGlyphs; ++i) { | 138 for (unsigned i = 0; i < numGlyphs; ++i) { |
90 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; | 139 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; |
91 uint16_t currentCharacterIndex = | 140 uint16_t currentCharacterIndex = |
92 run->m_startIndex + glyphData.characterIndex + runOffset; | 141 run->m_startIndex + glyphData.characterIndex + runOffset; |
93 if ((direction == TextDirection::Rtl && currentCharacterIndex >= to) || | 142 if ((direction == TextDirection::Rtl && currentCharacterIndex >= to) || |
94 (direction == TextDirection::Ltr && currentCharacterIndex < from)) { | 143 (direction == TextDirection::Ltr && currentCharacterIndex < from)) { |
95 advanceSoFar += glyphData.advance; | 144 advanceSoFar += glyphData.advance; |
96 } else if ((direction == TextDirection::Rtl && | 145 } else if ((direction == TextDirection::Rtl && |
97 currentCharacterIndex >= from) || | 146 currentCharacterIndex >= from) || |
98 (direction == TextDirection::Ltr && | 147 (direction == TextDirection::Ltr && |
99 currentCharacterIndex < to)) { | 148 currentCharacterIndex < to)) { |
100 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, | 149 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, |
101 run->m_fontData.get(), glyphData); | 150 run->m_fontData.get(), glyphData, textRun, |
151 currentCharacterIndex); | |
102 advanceSoFar += glyphData.advance; | 152 advanceSoFar += glyphData.advance; |
103 } | 153 } |
104 } | 154 } |
105 return advanceSoFar - initialAdvance; | 155 return advanceSoFar - initialAdvance; |
106 } | 156 } |
107 | 157 |
108 float ShapeResultBuffer::fillGlyphBufferForTextEmphasisRun( | 158 float ShapeResultBuffer::fillGlyphBufferForTextEmphasisRun( |
109 GlyphBuffer* glyphBuffer, | 159 GlyphBuffer* glyphBuffer, |
110 const ShapeResult::RunInfo* run, | 160 const ShapeResult::RunInfo* run, |
111 const TextRun& textRun, | 161 const TextRun& textRun, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
190 } | 240 } |
191 clusterStart = clusterEnd; | 241 clusterStart = clusterEnd; |
192 clusterAdvance = 0; | 242 clusterAdvance = 0; |
193 } | 243 } |
194 } | 244 } |
195 return advanceSoFar - initialAdvance; | 245 return advanceSoFar - initialAdvance; |
196 } | 246 } |
197 | 247 |
198 float ShapeResultBuffer::fillFastHorizontalGlyphBuffer( | 248 float ShapeResultBuffer::fillFastHorizontalGlyphBuffer( |
199 GlyphBuffer* glyphBuffer, | 249 GlyphBuffer* glyphBuffer, |
200 TextDirection dir) const { | 250 const TextRun& textRun) const { |
201 ASSERT(!hasVerticalOffsets()); | 251 ASSERT(!hasVerticalOffsets()); |
202 | 252 |
203 float advance = 0; | 253 float advance = 0; |
204 | 254 |
255 unsigned characterIndex = 0; | |
205 for (unsigned i = 0; i < m_results.size(); ++i) { | 256 for (unsigned i = 0; i < m_results.size(); ++i) { |
206 const auto& wordResult = isLeftToRightDirection(dir) | 257 const auto& wordResult = isLeftToRightDirection(textRun.direction()) |
207 ? m_results[i] | 258 ? m_results[i] |
208 : m_results[m_results.size() - 1 - i]; | 259 : m_results[m_results.size() - 1 - i]; |
209 ASSERT(!wordResult->hasVerticalOffsets()); | 260 ASSERT(!wordResult->hasVerticalOffsets()); |
210 | 261 |
211 for (const auto& run : wordResult->m_runs) { | 262 for (const auto& run : wordResult->m_runs) { |
212 ASSERT(run); | 263 ASSERT(run); |
213 ASSERT(HB_DIRECTION_IS_HORIZONTAL(run->m_direction)); | 264 ASSERT(HB_DIRECTION_IS_HORIZONTAL(run->m_direction)); |
214 | 265 |
215 for (const auto& glyphData : run->m_glyphData) { | 266 for (const auto& glyphData : run->m_glyphData) { |
216 ASSERT(!glyphData.offset.height()); | 267 ASSERT(!glyphData.offset.height()); |
217 | 268 |
218 glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), | 269 glyphBuffer->add(glyphData.glyph, run->m_fontData.get(), |
219 advance + glyphData.offset.width()); | 270 advance + glyphData.offset.width()); |
271 if (glyphBuffer->shouldSaveSkipInkExceptions() && !textRun.is8Bit()) { | |
272 addIsSkipInkException(glyphBuffer, textRun, | |
273 characterIndex + glyphData.characterIndex); | |
274 } | |
275 | |
220 advance += glyphData.advance; | 276 advance += glyphData.advance; |
221 } | 277 } |
222 } | 278 } |
279 characterIndex += wordResult->m_numCharacters; | |
223 } | 280 } |
224 | 281 |
225 ASSERT(!glyphBuffer->hasVerticalOffsets()); | 282 ASSERT(!glyphBuffer->hasVerticalOffsets()); |
226 | 283 |
227 return advance; | 284 return advance; |
228 } | 285 } |
229 | 286 |
230 float ShapeResultBuffer::fillGlyphBuffer(GlyphBuffer* glyphBuffer, | 287 float ShapeResultBuffer::fillGlyphBuffer(GlyphBuffer* glyphBuffer, |
231 const TextRun& textRun, | 288 const TextRun& textRun, |
232 unsigned from, | 289 unsigned from, |
233 unsigned to) const { | 290 unsigned to) const { |
234 // Fast path: full run with no vertical offsets | 291 // Fast path: full run with no vertical offsets |
235 if (!from && to == textRun.length() && !hasVerticalOffsets()) | 292 if (!from && to == textRun.length() && !hasVerticalOffsets()) |
236 return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun.direction()); | 293 return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun); |
237 | 294 |
238 float advance = 0; | 295 float advance = 0; |
239 | 296 |
240 if (textRun.rtl()) { | 297 if (textRun.rtl()) { |
241 unsigned wordOffset = textRun.length(); | 298 unsigned wordOffset = textRun.length(); |
242 for (unsigned j = 0; j < m_results.size(); j++) { | 299 for (unsigned j = 0; j < m_results.size(); j++) { |
243 unsigned resolvedIndex = m_results.size() - 1 - j; | 300 unsigned resolvedIndex = m_results.size() - 1 - j; |
244 const RefPtr<const ShapeResult>& wordResult = m_results[resolvedIndex]; | 301 const RefPtr<const ShapeResult>& wordResult = m_results[resolvedIndex]; |
245 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 302 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
246 advance += fillGlyphBufferForRun<TextDirection::Rtl>( | 303 advance += fillGlyphBufferForRun<TextDirection::Rtl>( |
247 glyphBuffer, wordResult->m_runs[i].get(), advance, from, to, | 304 glyphBuffer, wordResult->m_runs[i].get(), textRun, advance, from, |
248 wordOffset - wordResult->numCharacters()); | 305 to, wordOffset - wordResult->numCharacters()); |
249 } | 306 } |
250 wordOffset -= wordResult->numCharacters(); | 307 wordOffset -= wordResult->numCharacters(); |
251 } | 308 } |
252 } else { | 309 } else { |
253 unsigned wordOffset = 0; | 310 unsigned wordOffset = 0; |
254 for (unsigned j = 0; j < m_results.size(); j++) { | 311 for (unsigned j = 0; j < m_results.size(); j++) { |
255 const RefPtr<const ShapeResult>& wordResult = m_results[j]; | 312 const RefPtr<const ShapeResult>& wordResult = m_results[j]; |
256 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 313 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
257 advance += fillGlyphBufferForRun<TextDirection::Ltr>( | 314 advance += fillGlyphBufferForRun<TextDirection::Ltr>( |
258 glyphBuffer, wordResult->m_runs[i].get(), advance, from, to, | 315 glyphBuffer, wordResult->m_runs[i].get(), textRun, advance, from, |
259 wordOffset); | 316 to, wordOffset); |
260 } | 317 } |
261 wordOffset += wordResult->numCharacters(); | 318 wordOffset += wordResult->numCharacters(); |
262 } | 319 } |
263 } | 320 } |
264 | 321 |
265 return advance; | 322 return advance; |
266 } | 323 } |
267 | 324 |
268 float ShapeResultBuffer::fillGlyphBufferForTextEmphasis( | 325 float ShapeResultBuffer::fillGlyphBufferForTextEmphasis( |
269 GlyphBuffer* glyphBuffer, | 326 GlyphBuffer* glyphBuffer, |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
447 totalOffset += offsetForWord; | 504 totalOffset += offsetForWord; |
448 if (targetX >= 0 && targetX <= wordResult->width()) | 505 if (targetX >= 0 && targetX <= wordResult->width()) |
449 return totalOffset; | 506 return totalOffset; |
450 targetX -= wordResult->width(); | 507 targetX -= wordResult->width(); |
451 } | 508 } |
452 } | 509 } |
453 return totalOffset; | 510 return totalOffset; |
454 } | 511 } |
455 | 512 |
456 } // namespace blink | 513 } // namespace blink |
OLD | NEW |