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