1 /* 2 * Copyright (c) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h" 33 34 #include <unicode/normlzr.h> 35 #include <unicode/uchar.h> 36 #include "core/platform/graphics/Font.h" 37 #include "core/platform/graphics/SurrogatePairAwareTextIterator.h" 38 #include "core/platform/graphics/TextRun.h" 39 #include "core/platform/graphics/harfbuzz/HarfBuzzFace.h" 40 #include "hb-icu.h" 41 #include "wtf/MathExtras.h" 42 #include "wtf/unicode/Unicode.h" 43 #include "wtf/Vector.h" 44 45 namespace WebCore { 46 47 template<typename T> 48 class HarfBuzzScopedPtr { 49 public: 50 typedef void (*DestroyFunction)(T*); 51 52 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy) 53 : m_ptr(ptr) 54 , m_destroy(destroy) 55 { 56 ASSERT(m_destroy); 57 } 58 ~HarfBuzzScopedPtr() 59 { 60 if (m_ptr) 61 (*m_destroy)(m_ptr); 62 } 63 64 T* get() { return m_ptr; } 65 private: 66 T* m_ptr; 67 DestroyFunction m_destroy; 68 }; 69 70 static inline float harfBuzzPositionToFloat(hb_position_t value) 71 { 72 return static_cast<float>(value) / (1 << 16); 73 } 74 75 HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_t script) 76 : m_fontData(fontData) 77 , m_startIndex(startIndex) 78 , m_numCharacters(numCharacters) 79 , m_direction(direction) 80 , m_script(script) 81 { 82 } 83 84 void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfBuzzBuffer) 85 { 86 m_numGlyphs = hb_buffer_get_length(harfBuzzBuffer); 87 m_glyphs.resize(m_numGlyphs); 88 m_advances.resize(m_numGlyphs); 89 m_glyphToCharacterIndexes.resize(m_numGlyphs); 90 m_offsets.resize(m_numGlyphs); 91 } 92 93 void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance, float offsetX, float offsetY) 94 { 95 m_glyphs[index] = glyphId; 96 m_advances[index] = advance; 97 m_offsets[index] = FloatPoint(offsetX, offsetY); 98 } 99 100 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX) 101 { 102 ASSERT(targetX <= m_width); 103 float currentX = 0; 104 float currentAdvance = m_advances[0]; 105 unsigned glyphIndex = 0; 106 107 // Sum up advances that belong to a character. 108 while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) 109 currentAdvance += m_advances[++glyphIndex]; 110 currentAdvance = currentAdvance / 2.0; 111 if (targetX <= currentAdvance) 112 return rtl() ? m_numCharacters : 0; 113 114 ++glyphIndex; 115 while (glyphIndex < m_numGlyphs) { 116 unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1]; 117 float prevAdvance = currentAdvance; 118 currentAdvance = m_advances[glyphIndex]; 119 while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) 120 currentAdvance += m_advances[++glyphIndex]; 121 currentAdvance = currentAdvance / 2.0; 122 float nextX = currentX + prevAdvance + currentAdvance; 123 if (currentX <= targetX && targetX <= nextX) 124 return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphIndex]; 125 currentX = nextX; 126 prevAdvance = currentAdvance; 127 ++glyphIndex; 128 } 129 130 return rtl() ? 0 : m_numCharacters; 131 } 132 133 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset) 134 { 135 ASSERT(offset < m_numCharacters); 136 unsigned glyphIndex = 0; 137 float position = 0; 138 if (rtl()) { 139 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] > offset) { 140 position += m_advances[glyphIndex]; 141 ++glyphIndex; 142 } 143 // For RTL, we need to return the right side boundary of the character. 144 // Add advance of glyphs which are part of the character. 145 while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1]) { 146 position += m_advances[glyphIndex]; 147 ++glyphIndex; 148 } 149 position += m_advances[glyphIndex]; 150 } else { 151 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) { 152 position += m_advances[glyphIndex]; 153 ++glyphIndex; 154 } 155 } 156 return position; 157 } 158 159 static void normalizeCharacters(const TextRun& run, UChar* destination, int length) 160 { 161 int position = 0; 162 bool error = false; 163 const UChar* source; 164 String stringFor8BitRun; 165 if (run.is8Bit()) { 166 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), run.length()); 167 source = stringFor8BitRun.characters16(); 168 } else 169 source = run.characters16(); 170 171 while (position < length) { 172 UChar32 character; 173 int nextPosition = position; 174 U16_NEXT(source, nextPosition, length, character); 175 // Don't normalize tabs as they are not treated as spaces for word-end. 176 if (Font::treatAsSpace(character) && character != '\t') 177 character = ' '; 178 else if (Font::treatAsZeroWidthSpaceInComplexScript(character)) 179 character = zeroWidthSpace; 180 U16_APPEND(destination, position, length, character, error); 181 ASSERT_UNUSED(error, !error); 182 position = nextPosition; 183 } 184 } 185 186 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run) 187 : m_font(font) 188 , m_normalizedBufferLength(0) 189 , m_run(run) 190 , m_wordSpacingAdjustment(font->wordSpacing()) 191 , m_padding(0) 192 , m_padPerWordBreak(0) 193 , m_padError(0) 194 , m_letterSpacing(font->letterSpacing()) 195 , m_fromIndex(0) 196 , m_toIndex(m_run.length()) 197 { 198 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]); 199 m_normalizedBufferLength = m_run.length(); 200 normalizeCharacters(m_run, m_normalizedBuffer.get(), m_normalizedBufferLength); 201 setPadding(m_run.expansion()); 202 setFontFeatures(); 203 } 204 205 HarfBuzzShaper::~HarfBuzzShaper() 206 { 207 } 208 209 static void normalizeSpacesAndMirrorChars(const UChar* source, UChar* destination, int length, HarfBuzzShaper::NormalizeMode normalizeMode) 210 { 211 int position = 0; 212 bool error = false; 213 // Iterate characters in source and mirror character if needed. 214 while (position < length) { 215 UChar32 character; 216 int nextPosition = position; 217 U16_NEXT(source, nextPosition, length, character); 218 // Don't normalize tabs as they are not treated as spaces for word-end 219 if (Font::treatAsSpace(character) && character != '\t') 220 character = ' '; 221 else if (Font::treatAsZeroWidthSpace(character)) 222 character = zeroWidthSpace; 223 else if (normalizeMode == HarfBuzzShaper::NormalizeMirrorChars) 224 character = u_charMirror(character); 225 U16_APPEND(destination, position, length, character, error); 226 ASSERT_UNUSED(error, !error); 227 position = nextPosition; 228 } 229 } 230 231 void HarfBuzzShaper::setNormalizedBuffer(NormalizeMode normalizeMode) 232 { 233 // Normalize the text run in three ways: 234 // 1) Convert the |originalRun| to NFC normalized form if combining diacritical marks 235 // (U+0300..) are used in the run. This conversion is necessary since most OpenType 236 // fonts (e.g., Arial) don't have substitution rules for the diacritical marks in 237 // their GSUB tables. 238 // 239 // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API here since 240 // the API returns FALSE (= not normalized) for complex runs that don't require NFC 241 // normalization (e.g., Arabic text). Unless the run contains the diacritical marks, 242 // HarfBuzz will do the same thing for us using the GSUB table. 243 // 2) Convert spacing characters into plain spaces, as some fonts will provide glyphs 244 // for characters like '\n' otherwise. 245 // 3) Convert mirrored characters such as parenthesis for rtl text. 246 247 // Convert to NFC form if the text has diacritical marks. 248 icu::UnicodeString normalizedString; 249 UErrorCode error = U_ZERO_ERROR; 250 251 const UChar* runCharacters; 252 String stringFor8BitRun; 253 if (m_run.is8Bit()) { 254 stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length()); 255 runCharacters = stringFor8BitRun.characters16(); 256 } else 257 runCharacters = m_run.characters16(); 258 259 for (int i = 0; i < m_run.length(); ++i) { 260 UChar ch = runCharacters[i]; 261 if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) { 262 icu::Normalizer::normalize(icu::UnicodeString(runCharacters, 263 m_run.length()), UNORM_NFC, 0 /* no options */, 264 normalizedString, error); 265 if (U_FAILURE(error)) 266 normalizedString.remove(); 267 break; 268 } 269 } 270 271 const UChar* sourceText; 272 if (normalizedString.isEmpty()) { 273 m_normalizedBufferLength = m_run.length(); 274 sourceText = runCharacters; 275 } else { 276 m_normalizedBufferLength = normalizedString.length(); 277 sourceText = normalizedString.getBuffer(); 278 } 279 280 m_normalizedBuffer = adoptArrayPtr(new UChar[m_normalizedBufferLength + 1]); 281 normalizeSpacesAndMirrorChars(sourceText, m_normalizedBuffer.get(), m_normalizedBufferLength, normalizeMode); 282 } 283 284 bool HarfBuzzShaper::isWordEnd(unsigned index) 285 { 286 // This could refer a high-surrogate, but should work. 287 return index && isCodepointSpace(m_normalizedBuffer[index]); 288 } 289 290 int HarfBuzzShaper::determineWordBreakSpacing() 291 { 292 int wordBreakSpacing = m_wordSpacingAdjustment; 293 294 if (m_padding > 0) { 295 int toPad = roundf(m_padPerWordBreak + m_padError); 296 m_padError += m_padPerWordBreak - toPad; 297 298 if (m_padding < toPad) 299 toPad = m_padding; 300 m_padding -= toPad; 301 wordBreakSpacing += toPad; 302 } 303 return wordBreakSpacing; 304 } 305 306 // setPadding sets a number of pixels to be distributed across the TextRun. 307 // WebKit uses this to justify text. 308 void HarfBuzzShaper::setPadding(int padding) 309 { 310 m_padding = padding; 311 m_padError = 0; 312 if (!m_padding) 313 return; 314 315 // If we have padding to distribute, then we try to give an equal 316 // amount to each space. The last space gets the smaller amount, if 317 // any. 318 unsigned numWordEnds = 0; 319 320 for (unsigned i = 0; i < m_normalizedBufferLength; i++) { 321 if (isWordEnd(i)) 322 numWordEnds++; 323 } 324 325 if (numWordEnds) 326 m_padPerWordBreak = m_padding / numWordEnds; 327 else 328 m_padPerWordBreak = 0; 329 } 330 331 332 void HarfBuzzShaper::setDrawRange(int from, int to) 333 { 334 ASSERT_WITH_SECURITY_IMPLICATION(from >= 0); 335 ASSERT_WITH_SECURITY_IMPLICATION(to <= m_run.length()); 336 m_fromIndex = from; 337 m_toIndex = to; 338 } 339 340 void HarfBuzzShaper::setFontFeatures() 341 { 342 const FontDescription& description = m_font->fontDescription(); 343 if (description.orientation() == Vertical) { 344 static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<unsigned>(-1) }; 345 static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<unsigned>(-1) }; 346 m_features.append(vert); 347 m_features.append(vrt2); 348 } 349 350 FontFeatureSettings* settings = description.featureSettings(); 351 if (!settings) 352 return; 353 354 unsigned numFeatures = settings->size(); 355 for (unsigned i = 0; i < numFeatures; ++i) { 356 hb_feature_t feature; 357 String tag = settings->at(i).tag(); 358 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); 359 feature.value = settings->at(i).value(); 360 feature.start = 0; 361 feature.end = static_cast<unsigned>(-1); 362 m_features.append(feature); 363 } 364 } 365 366 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) 367 { 368 if (!collectHarfBuzzRuns()) 369 return false; 370 371 m_totalWidth = 0; 372 // WebKit doesn't set direction when calulating widths. Leave the direction setting to 373 // HarfBuzz when we are calculating widths (except when directionalOverride() is set). 374 if (!shapeHarfBuzzRuns(glyphBuffer || m_run.directionalOverride())) 375 return false; 376 m_totalWidth = roundf(m_totalWidth); 377 378 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer)) 379 return false; 380 381 return true; 382 } 383 384 FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point) 385 { 386 return point + m_startOffset; 387 } 388 389 bool HarfBuzzShaper::collectHarfBuzzRuns() 390 { 391 const UChar* normalizedBufferEnd = m_normalizedBuffer.get() + m_normalizedBufferLength; 392 SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_normalizedBufferLength, m_normalizedBufferLength); 393 UChar32 character; 394 unsigned clusterLength = 0; 395 unsigned startIndexOfCurrentRun = 0; 396 if (!iterator.consume(character, clusterLength)) 397 return false; 398 399 const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character, false).fontData; 400 UErrorCode errorCode = U_ZERO_ERROR; 401 UScriptCode nextScript = uscript_getScript(character, &errorCode); 402 if (U_FAILURE(errorCode)) 403 return false; 404 405 do { 406 const UChar* currentCharacterPosition = iterator.characters(); 407 const SimpleFontData* currentFontData = nextFontData; 408 UScriptCode currentScript = nextScript; 409 410 for (iterator.advance(clusterLength); iterator.consume(character, clusterLength); iterator.advance(clusterLength)) { 411 if (Font::treatAsZeroWidthSpace(character)) 412 continue; 413 414 if (U_GET_GC_MASK(character) & U_GC_M_MASK) { 415 int markLength = clusterLength; 416 const UChar* markCharactersEnd = iterator.characters() + clusterLength; 417 while (markCharactersEnd < normalizedBufferEnd) { 418 UChar32 nextCharacter; 419 int nextCharacterLength = 0; 420 U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter); 421 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) 422 break; 423 markLength += nextCharacterLength; 424 markCharactersEnd += nextCharacterLength; 425 } 426 427 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacterPosition, markCharactersEnd - currentCharacterPosition)) { 428 clusterLength = markLength; 429 continue; 430 } 431 nextFontData = m_font->glyphDataForCharacter(character, false).fontData; 432 } else 433 nextFontData = m_font->glyphDataForCharacter(character, false).fontData; 434 435 nextScript = uscript_getScript(character, &errorCode); 436 if (U_FAILURE(errorCode)) 437 return false; 438 if ((nextFontData != currentFontData) || ((currentScript != nextScript) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, currentScript)))) 439 break; 440 if (nextScript == USCRIPT_INHERITED) 441 nextScript = currentScript; 442 currentCharacterPosition = iterator.characters(); 443 } 444 unsigned numCharactersOfCurrentRun = iterator.currentCharacter() - startIndexOfCurrentRun; 445 hb_script_t script = hb_icu_script_to_script(currentScript); 446 m_harfBuzzRuns.append(HarfBuzzRun::create(currentFontData, startIndexOfCurrentRun, numCharactersOfCurrentRun, m_run.direction(), script)); 447 currentFontData = nextFontData; 448 startIndexOfCurrentRun = iterator.currentCharacter(); 449 } while (iterator.consume(character, clusterLength)); 450 451 return !m_harfBuzzRuns.isEmpty(); 452 } 453 454 bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection) 455 { 456 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_destroy); 457 458 hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs()); 459 460 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 461 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; 462 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 463 const SimpleFontData* currentFontData = currentRun->fontData(); 464 if (currentFontData->isSVGFont()) 465 return false; 466 467 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); 468 if (shouldSetDirection) 469 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB_DIRECTION_RTL : HB_DIRECTION_LTR); 470 else 471 // Leaving direction to HarfBuzz to guess is *really* bad, but will do for now. 472 hb_buffer_guess_segment_properties(harfBuzzBuffer.get()); 473 474 // Add a space as pre-context to the buffer. This prevents showing dotted-circle 475 // for combining marks at the beginning of runs. 476 static const uint16_t preContext = ' '; 477 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); 478 479 if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->startIndex()])) { 480 String upperText = String(m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters()); 481 upperText.makeUpper(); 482 currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData; 483 ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, therefore upperText is 16 bit, even after we call makeUpper(). 484 hb_buffer_add_utf16(harfBuzzBuffer.get(), upperText.characters16(), currentRun->numCharacters(), 0, currentRun->numCharacters()); 485 } else 486 hb_buffer_add_utf16(harfBuzzBuffer.get(), m_normalizedBuffer.get() + currentRun->startIndex(), currentRun->numCharacters(), 0, currentRun->numCharacters()); 487 488 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tFontData->platformData()); 489 HarfBuzzFace* face = platformData->harfBuzzFace(); 490 if (!face) 491 return false; 492 493 if (m_font->fontDescription().orientation() == Vertical) 494 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); 495 496 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_destroy); 497 498 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); 499 500 currentRun->applyShapeResult(harfBuzzBuffer.get()); 501 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get()); 502 503 hb_buffer_reset(harfBuzzBuffer.get()); 504 } 505 506 return true; 507 } 508 509 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer) 510 { 511 const SimpleFontData* currentFontData = currentRun->fontData(); 512 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); 513 hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzzBuffer, 0); 514 515 unsigned numGlyphs = currentRun->numGlyphs(); 516 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); 517 float totalAdvance = 0; 518 519 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. 520 for (size_t i = 0; i < numGlyphs; ++i) { 521 bool runEnd = i + 1 == numGlyphs; 522 uint16_t glyph = glyphInfos[i].codepoint; 523 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); 524 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); 525 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance); 526 527 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].cluster; 528 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1].cluster; 529 float spacing = 0; 530 531 glyphToCharacterIndexes[i] = glyphInfos[i].cluster; 532 533 if (isClusterEnd && !Font::treatAsZeroWidthSpace(m_normalizedBuffer[currentCharacterIndex])) 534 spacing += m_letterSpacing; 535 536 if (isClusterEnd && isWordEnd(currentCharacterIndex)) 537 spacing += determineWordBreakSpacing(); 538 539 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { 540 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); 541 continue; 542 } 543 544 advance += spacing; 545 if (m_run.rtl()) { 546 // In RTL, spacing should be added to left side of glyphs. 547 offsetX += spacing; 548 if (!isClusterEnd) 549 offsetX += m_letterSpacing; 550 } 551 552 currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); 553 554 totalAdvance += advance; 555 } 556 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); 557 m_totalWidth += currentRun->width(); 558 } 559 560 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, HarfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun) 561 { 562 FloatPoint* offsets = currentRun->offsets(); 563 uint16_t* glyphs = currentRun->glyphs(); 564 float* advances = currentRun->advances(); 565 unsigned numGlyphs = currentRun->numGlyphs(); 566 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes(); 567 568 for (unsigned i = 0; i < numGlyphs; ++i) { 569 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToCharacterIndexes[i]; 570 FloatPoint& currentOffset = offsets[i]; 571 FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : offsets[i + 1]; 572 float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x(); 573 float glyphAdvanceY = nextOffset.y() - currentOffset.y(); 574 if (m_run.rtl()) { 575 if (currentCharacterIndex > m_toIndex) 576 m_startOffset.move(glyphAdvanceX, glyphAdvanceY); 577 else if (currentCharacterIndex >= m_fromIndex) 578 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); 579 } else { 580 if (currentCharacterIndex < m_fromIndex) 581 m_startOffset.move(glyphAdvanceX, glyphAdvanceY); 582 else if (currentCharacterIndex < m_toIndex) 583 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphBufferAdvance(glyphAdvanceX, glyphAdvanceY)); 584 } 585 } 586 } 587 588 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer) 589 { 590 unsigned numRuns = m_harfBuzzRuns.size(); 591 if (m_run.rtl()) { 592 m_startOffset = m_harfBuzzRuns.last()->offsets()[0]; 593 for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) { 594 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 595 FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfBuzzRuns[runIndex - 1]->offsets()[0]; 596 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun); 597 } 598 } else { 599 m_startOffset = m_harfBuzzRuns.first()->offsets()[0]; 600 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) { 601 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 602 FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoint() : m_harfBuzzRuns[runIndex + 1]->offsets()[0]; 603 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetOfNextRun); 604 } 605 } 606 return glyphBuffer->size(); 607 } 608 609 int HarfBuzzShaper::offsetForPosition(float targetX) 610 { 611 int charactersSoFar = 0; 612 float currentX = 0; 613 614 if (m_run.rtl()) { 615 charactersSoFar = m_normalizedBufferLength; 616 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { 617 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); 618 float nextX = currentX + m_harfBuzzRuns[i]->width(); 619 float offsetForRun = targetX - currentX; 620 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) { 621 // The x value in question is within this script run. 622 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun); 623 return charactersSoFar + index; 624 } 625 currentX = nextX; 626 } 627 } else { 628 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 629 float nextX = currentX + m_harfBuzzRuns[i]->width(); 630 float offsetForRun = targetX - currentX; 631 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) { 632 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosition(offsetForRun); 633 return charactersSoFar + index; 634 } 635 charactersSoFar += m_harfBuzzRuns[i]->numCharacters(); 636 currentX = nextX; 637 } 638 } 639 640 return charactersSoFar; 641 } 642 643 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to) 644 { 645 float currentX = 0; 646 float fromX = 0; 647 float toX = 0; 648 bool foundFromX = false; 649 bool foundToX = false; 650 651 if (m_run.rtl()) 652 currentX = m_totalWidth; 653 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 654 if (m_run.rtl()) 655 currentX -= m_harfBuzzRuns[i]->width(); 656 int numCharacters = m_harfBuzzRuns[i]->numCharacters(); 657 if (!foundFromX && from >= 0 && from < numCharacters) { 658 fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX; 659 foundFromX = true; 660 } else 661 from -= numCharacters; 662 663 if (!foundToX && to >= 0 && to < numCharacters) { 664 toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX; 665 foundToX = true; 666 } else 667 to -= numCharacters; 668 669 if (foundFromX && foundToX) 670 break; 671 if (!m_run.rtl()) 672 currentX += m_harfBuzzRuns[i]->width(); 673 } 674 675 // The position in question might be just after the text. 676 if (!foundFromX) 677 fromX = 0; 678 if (!foundToX) 679 toX = m_run.rtl() ? 0 : m_totalWidth; 680 681 // Using floorf() and roundf() as the same as mac port. 682 if (fromX < toX) 683 return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - fromX), height); 684 return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), height); 685 } 686 687 } // namespace WebCore 688