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" |
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
83 unsigned to, | 83 unsigned to, |
84 unsigned runOffset) { | 84 unsigned runOffset) { |
85 if (!run) | 85 if (!run) |
86 return 0; | 86 return 0; |
87 float advanceSoFar = initialAdvance; | 87 float advanceSoFar = initialAdvance; |
88 const unsigned numGlyphs = run->m_glyphData.size(); | 88 const unsigned numGlyphs = run->m_glyphData.size(); |
89 for (unsigned i = 0; i < numGlyphs; ++i) { | 89 for (unsigned i = 0; i < numGlyphs; ++i) { |
90 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; | 90 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; |
91 uint16_t currentCharacterIndex = | 91 uint16_t currentCharacterIndex = |
92 run->m_startIndex + glyphData.characterIndex + runOffset; | 92 run->m_startIndex + glyphData.characterIndex + runOffset; |
93 if ((direction == RTL && currentCharacterIndex >= to) || | 93 if ((direction == TextDirection::Rtl && currentCharacterIndex >= to) || |
94 (direction == LTR && currentCharacterIndex < from)) { | 94 (direction == TextDirection::Ltr && currentCharacterIndex < from)) { |
95 advanceSoFar += glyphData.advance; | 95 advanceSoFar += glyphData.advance; |
96 } else if ((direction == RTL && currentCharacterIndex >= from) || | 96 } else if ((direction == TextDirection::Rtl && |
97 (direction == LTR && currentCharacterIndex < to)) { | 97 currentCharacterIndex >= from) || |
| 98 (direction == TextDirection::Ltr && |
| 99 currentCharacterIndex < to)) { |
98 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, | 100 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction, |
99 run->m_fontData.get(), glyphData); | 101 run->m_fontData.get(), glyphData); |
100 advanceSoFar += glyphData.advance; | 102 advanceSoFar += glyphData.advance; |
101 } | 103 } |
102 } | 104 } |
103 return advanceSoFar - initialAdvance; | 105 return advanceSoFar - initialAdvance; |
104 } | 106 } |
105 | 107 |
106 float ShapeResultBuffer::fillGlyphBufferForTextEmphasisRun( | 108 float ShapeResultBuffer::fillGlyphBufferForTextEmphasisRun( |
107 GlyphBuffer* glyphBuffer, | 109 GlyphBuffer* glyphBuffer, |
(...skipping 16 matching lines...) Expand all Loading... |
124 TextDirection direction = textRun.direction(); | 126 TextDirection direction = textRun.direction(); |
125 | 127 |
126 // A "cluster" in this context means a cluster as it is used by HarfBuzz: | 128 // A "cluster" in this context means a cluster as it is used by HarfBuzz: |
127 // The minimal group of characters and corresponding glyphs, that cannot be | 129 // The minimal group of characters and corresponding glyphs, that cannot be |
128 // broken down further from a text shaping point of view. A cluster can | 130 // broken down further from a text shaping point of view. A cluster can |
129 // contain multiple glyphs and grapheme clusters, with mutually overlapping | 131 // contain multiple glyphs and grapheme clusters, with mutually overlapping |
130 // boundaries. Below we count grapheme clusters per HarfBuzz clusters, then | 132 // boundaries. Below we count grapheme clusters per HarfBuzz clusters, then |
131 // linearly split the sum of corresponding glyph advances by the number of | 133 // linearly split the sum of corresponding glyph advances by the number of |
132 // grapheme clusters in order to find positions for emphasis mark drawing. | 134 // grapheme clusters in order to find positions for emphasis mark drawing. |
133 uint16_t clusterStart = static_cast<uint16_t>( | 135 uint16_t clusterStart = static_cast<uint16_t>( |
134 direction == RTL ? run->m_startIndex + run->m_numCharacters + runOffset | 136 direction == TextDirection::Rtl |
135 : run->glyphToCharacterIndex(0) + runOffset); | 137 ? run->m_startIndex + run->m_numCharacters + runOffset |
| 138 : run->glyphToCharacterIndex(0) + runOffset); |
136 | 139 |
137 float advanceSoFar = initialAdvance; | 140 float advanceSoFar = initialAdvance; |
138 const unsigned numGlyphs = run->m_glyphData.size(); | 141 const unsigned numGlyphs = run->m_glyphData.size(); |
139 for (unsigned i = 0; i < numGlyphs; ++i) { | 142 for (unsigned i = 0; i < numGlyphs; ++i) { |
140 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; | 143 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i]; |
141 uint16_t currentCharacterIndex = | 144 uint16_t currentCharacterIndex = |
142 run->m_startIndex + glyphData.characterIndex + runOffset; | 145 run->m_startIndex + glyphData.characterIndex + runOffset; |
143 bool isRunEnd = (i + 1 == numGlyphs); | 146 bool isRunEnd = (i + 1 == numGlyphs); |
144 bool isClusterEnd = | 147 bool isClusterEnd = |
145 isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != | 148 isRunEnd || (run->glyphToCharacterIndex(i + 1) + runOffset != |
146 currentCharacterIndex); | 149 currentCharacterIndex); |
147 | 150 |
148 if ((direction == RTL && currentCharacterIndex >= to) || | 151 if ((direction == TextDirection::Rtl && currentCharacterIndex >= to) || |
149 (direction != RTL && currentCharacterIndex < from)) { | 152 (direction != TextDirection::Rtl && currentCharacterIndex < from)) { |
150 advanceSoFar += glyphData.advance; | 153 advanceSoFar += glyphData.advance; |
151 direction == RTL ? --clusterStart : ++clusterStart; | 154 direction == TextDirection::Rtl ? --clusterStart : ++clusterStart; |
152 continue; | 155 continue; |
153 } | 156 } |
154 | 157 |
155 clusterAdvance += glyphData.advance; | 158 clusterAdvance += glyphData.advance; |
156 | 159 |
157 if (textRun.is8Bit()) { | 160 if (textRun.is8Bit()) { |
158 float glyphAdvanceX = glyphData.advance; | 161 float glyphAdvanceX = glyphData.advance; |
159 if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) { | 162 if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex])) { |
160 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, | 163 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, |
161 advanceSoFar + glyphAdvanceX / 2); | 164 advanceSoFar + glyphAdvanceX / 2); |
162 } | 165 } |
163 advanceSoFar += glyphAdvanceX; | 166 advanceSoFar += glyphAdvanceX; |
164 } else if (isClusterEnd) { | 167 } else if (isClusterEnd) { |
165 uint16_t clusterEnd; | 168 uint16_t clusterEnd; |
166 if (direction == RTL) | 169 if (direction == TextDirection::Rtl) |
167 clusterEnd = currentCharacterIndex; | 170 clusterEnd = currentCharacterIndex; |
168 else | 171 else |
169 clusterEnd = static_cast<uint16_t>( | 172 clusterEnd = static_cast<uint16_t>( |
170 isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset | 173 isRunEnd ? run->m_startIndex + run->m_numCharacters + runOffset |
171 : run->glyphToCharacterIndex(i + 1) + runOffset); | 174 : run->glyphToCharacterIndex(i + 1) + runOffset); |
172 | 175 |
173 graphemesInCluster = countGraphemesInCluster(textRun.characters16(), | 176 graphemesInCluster = countGraphemesInCluster(textRun.characters16(), |
174 textRun.charactersLength(), | 177 textRun.charactersLength(), |
175 clusterStart, clusterEnd); | 178 clusterStart, clusterEnd); |
176 if (!graphemesInCluster || !clusterAdvance) | 179 if (!graphemesInCluster || !clusterAdvance) |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun.direction()); | 236 return fillFastHorizontalGlyphBuffer(glyphBuffer, textRun.direction()); |
234 | 237 |
235 float advance = 0; | 238 float advance = 0; |
236 | 239 |
237 if (textRun.rtl()) { | 240 if (textRun.rtl()) { |
238 unsigned wordOffset = textRun.length(); | 241 unsigned wordOffset = textRun.length(); |
239 for (unsigned j = 0; j < m_results.size(); j++) { | 242 for (unsigned j = 0; j < m_results.size(); j++) { |
240 unsigned resolvedIndex = m_results.size() - 1 - j; | 243 unsigned resolvedIndex = m_results.size() - 1 - j; |
241 const RefPtr<const ShapeResult>& wordResult = m_results[resolvedIndex]; | 244 const RefPtr<const ShapeResult>& wordResult = m_results[resolvedIndex]; |
242 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 245 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
243 advance += fillGlyphBufferForRun<RTL>( | 246 advance += fillGlyphBufferForRun<TextDirection::Rtl>( |
244 glyphBuffer, wordResult->m_runs[i].get(), advance, from, to, | 247 glyphBuffer, wordResult->m_runs[i].get(), advance, from, to, |
245 wordOffset - wordResult->numCharacters()); | 248 wordOffset - wordResult->numCharacters()); |
246 } | 249 } |
247 wordOffset -= wordResult->numCharacters(); | 250 wordOffset -= wordResult->numCharacters(); |
248 } | 251 } |
249 } else { | 252 } else { |
250 unsigned wordOffset = 0; | 253 unsigned wordOffset = 0; |
251 for (unsigned j = 0; j < m_results.size(); j++) { | 254 for (unsigned j = 0; j < m_results.size(); j++) { |
252 const RefPtr<const ShapeResult>& wordResult = m_results[j]; | 255 const RefPtr<const ShapeResult>& wordResult = m_results[j]; |
253 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { | 256 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) { |
254 advance += | 257 advance += fillGlyphBufferForRun<TextDirection::Ltr>( |
255 fillGlyphBufferForRun<LTR>(glyphBuffer, wordResult->m_runs[i].get(), | 258 glyphBuffer, wordResult->m_runs[i].get(), advance, from, to, |
256 advance, from, to, wordOffset); | 259 wordOffset); |
257 } | 260 } |
258 wordOffset += wordResult->numCharacters(); | 261 wordOffset += wordResult->numCharacters(); |
259 } | 262 } |
260 } | 263 } |
261 | 264 |
262 return advance; | 265 return advance; |
263 } | 266 } |
264 | 267 |
265 float ShapeResultBuffer::fillGlyphBufferForTextEmphasis( | 268 float ShapeResultBuffer::fillGlyphBufferForTextEmphasis( |
266 GlyphBuffer* glyphBuffer, | 269 GlyphBuffer* glyphBuffer, |
(...skipping 23 matching lines...) Expand all Loading... |
290 CharacterRange ShapeResultBuffer::getCharacterRange(TextDirection direction, | 293 CharacterRange ShapeResultBuffer::getCharacterRange(TextDirection direction, |
291 float totalWidth, | 294 float totalWidth, |
292 unsigned absoluteFrom, | 295 unsigned absoluteFrom, |
293 unsigned absoluteTo) const { | 296 unsigned absoluteTo) const { |
294 float currentX = 0; | 297 float currentX = 0; |
295 float fromX = 0; | 298 float fromX = 0; |
296 float toX = 0; | 299 float toX = 0; |
297 bool foundFromX = false; | 300 bool foundFromX = false; |
298 bool foundToX = false; | 301 bool foundToX = false; |
299 | 302 |
300 if (direction == RTL) | 303 if (direction == TextDirection::Rtl) |
301 currentX = totalWidth; | 304 currentX = totalWidth; |
302 | 305 |
303 // The absoluteFrom and absoluteTo arguments represent the start/end offset | 306 // The absoluteFrom and absoluteTo arguments represent the start/end offset |
304 // for the entire run, from/to are continuously updated to be relative to | 307 // for the entire run, from/to are continuously updated to be relative to |
305 // the current word (ShapeResult instance). | 308 // the current word (ShapeResult instance). |
306 int from = absoluteFrom; | 309 int from = absoluteFrom; |
307 int to = absoluteTo; | 310 int to = absoluteTo; |
308 | 311 |
309 unsigned totalNumCharacters = 0; | 312 unsigned totalNumCharacters = 0; |
310 for (unsigned j = 0; j < m_results.size(); j++) { | 313 for (unsigned j = 0; j < m_results.size(); j++) { |
311 const RefPtr<const ShapeResult> result = m_results[j]; | 314 const RefPtr<const ShapeResult> result = m_results[j]; |
312 if (direction == RTL) { | 315 if (direction == TextDirection::Rtl) { |
313 // Convert logical offsets to visual offsets, because results are in | 316 // Convert logical offsets to visual offsets, because results are in |
314 // logical order while runs are in visual order. | 317 // logical order while runs are in visual order. |
315 if (!foundFromX && from >= 0 && | 318 if (!foundFromX && from >= 0 && |
316 static_cast<unsigned>(from) < result->numCharacters()) | 319 static_cast<unsigned>(from) < result->numCharacters()) |
317 from = result->numCharacters() - from - 1; | 320 from = result->numCharacters() - from - 1; |
318 if (!foundToX && to >= 0 && | 321 if (!foundToX && to >= 0 && |
319 static_cast<unsigned>(to) < result->numCharacters()) | 322 static_cast<unsigned>(to) < result->numCharacters()) |
320 to = result->numCharacters() - to - 1; | 323 to = result->numCharacters() - to - 1; |
321 currentX -= result->width(); | 324 currentX -= result->width(); |
322 } | 325 } |
323 for (unsigned i = 0; i < result->m_runs.size(); i++) { | 326 for (unsigned i = 0; i < result->m_runs.size(); i++) { |
324 if (!result->m_runs[i]) | 327 if (!result->m_runs[i]) |
325 continue; | 328 continue; |
326 ASSERT((direction == RTL) == result->m_runs[i]->rtl()); | 329 DCHECK_EQ(direction == TextDirection::Rtl, result->m_runs[i]->rtl()); |
327 int numCharacters = result->m_runs[i]->m_numCharacters; | 330 int numCharacters = result->m_runs[i]->m_numCharacters; |
328 if (!foundFromX && from >= 0 && from < numCharacters) { | 331 if (!foundFromX && from >= 0 && from < numCharacters) { |
329 fromX = | 332 fromX = |
330 result->m_runs[i]->xPositionForVisualOffset(from, AdjustToStart) + | 333 result->m_runs[i]->xPositionForVisualOffset(from, AdjustToStart) + |
331 currentX; | 334 currentX; |
332 foundFromX = true; | 335 foundFromX = true; |
333 } else { | 336 } else { |
334 from -= numCharacters; | 337 from -= numCharacters; |
335 } | 338 } |
336 | 339 |
337 if (!foundToX && to >= 0 && to < numCharacters) { | 340 if (!foundToX && to >= 0 && to < numCharacters) { |
338 toX = result->m_runs[i]->xPositionForVisualOffset(to, AdjustToEnd) + | 341 toX = result->m_runs[i]->xPositionForVisualOffset(to, AdjustToEnd) + |
339 currentX; | 342 currentX; |
340 foundToX = true; | 343 foundToX = true; |
341 } else { | 344 } else { |
342 to -= numCharacters; | 345 to -= numCharacters; |
343 } | 346 } |
344 | 347 |
345 if (foundFromX && foundToX) | 348 if (foundFromX && foundToX) |
346 break; | 349 break; |
347 currentX += result->m_runs[i]->m_width; | 350 currentX += result->m_runs[i]->m_width; |
348 } | 351 } |
349 if (direction == RTL) | 352 if (direction == TextDirection::Rtl) |
350 currentX -= result->width(); | 353 currentX -= result->width(); |
351 totalNumCharacters += result->numCharacters(); | 354 totalNumCharacters += result->numCharacters(); |
352 } | 355 } |
353 | 356 |
354 // The position in question might be just after the text. | 357 // The position in question might be just after the text. |
355 if (!foundFromX && absoluteFrom == totalNumCharacters) { | 358 if (!foundFromX && absoluteFrom == totalNumCharacters) { |
356 fromX = direction == RTL ? 0 : totalWidth; | 359 fromX = direction == TextDirection::Rtl ? 0 : totalWidth; |
357 foundFromX = true; | 360 foundFromX = true; |
358 } | 361 } |
359 if (!foundToX && absoluteTo == totalNumCharacters) { | 362 if (!foundToX && absoluteTo == totalNumCharacters) { |
360 toX = direction == RTL ? 0 : totalWidth; | 363 toX = direction == TextDirection::Rtl ? 0 : totalWidth; |
361 foundToX = true; | 364 foundToX = true; |
362 } | 365 } |
363 if (!foundFromX) | 366 if (!foundFromX) |
364 fromX = 0; | 367 fromX = 0; |
365 if (!foundToX) | 368 if (!foundToX) |
366 toX = direction == RTL ? 0 : totalWidth; | 369 toX = direction == TextDirection::Rtl ? 0 : totalWidth; |
367 | 370 |
368 // None of our runs is part of the selection, possibly invalid arguments. | 371 // None of our runs is part of the selection, possibly invalid arguments. |
369 if (!foundToX && !foundFromX) | 372 if (!foundToX && !foundFromX) |
370 fromX = toX = 0; | 373 fromX = toX = 0; |
371 if (fromX < toX) | 374 if (fromX < toX) |
372 return CharacterRange(fromX, toX); | 375 return CharacterRange(fromX, toX); |
373 return CharacterRange(toX, fromX); | 376 return CharacterRange(toX, fromX); |
374 } | 377 } |
375 | 378 |
376 void ShapeResultBuffer::addRunInfoRanges(const ShapeResult::RunInfo& runInfo, | 379 void ShapeResultBuffer::addRunInfoRanges(const ShapeResult::RunInfo& runInfo, |
(...skipping 14 matching lines...) Expand all Loading... |
391 ranges.append(CharacterRange(end, start)); | 394 ranges.append(CharacterRange(end, start)); |
392 else | 395 else |
393 ranges.append(CharacterRange(start, end)); | 396 ranges.append(CharacterRange(start, end)); |
394 } | 397 } |
395 } | 398 } |
396 | 399 |
397 Vector<CharacterRange> ShapeResultBuffer::individualCharacterRanges( | 400 Vector<CharacterRange> ShapeResultBuffer::individualCharacterRanges( |
398 TextDirection direction, | 401 TextDirection direction, |
399 float totalWidth) const { | 402 float totalWidth) const { |
400 Vector<CharacterRange> ranges; | 403 Vector<CharacterRange> ranges; |
401 float currentX = direction == RTL ? totalWidth : 0; | 404 float currentX = direction == TextDirection::Rtl ? totalWidth : 0; |
402 for (const RefPtr<const ShapeResult> result : m_results) { | 405 for (const RefPtr<const ShapeResult> result : m_results) { |
403 if (direction == RTL) | 406 if (direction == TextDirection::Rtl) |
404 currentX -= result->width(); | 407 currentX -= result->width(); |
405 unsigned runCount = result->m_runs.size(); | 408 unsigned runCount = result->m_runs.size(); |
406 for (unsigned index = 0; index < runCount; index++) { | 409 for (unsigned index = 0; index < runCount; index++) { |
407 unsigned runIndex = direction == RTL ? runCount - 1 - index : index; | 410 unsigned runIndex = |
| 411 direction == TextDirection::Rtl ? runCount - 1 - index : index; |
408 addRunInfoRanges(*result->m_runs[runIndex], currentX, ranges); | 412 addRunInfoRanges(*result->m_runs[runIndex], currentX, ranges); |
409 currentX += result->m_runs[runIndex]->m_width; | 413 currentX += result->m_runs[runIndex]->m_width; |
410 } | 414 } |
411 if (direction == RTL) | 415 if (direction == TextDirection::Rtl) |
412 currentX -= result->width(); | 416 currentX -= result->width(); |
413 } | 417 } |
414 return ranges; | 418 return ranges; |
415 } | 419 } |
416 | 420 |
417 int ShapeResultBuffer::offsetForPosition(const TextRun& run, | 421 int ShapeResultBuffer::offsetForPosition(const TextRun& run, |
418 float targetX, | 422 float targetX, |
419 bool includePartialGlyphs) const { | 423 bool includePartialGlyphs) const { |
420 unsigned totalOffset; | 424 unsigned totalOffset; |
421 if (run.rtl()) { | 425 if (run.rtl()) { |
(...skipping 21 matching lines...) Expand all Loading... |
443 totalOffset += offsetForWord; | 447 totalOffset += offsetForWord; |
444 if (targetX >= 0 && targetX <= wordResult->width()) | 448 if (targetX >= 0 && targetX <= wordResult->width()) |
445 return totalOffset; | 449 return totalOffset; |
446 targetX -= wordResult->width(); | 450 targetX -= wordResult->width(); |
447 } | 451 } |
448 } | 452 } |
449 return totalOffset; | 453 return totalOffset; |
450 } | 454 } |
451 | 455 |
452 } // namespace blink | 456 } // namespace blink |
OLD | NEW |