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

Side by Side Diff: Source/platform/fonts/shaping/HarfBuzzShaper.cpp

Issue 957473003: Optimize complex text shaping (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Rebase again Created 5 years, 9 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
« no previous file with comments | « Source/platform/fonts/shaping/HarfBuzzShaper.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (c) 2012 Google Inc. All rights reserved. 2 * Copyright (c) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved. 3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
208 { 208 {
209 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ()); 209 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ());
210 return globalHarfBuzzRunCache; 210 return globalHarfBuzzRunCache;
211 } 211 }
212 212
213 static inline float harfBuzzPositionToFloat(hb_position_t value) 213 static inline float harfBuzzPositionToFloat(hb_position_t value)
214 { 214 {
215 return static_cast<float>(value) / (1 << 16); 215 return static_cast<float>(value) / (1 << 16);
216 } 216 }
217 217
218 static inline unsigned countGraphemesInCluster(const UChar* normalizedBuffer, un signed normalizedBufferLength, uint16_t startIndex, uint16_t endIndex) 218 static inline unsigned countGraphemesInCluster(const UChar* str, unsigned strLen gth, uint16_t startIndex, uint16_t endIndex)
219 { 219 {
220 if (startIndex > endIndex) { 220 if (startIndex > endIndex) {
221 uint16_t tempIndex = startIndex; 221 uint16_t tempIndex = startIndex;
222 startIndex = endIndex; 222 startIndex = endIndex;
223 endIndex = tempIndex; 223 endIndex = tempIndex;
224 } 224 }
225 uint16_t length = endIndex - startIndex; 225 uint16_t length = endIndex - startIndex;
226 ASSERT(static_cast<unsigned>(startIndex + length) <= normalizedBufferLength) ; 226 ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
227 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&normalizedBuf fer[startIndex], length); 227 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startInde x], length);
228 228
229 int cursorPos = cursorPosIterator->current(); 229 int cursorPos = cursorPosIterator->current();
230 int numGraphemes = -1; 230 int numGraphemes = -1;
231 while (0 <= cursorPos) { 231 while (0 <= cursorPos) {
232 cursorPos = cursorPosIterator->next(); 232 cursorPos = cursorPosIterator->next();
233 numGraphemes++; 233 numGraphemes++;
234 } 234 }
235 return numGraphemes < 0 ? 0 : numGraphemes; 235 return numGraphemes < 0 ? 0 : numGraphemes;
236 } 236 }
237 237
(...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 position += m_advances[glyphIndex]; 339 position += m_advances[glyphIndex];
340 } else { 340 } else {
341 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) { 341 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) {
342 position += m_advances[glyphIndex]; 342 position += m_advances[glyphIndex];
343 ++glyphIndex; 343 ++glyphIndex;
344 } 344 }
345 } 345 }
346 return position; 346 return position;
347 } 347 }
348 348
349 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest ination, unsigned* destinationLength)
350 {
351 unsigned position = 0;
352 bool error = false;
353 const UChar* source;
354 String stringFor8BitRun;
355 if (run.is8Bit()) {
356 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length());
357 source = stringFor8BitRun.characters16();
358 } else {
359 source = run.characters16();
360 }
361
362 *destinationLength = 0;
363 while (position < length) {
364 UChar32 character;
365 U16_NEXT(source, position, length, character);
366 // Don't normalize tabs as they are not treated as spaces for word-end.
367 if (run.normalizeSpace() && Character::isNormalizedCanvasSpaceCharacter( character))
368 character = space;
369 else if (Character::treatAsSpace(character) && character != characterTab ulation)
370 character = space;
371 else if (Character::treatAsZeroWidthSpaceInComplexScript(character))
372 character = zeroWidthSpace;
373
374 U16_APPEND(destination, *destinationLength, length, character, error);
375 ASSERT_UNUSED(error, !error);
376 }
377 }
378 349
379 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmph asisOrNot forTextEmphasis, HashSet<const SimpleFontData*>* fallbackFonts, FloatR ect* bounds) 350 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, ForTextEmph asisOrNot forTextEmphasis, HashSet<const SimpleFontData*>* fallbackFonts, FloatR ect* bounds)
380 : Shaper(font, run, forTextEmphasis, fallbackFonts, bounds) 351 : Shaper(font, run, forTextEmphasis, fallbackFonts, bounds)
381 , m_normalizedBufferLength(0)
382 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) 352 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing())
383 , m_letterSpacing(font->fontDescription().letterSpacing()) 353 , m_letterSpacing(font->fontDescription().letterSpacing())
384 , m_expansionOpportunityCount(0) 354 , m_expansionOpportunityCount(0)
385 , m_fromIndex(0) 355 , m_fromIndex(0)
386 , m_toIndex(m_run.length()) 356 , m_toIndex(m_run.length())
387 { 357 {
388 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
389 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm alizedBufferLength);
390 setExpansion(m_run.expansion()); 358 setExpansion(m_run.expansion());
391 setFontFeatures(); 359 setFontFeatures();
392 } 360 }
393 361
394 float HarfBuzzShaper::nextExpansionPerOpportunity() 362 float HarfBuzzShaper::nextExpansionPerOpportunity()
395 { 363 {
396 if (!m_expansionOpportunityCount) { 364 if (!m_expansionOpportunityCount) {
397 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha per does not match to the one in expansionOpportunityCount() 365 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha per does not match to the one in expansionOpportunityCount()
398 return 0; 366 return 0;
399 } 367 }
(...skipping 10 matching lines...) Expand all
410 // WebKit uses this to justify text. 378 // WebKit uses this to justify text.
411 void HarfBuzzShaper::setExpansion(float padding) 379 void HarfBuzzShaper::setExpansion(float padding)
412 { 380 {
413 m_expansion = padding; 381 m_expansion = padding;
414 if (!m_expansion) 382 if (!m_expansion)
415 return; 383 return;
416 384
417 // If we have padding to distribute, then we try to give an equal 385 // If we have padding to distribute, then we try to give an equal
418 // amount to each expansion opportunity. 386 // amount to each expansion opportunity.
419 bool isAfterExpansion = m_isAfterExpansion; 387 bool isAfterExpansion = m_isAfterExpansion;
420 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_normali zedBuffer.get(), m_normalizedBufferLength, m_run.direction(), isAfterExpansion, m_run.textJustify()); 388 if (m_run.is8Bit())
389 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_run .characters8(), m_run.length(), m_run.direction(), isAfterExpansion, m_run.textJ ustify());
390 else
391 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_run .characters16(), m_run.length(), m_run.direction(), isAfterExpansion, m_run.text Justify());
392
421 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) { 393 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) {
422 ASSERT(m_expansionOpportunityCount > 0); 394 ASSERT(m_expansionOpportunityCount > 0);
423 --m_expansionOpportunityCount; 395 --m_expansionOpportunityCount;
424 } 396 }
425 397
426 if (m_expansionOpportunityCount) 398 if (m_expansionOpportunityCount)
427 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; 399 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount;
428 else 400 else
429 m_expansionPerOpportunity = 0; 401 m_expansionPerOpportunity = 0;
430 } 402 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
530 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); 502 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
531 feature.value = settings->at(i).value(); 503 feature.value = settings->at(i).value();
532 feature.start = 0; 504 feature.start = 0;
533 feature.end = static_cast<unsigned>(-1); 505 feature.end = static_cast<unsigned>(-1);
534 m_features.append(feature); 506 m_features.append(feature);
535 } 507 }
536 } 508 }
537 509
538 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) 510 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
539 { 511 {
540 if (!createHarfBuzzRuns()) 512 if (m_run.is8Bit())
541 return false; 513 return shapeInternal<LChar>(glyphBuffer);
542 514 return shapeInternal<UChar>(glyphBuffer);
543 m_totalWidth = 0;
544 if (!shapeHarfBuzzRuns())
545 return false;
546
547 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
548 return false;
549
550 return true;
551 } 515 }
552 516
553 static inline int handleMultipleUChar( 517 static inline int handleMultipleUChar(
554 UChar32 character, 518 UChar32 character,
555 unsigned clusterLength, 519 unsigned clusterLength,
556 const SimpleFontData* currentFontData, 520 const SimpleFontData* currentFontData,
557 const UChar* currentCharacterPosition, 521 const UChar* currentCharacterPosition,
558 const UChar* markCharactersEnd, 522 const UChar* markCharactersEnd,
559 const UChar* normalizedBufferEnd) 523 const UChar* strEnd)
560 { 524 {
561 if (U_GET_GC_MASK(character) & U_GC_M_MASK) { 525 if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
562 int markLength = clusterLength; 526 int markLength = clusterLength;
563 while (markCharactersEnd < normalizedBufferEnd) { 527 while (markCharactersEnd < strEnd) {
564 UChar32 nextCharacter; 528 UChar32 nextCharacter;
565 int nextCharacterLength = 0; 529 int nextCharacterLength = 0;
566 U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter); 530 U16_NEXT(markCharactersEnd, nextCharacterLength, strEnd - markCharac tersEnd, nextCharacter);
567 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) 531 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
568 break; 532 break;
569 markLength += nextCharacterLength; 533 markLength += nextCharacterLength;
570 markCharactersEnd += nextCharacterLength; 534 markCharactersEnd += nextCharacterLength;
571 } 535 }
572 536
573 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacte rPosition, markCharactersEnd - currentCharacterPosition)) { 537 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacte rPosition, markCharactersEnd - currentCharacterPosition)) {
574 return markLength; 538 return markLength;
575 } 539 }
576 } 540 }
577 return 0; 541 return 0;
578 } 542 }
579 543
580 struct CandidateRun { 544 struct CandidateRun {
581 UChar32 character; 545 UChar32 character;
582 unsigned start; 546 unsigned start;
583 unsigned end; 547 unsigned end;
584 const SimpleFontData* fontData; 548 const SimpleFontData* fontData;
585 UScriptCode script; 549 UScriptCode script;
586 }; 550 };
587 551
588 static inline bool collectCandidateRuns(const UChar* normalizedBuffer, 552 template<typename CharType>
589 size_t bufferLength, const Font* font, Vector<CandidateRun>* runs, bool isSp aceNormalize) 553 bool collectCandidateRuns(const TextRun& textRun,
554 const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize)
590 { 555 {
591 const UChar* normalizedBufferEnd = normalizedBuffer + bufferLength; 556 const CharType* str = textRun.characters16();
592 SurrogatePairAwareTextIterator iterator(normalizedBuffer, 0, bufferLength, b ufferLength); 557 const CharType* strEnd = str + textRun.length();
558 SurrogatePairAwareTextIterator iterator(str, 0, textRun.length(), textRun.le ngth());
593 UChar32 character; 559 UChar32 character;
594 unsigned clusterLength = 0; 560 unsigned clusterLength = 0;
595 unsigned startIndexOfCurrentRun = 0; 561 unsigned startIndexOfCurrentRun = 0;
596 562
597 if (!iterator.consume(character, clusterLength)) 563 if (!iterator.consume(character, clusterLength))
598 return false; 564 return false;
599 565
600 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData; 566 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData;
601 UErrorCode errorCode = U_ZERO_ERROR; 567 UErrorCode errorCode = U_ZERO_ERROR;
602 UScriptCode nextScript = uscript_getScript(character, &errorCode); 568 UScriptCode nextScript = uscript_getScript(character, &errorCode);
603 if (U_FAILURE(errorCode)) 569 if (U_FAILURE(errorCode))
604 return false; 570 return false;
605 571
606 do { 572 do {
607 const UChar* currentCharacterPosition = iterator.characters(); 573 const CharType* currentCharacterPosition = iterator.characters();
608 const SimpleFontData* currentFontData = nextFontData; 574 const SimpleFontData* currentFontData = nextFontData;
609 UScriptCode currentScript = nextScript; 575 UScriptCode currentScript = nextScript;
610 576
611 UChar32 lastCharacter = character; 577 UChar32 lastCharacter = character;
612 for (iterator.advance(clusterLength); iterator.consume(character, cluste rLength); iterator.advance(clusterLength)) { 578 for (iterator.advance(clusterLength); iterator.consume(character, cluste rLength); iterator.advance(clusterLength)) {
613 if (Character::treatAsZeroWidthSpace(character)) 579 if (Character::treatAsZeroWidthSpace(character))
614 continue; 580 continue;
615 581
616 int length = handleMultipleUChar(character, clusterLength, currentFo ntData, currentCharacterPosition, iterator.characters() + clusterLength, normali zedBufferEnd); 582 int length = handleMultipleUChar(character, clusterLength, currentFo ntData, currentCharacterPosition, iterator.characters() + clusterLength, strEnd) ;
617 if (length) { 583 if (length) {
618 clusterLength = length; 584 clusterLength = length;
619 continue; 585 continue;
620 } 586 }
621 587
622 nextFontData = font->glyphDataForCharacter(character, false, isSpace Normalize).fontData; 588 nextFontData = font->glyphDataForCharacter(character, false, isSpace Normalize).fontData;
623 nextScript = uscript_getScript(character, &errorCode); 589 nextScript = uscript_getScript(character, &errorCode);
624 if (U_FAILURE(errorCode)) 590 if (U_FAILURE(errorCode))
625 return false; 591 return false;
626 if (lastCharacter == zeroWidthJoiner) 592 if (lastCharacter == zeroWidthJoiner)
627 currentFontData = nextFontData; 593 currentFontData = nextFontData;
628 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript)))) 594 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript))))
629 break; 595 break;
630 currentCharacterPosition = iterator.characters(); 596 currentCharacterPosition = iterator.characters();
631 lastCharacter = character; 597 lastCharacter = character;
632 } 598 }
633 599
634 CandidateRun run = { character, startIndexOfCurrentRun, iterator.current Character(), currentFontData, currentScript }; 600 CandidateRun run = { character, startIndexOfCurrentRun, iterator.current Character(), currentFontData, currentScript };
635 runs->append(run); 601 runs->append(run);
636 602
637 startIndexOfCurrentRun = iterator.currentCharacter(); 603 startIndexOfCurrentRun = iterator.currentCharacter();
638 } while (iterator.consume(character, clusterLength)); 604 } while (iterator.consume(character, clusterLength));
639 605
640 return true; 606 return true;
641 } 607 }
642 608
609 template<>
610 bool collectCandidateRuns<LChar>(const TextRun& textRun,
611 const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize)
612 {
613 const LChar* str = textRun.characters8();
614 UChar32 character = *str;
615 const SimpleFontData* fontData = font->glyphDataForCharacter(character,
616 false, isSpaceNormalize).fontData;
617
618 // For 8-bit runs we do not need to split based on script or check for
619 // clusters as the entire run is guaranteed to be latin-1.
620 CandidateRun run = { *str, 0, textRun.length(), fontData, USCRIPT_LATIN };
621 runs->append(run);
622 return true;
623 }
624
643 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, 625 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length,
644 CandidateRun& adjacentRun) 626 CandidateRun& adjacentRun)
645 { 627 {
646 for (int i = 0; i < length; i++) { 628 for (int i = 0; i < length; i++) {
647 if (scriptExtensions[i] == adjacentRun.script) 629 if (scriptExtensions[i] == adjacentRun.script)
648 return true; 630 return true;
649 } 631 }
650 return false; 632 return false;
651 } 633 }
652 634
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
722 704
723 i = std::max(i, nextResolvedRun); 705 i = std::max(i, nextResolvedRun);
724 } 706 }
725 return true; 707 return true;
726 } 708 }
727 709
728 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact er length 710 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact er length
729 // because most characters have break opportunities both before and after. 711 // because most characters have break opportunities both before and after.
730 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter() 712 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter()
731 { 713 {
732 ASSERT(m_normalizedBufferLength == 1); 714 ASSERT(m_run.length() == 1);
733 UChar32 character = m_normalizedBuffer[0]; 715 UChar32 character = m_run[0];
734 if (!U16_IS_SINGLE(character)) 716 if (!U16_IS_SINGLE(character))
735 return false; 717 return false;
736 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character, fa lse, m_run.normalizeSpace()).fontData; 718 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character,
719 false, m_run.normalizeSpace()).fontData;
737 UErrorCode errorCode = U_ZERO_ERROR; 720 UErrorCode errorCode = U_ZERO_ERROR;
738 UScriptCode script = uscript_getScript(character, &errorCode); 721 UScriptCode script = uscript_getScript(character, &errorCode);
739 if (U_FAILURE(errorCode)) 722 if (U_FAILURE(errorCode))
740 return false; 723 return false;
741 addHarfBuzzRun(0, 1, fontData, script); 724 addHarfBuzzRun(0, 1, fontData, script);
742 return true; 725 return true;
743 } 726 }
744 727
728 template<typename CharType>
729 bool HarfBuzzShaper::shapeInternal(GlyphBuffer* glyphBuffer)
730 {
731 if (!createHarfBuzzRuns<CharType>())
732 return false;
733
734 m_totalWidth = 0;
735 if (!shapeHarfBuzzRuns<CharType>())
736 return false;
737
738 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
739 return false;
740
741 return true;
742 }
743
744 template<typename CharType>
745 bool HarfBuzzShaper::createHarfBuzzRuns() 745 bool HarfBuzzShaper::createHarfBuzzRuns()
746 { 746 {
747 if (m_normalizedBufferLength == 1) 747 if (m_run.length() == 1)
748 return createHarfBuzzRunsForSingleCharacter(); 748 return createHarfBuzzRunsForSingleCharacter();
749 749
750 Vector<CandidateRun> candidateRuns; 750 Vector<CandidateRun> candidateRuns;
751 if (!collectCandidateRuns(m_normalizedBuffer.get(), 751 if (!collectCandidateRuns<CharType>(m_run, m_font, &candidateRuns,
752 m_normalizedBufferLength, m_font, &candidateRuns, m_run.normalizeSpace() )) 752 m_run.normalizeSpace()))
753 return false; 753 return false;
754 754
755 if (!resolveCandidateRuns(candidateRuns)) 755 if (!resolveCandidateRuns(candidateRuns))
756 return false; 756 return false;
757 757
758 size_t length = candidateRuns.size(); 758 size_t length = candidateRuns.size();
759 for (size_t i = 0; i < length; ) { 759 for (size_t i = 0; i < length; ) {
760 CandidateRun& run = candidateRuns[i]; 760 CandidateRun& run = candidateRuns[i];
761 CandidateRun lastMatchingRun = run; 761 CandidateRun lastMatchingRun = run;
762 for (i++; i < length; i++) { 762 for (i++; i < length; i++) {
763 if (candidateRuns[i].script != run.script 763 if (candidateRuns[i].script != run.script
764 || candidateRuns[i].fontData != run.fontData) 764 || candidateRuns[i].fontData != run.fontData)
765 break; 765 break;
766 lastMatchingRun = candidateRuns[i]; 766 lastMatchingRun = candidateRuns[i];
767 } 767 }
768 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script) ; 768 if (lastMatchingRun.end > run.start)
769 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.scr ipt);
769 } 770 }
770 return !m_harfBuzzRuns.isEmpty(); 771 return !m_harfBuzzRuns.isEmpty();
771 } 772 }
772 773
773 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built 774 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
774 // without hb-icu. See http://crbug.com/356929 775 // without hb-icu. See http://crbug.com/356929
775 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) 776 static inline hb_script_t ICUScriptToHBScript(UScriptCode script)
776 { 777 {
777 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) 778 if (UNLIKELY(script == USCRIPT_INVALID_CODE))
778 return HB_SCRIPT_INVALID; 779 return HB_SCRIPT_INVALID;
(...skipping 14 matching lines...) Expand all
793 ASSERT(endCharacter > startCharacter); 794 ASSERT(endCharacter > startCharacter);
794 ASSERT(script != USCRIPT_INVALID_CODE); 795 ASSERT(script != USCRIPT_INVALID_CODE);
795 if (m_fallbackFonts) 796 if (m_fallbackFonts)
796 trackNonPrimaryFallbackFont(fontData); 797 trackNonPrimaryFallbackFont(fontData);
797 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, 798 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData,
798 startCharacter, endCharacter - startCharacter, 799 startCharacter, endCharacter - startCharacter,
799 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription(). orientation(), fontData), 800 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription(). orientation(), fontData),
800 ICUScriptToHBScript(script))); 801 ICUScriptToHBScript(script)));
801 } 802 }
802 803
803 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir,
804 const String& localeString, const CachedShapingResults* cachedResults)
805 {
806 ASSERT(cachedResults);
807 return cachedResults->dir == dir
808 && cachedResults->font == *font
809 && !cachedResults->font.loadingCustomFonts()
810 && !font->loadingCustomFonts()
811 && cachedResults->locale == localeString;
812 }
813
814 static const uint16_t* toUint16(const UChar* src) 804 static const uint16_t* toUint16(const UChar* src)
815 { 805 {
816 // FIXME: This relies on undefined behavior however it works on the 806 // FIXME: This relies on undefined behavior however it works on the
817 // current versions of all compilers we care about and avoids making 807 // current versions of all compilers we care about and avoids making
818 // a copy of the string. 808 // a copy of the string.
819 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t"); 809 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t");
820 return reinterpret_cast<const uint16_t*>(src); 810 return reinterpret_cast<const uint16_t*>(src);
821 } 811 }
822 812
823 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, 813 template<typename CharType>
824 const FontDescription& fontDescription, const UChar* normalizedBuffer, 814 inline const CharType* charactersForRun(const TextRun& textRun,
815 unsigned startIndex)
816 {
817 return textRun.data16(startIndex);
818 }
819
820 template<>
821 inline const LChar* charactersForRun<LChar>(const TextRun& textRun,
822 unsigned startIndex)
823 {
824 return textRun.data8(startIndex);
825 }
826
827 template<typename CharType>
828 inline const CharType* charactersForString(const String& string)
829 {
830 return string.characters16();
831 }
832
833 template<>
834 inline const LChar* charactersForString<LChar>(const String& string)
835 {
836 return string.characters8();
837 }
838
839 template<typename CharType>
840 inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer,
841 const CharType* characters, unsigned length)
842 {
843 hb_buffer_add_utf16(buffer, toUint16(characters), length, 0, length);
844 }
845
846 template<>
847 inline void addToHarfBuzzBufferInternal<LChar>(hb_buffer_t* buffer,
848 const LChar* characters, unsigned length)
849 {
850 // On linux we use the system version of harfbuzz so we cannot depend on
851 // hb_buffer_add_latin1 being available as it was only added in 0.9.38.
852 // FIXME: Remove this hack once all supported distros have HB >= 0.9.38.
853 // https://crbug.com/462689
854 #if OS(LINUX)
855 String converted = String::make16BitFrom8BitSource(characters, length);
856 hb_buffer_add_utf16(buffer, toUint16(converted.characters16()),
857 length, 0, length);
858 #else
859 hb_buffer_add_latin1(buffer, characters, length, 0, length);
860 #endif
861 }
862
863 template<typename CharType>
864 inline void addToHarfBuzzBuffer(hb_buffer_t* buffer,
865 const FontDescription& fontDescription, const TextRun& textRun,
825 unsigned startIndex, unsigned numCharacters) 866 unsigned startIndex, unsigned numCharacters)
826 { 867 {
827 if (fontDescription.variant() == FontVariantSmallCaps 868 if (fontDescription.variant() == FontVariantSmallCaps
828 && u_islower(normalizedBuffer[startIndex])) { 869 && u_islower(textRun[startIndex])) {
829 String upperText = String(normalizedBuffer + startIndex, numCharacters) 870 String upperText = String(charactersForRun<CharType>(
830 .upper(); 871 textRun, startIndex), numCharacters).upper();
831 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call 872 // If TextRun is 16 bit upperText should be 16 bit too.
832 // makeUpper(). 873 ASSERT(upperText.is8Bit() == textRun.is8Bit());
833 ASSERT(!upperText.is8Bit()); 874 addToHarfBuzzBufferInternal<CharType>(buffer,
834 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), 875 charactersForString<CharType>(upperText), numCharacters);
835 numCharacters, 0, numCharacters);
836 } else { 876 } else {
837 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex), 877 addToHarfBuzzBufferInternal(buffer,
838 numCharacters, 0, numCharacters); 878 charactersForRun<CharType>(textRun, startIndex), numCharacters);
839 } 879 }
840 } 880 }
841 881
882 template<typename CharType, bool normalizeSpace>
883 static inline UChar32 normalizeCharacter(UChar32 character)
884 {
885 if (normalizeSpace && Character::isNormalizedCanvasSpaceCharacter(character) )
886 return space;
887 if (Character::treatAsSpace(character) && character != characterTabulation)
888 return space;
889 if (Character::treatAsZeroWidthSpaceInComplexScript(static_cast<CharType>(ch aracter)))
890 return zeroWidthSpace;
891 return character;
892 }
893
894 template<typename CharType, bool normalizeSpace>
895 inline void normalizeHarfBuzzBuffer(hb_buffer_t* buffer)
896 {
897 unsigned length;
898 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(buffer, &length);
899 for (unsigned i = 0; i < length; i++) {
900 UChar32 character = glyphInfos[i].codepoint;
901 UChar32 normalized = normalizeCharacter<CharType, normalizeSpace>(charac ter);
902 if (character != normalized)
903 glyphInfos[i].codepoint = normalized;
904 }
905 }
906
907 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir,
908 const String& localeString, const CachedShapingResults* cachedResults)
909 {
910 ASSERT(cachedResults);
911 return cachedResults->dir == dir
912 && cachedResults->font == *font
913 && !cachedResults->font.loadingCustomFonts()
914 && !font->loadingCustomFonts()
915 && cachedResults->locale == localeString;
916 }
917
918 template<typename CharType>
842 bool HarfBuzzShaper::shapeHarfBuzzRuns() 919 bool HarfBuzzShaper::shapeHarfBuzzRuns()
843 { 920 {
844 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy); 921 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy);
845 922
846 HarfBuzzRunCache& runCache = harfBuzzRunCache(); 923 HarfBuzzRunCache& runCache = harfBuzzRunCache();
847 const FontDescription& fontDescription = m_font->fontDescription(); 924 const FontDescription& fontDescription = m_font->fontDescription();
848 const String& localeString = fontDescription.locale(); 925 const String& localeString = fontDescription.locale();
849 CString locale = localeString.latin1(); 926 CString locale = localeString.latin1();
850 HarfBuzzRun* previousRun = nullptr; 927 HarfBuzzRun* previousRun = nullptr;
851 928
852 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 929 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
853 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; 930 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
854 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 931 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
855 932
856 const SimpleFontData* currentFontData = currentRun->fontData(); 933 const SimpleFontData* currentFontData = currentRun->fontData();
857 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData()); 934 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData());
858 HarfBuzzFace* face = platformData->harfBuzzFace(); 935 HarfBuzzFace* face = platformData->harfBuzzFace();
859 if (!face) 936 if (!face)
860 return false; 937 return false;
861 938
862 hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(loc ale.data(), locale.length())); 939 hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(loc ale.data(), locale.length()));
863 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); 940 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
864 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction()); 941 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction());
865 942
866 const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex(); 943 const CharType* src = charactersForRun<CharType>(m_run, currentRun->star tIndex());
867 std::wstring key(src, src + currentRun->numCharacters()); 944 std::wstring key(src, src + currentRun->numCharacters());
868 945
869 CachedShapingResults* cachedResults = runCache.find(key); 946 CachedShapingResults* cachedResults = runCache.find(key);
870 if (cachedResults) { 947 if (cachedResults) {
871 if (isValidCachedResult(m_font, currentRun->direction(), 948 if (isValidCachedResult(m_font, currentRun->direction(),
872 localeString, cachedResults)) { 949 localeString, cachedResults)) {
873 currentRun->applyShapeResult(cachedResults->buffer); 950 currentRun->applyShapeResult(cachedResults->buffer);
874 setGlyphPositionsForHarfBuzzRun(currentRun, 951 setGlyphPositionsForHarfBuzzRun(currentRun,
875 cachedResults->buffer, previousRun); 952 cachedResults->buffer, previousRun);
876 hb_buffer_clear_contents(harfBuzzBuffer.get()); 953 hb_buffer_clear_contents(harfBuzzBuffer.get());
877 runCache.moveToBack(cachedResults); 954 runCache.moveToBack(cachedResults);
878 previousRun = currentRun; 955 previousRun = currentRun;
879 continue; 956 continue;
880 } 957 }
881 runCache.remove(cachedResults); 958 runCache.remove(cachedResults);
882 } 959 }
883 960
884 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle 961 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle
885 // for combining marks at the beginning of runs. 962 // for combining marks at the beginning of runs.
886 static const uint16_t preContext = space; 963 static const uint16_t preContext = space;
887 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); 964 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
888 965
889 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), 966 addToHarfBuzzBuffer<CharType>(harfBuzzBuffer.get(),
890 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(), 967 fontDescription, m_run, currentRun->startIndex(),
891 currentRun->numCharacters()); 968 currentRun->numCharacters());
892 969
970 if (m_run.normalizeSpace())
971 normalizeHarfBuzzBuffer<CharType, true>(harfBuzzBuffer.get());
972 else
973 normalizeHarfBuzzBuffer<CharType, false>(harfBuzzBuffer.get());
974
893 if (fontDescription.orientation() == Vertical) 975 if (fontDescription.orientation() == Vertical)
894 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); 976 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
895 977
896 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy); 978 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy);
897 979
898 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); 980 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
899 currentRun->applyShapeResult(harfBuzzBuffer.get()); 981 currentRun->applyShapeResult(harfBuzzBuffer.get());
900 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get(), previo usRun); 982 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get(), previo usRun);
901 983
902 runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_fo nt, currentRun->direction(), localeString)); 984 runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_fo nt, currentRun->direction(), localeString));
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
934 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. 1016 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
935 for (size_t i = 0; i < numGlyphs; ++i) { 1017 for (size_t i = 0; i < numGlyphs; ++i) {
936 bool runEnd = i + 1 == numGlyphs; 1018 bool runEnd = i + 1 == numGlyphs;
937 uint16_t glyph = glyphInfos[i].codepoint; 1019 uint16_t glyph = glyphInfos[i].codepoint;
938 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); 1020 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
939 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); 1021 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
940 // One out of x_advance and y_advance is zero, depending on 1022 // One out of x_advance and y_advance is zero, depending on
941 // whether the buffer direction is horizontal or vertical. 1023 // whether the buffer direction is horizontal or vertical.
942 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance); 1024 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance);
943 1025
944 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster; 1026 int currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].clu ster;
945 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); 1027 RELEASE_ASSERT(m_run.length() > currentCharacterIndex);
946 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster; 1028 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster;
947 float spacing = 0; 1029 float spacing = 0;
948 1030
949 glyphToCharacterIndexes[i] = glyphInfos[i].cluster; 1031 glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
950 1032
951 if (isClusterEnd) 1033 if (isClusterEnd)
952 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, previ ousRun, offsetX, totalAdvance); 1034 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, previ ousRun, offsetX, totalAdvance);
953 1035
954 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { 1036 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
955 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); 1037 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
(...skipping 19 matching lines...) Expand all
975 1057
976 totalAdvance += advance; 1058 totalAdvance += advance;
977 } 1059 }
978 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); 1060 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
979 m_totalWidth += currentRun->width(); 1061 m_totalWidth += currentRun->width();
980 } 1062 }
981 1063
982 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex, unsigned currentCharacterIndex, HarfBuzzRun* previousRun, float& offsetX, float& totalAdvance) 1064 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex, unsigned currentCharacterIndex, HarfBuzzRun* previousRun, float& offsetX, float& totalAdvance)
983 { 1065 {
984 float spacing = 0; 1066 float spacing = 0;
985 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; 1067 UChar32 character = normalizeCharacter<UChar, false>(m_run[currentCharacterI ndex]);
986 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) 1068 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character))
987 spacing += m_letterSpacing; 1069 spacing += m_letterSpacing;
988 1070
989 bool treatAsSpace = Character::treatAsSpace(character); 1071 bool treatAsSpace = Character::treatAsSpace(character);
990 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al lowTabs())) 1072 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al lowTabs()))
991 spacing += m_wordSpacingAdjustment; 1073 spacing += m_wordSpacingAdjustment;
992 1074
993 if (!m_expansionOpportunityCount) 1075 if (!m_expansionOpportunityCount)
994 return spacing; 1076 return spacing;
995 1077
996 if (treatAsSpace) { 1078 if (treatAsSpace) {
997 spacing += nextExpansionPerOpportunity(); 1079 spacing += nextExpansionPerOpportunity();
998 m_isAfterExpansion = true; 1080 m_isAfterExpansion = true;
999 return spacing; 1081 return spacing;
1000 } 1082 }
1001 1083
1002 if (m_run.textJustify() != TextJustify::TextJustifyAuto) { 1084 if (m_run.textJustify() != TextJustify::TextJustifyAuto) {
1003 m_isAfterExpansion = false; 1085 m_isAfterExpansion = false;
1004 return spacing; 1086 return spacing;
1005 } 1087 }
1006 1088
1007 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte r each character. 1089 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte r each character.
1008 // http://www.w3.org/TR/jlreq/#line_adjustment 1090 // http://www.w3.org/TR/jlreq/#line_adjustment
1009 if (U16_IS_LEAD(character) && currentCharacterIndex + 1 < m_normalizedBuffer Length && U16_IS_TRAIL(m_normalizedBuffer[currentCharacterIndex + 1])) 1091 if (!m_run.is8Bit() && U16_IS_LEAD(character) && currentCharacterIndex + 1 < static_cast<unsigned>(m_run.charactersLength()) && U16_IS_TRAIL(m_run[currentCh aracterIndex + 1])) {
1010 character = U16_GET_SUPPLEMENTARY(character, m_normalizedBuffer[currentC haracterIndex + 1]); 1092 UChar32 nextChar = normalizeCharacter<UChar, false>(m_run[currentCharact erIndex + 1]);
1093 character = U16_GET_SUPPLEMENTARY(character, nextChar);
1094 }
1011 if (!Character::isCJKIdeographOrSymbol(character)) { 1095 if (!Character::isCJKIdeographOrSymbol(character)) {
1012 m_isAfterExpansion = false; 1096 m_isAfterExpansion = false;
1013 return spacing; 1097 return spacing;
1014 } 1098 }
1015 1099
1016 if (!m_isAfterExpansion) { 1100 if (!m_isAfterExpansion) {
1017 // Take the expansion opportunity before this ideograph. 1101 // Take the expansion opportunity before this ideograph.
1018 float expandBefore = nextExpansionPerOpportunity(); 1102 float expandBefore = nextExpansionPerOpportunity();
1019 if (expandBefore) { 1103 if (expandBefore) {
1020 if (glyphIndex > 0) { 1104 if (glyphIndex > 0) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
1116 1200
1117 clusterAdvance += advances[i]; 1201 clusterAdvance += advances[i];
1118 1202
1119 if (isClusterEnd) { 1203 if (isClusterEnd) {
1120 uint16_t clusterEnd; 1204 uint16_t clusterEnd;
1121 if (m_run.rtl()) 1205 if (m_run.rtl())
1122 clusterEnd = currentCharacterIndex; 1206 clusterEnd = currentCharacterIndex;
1123 else 1207 else
1124 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n umCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1]; 1208 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n umCharacters() : currentRun->startIndex() + glyphToCharacterIndexes[i + 1];
1125 1209
1126 graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get( ), m_normalizedBufferLength, clusterStart, clusterEnd); 1210 graphemesInCluster = m_run.is8Bit() ? 1 : countGraphemesInCluster(m_ run.characters16(), m_run.length(), clusterStart, clusterEnd);
1127 if (!graphemesInCluster || !clusterAdvance) 1211 if (!graphemesInCluster || !clusterAdvance)
1128 continue; 1212 continue;
1129 1213
1130 float glyphAdvanceX = clusterAdvance / graphemesInCluster; 1214 float glyphAdvanceX = clusterAdvance / graphemesInCluster;
1131 for (unsigned j = 0; j < graphemesInCluster; ++j) { 1215 for (unsigned j = 0; j < graphemesInCluster; ++j) {
1132 // Do not put emphasis marks on space, separator, and control ch aracters. 1216 // Do not put emphasis marks on space, separator, and control ch aracters.
1133 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[curre ntCharacterIndex]) ? 1 : 0; 1217 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[curre ntCharacterIndex]) ? 1 : 0;
1134 // The emphasis code expects mid-glyph offsets. 1218 // The emphasis code expects mid-glyph offsets.
1135 glyphBuffer->add(glyphToAdd, currentRun->fontData(), advanceSoFa r + glyphAdvanceX / 2); 1219 glyphBuffer->add(glyphToAdd, currentRun->fontData(), advanceSoFa r + glyphAdvanceX / 2);
1136 advanceSoFar += glyphAdvanceX; 1220 advanceSoFar += glyphAdvanceX;
(...skipping 23 matching lines...) Expand all
1160 } 1244 }
1161 return glyphBuffer->size(); 1245 return glyphBuffer->size();
1162 } 1246 }
1163 1247
1164 int HarfBuzzShaper::offsetForPosition(float targetX) 1248 int HarfBuzzShaper::offsetForPosition(float targetX)
1165 { 1249 {
1166 int charactersSoFar = 0; 1250 int charactersSoFar = 0;
1167 float currentX = 0; 1251 float currentX = 0;
1168 1252
1169 if (m_run.rtl()) { 1253 if (m_run.rtl()) {
1170 charactersSoFar = m_normalizedBufferLength; 1254 charactersSoFar = m_run.length();
1171 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { 1255 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
1172 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); 1256 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
1173 float nextX = currentX + m_harfBuzzRuns[i]->width(); 1257 float nextX = currentX + m_harfBuzzRuns[i]->width();
1174 float offsetForRun = targetX - currentX; 1258 float offsetForRun = targetX - currentX;
1175 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) { 1259 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
1176 // The x value in question is within this script run. 1260 // The x value in question is within this script run.
1177 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun); 1261 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun);
1178 return charactersSoFar + index; 1262 return charactersSoFar + index;
1179 } 1263 }
1180 currentX = nextX; 1264 currentX = nextX;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1238 // possibly invalid from, to arguments. 1322 // possibly invalid from, to arguments.
1239 if (!foundToX && !foundFromX) 1323 if (!foundToX && !foundFromX)
1240 fromX = toX = 0; 1324 fromX = toX = 0;
1241 1325
1242 if (fromX < toX) 1326 if (fromX < toX)
1243 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); 1327 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
1244 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); 1328 return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
1245 } 1329 }
1246 1330
1247 } // namespace blink 1331 } // namespace blink
OLDNEW
« no previous file with comments | « Source/platform/fonts/shaping/HarfBuzzShaper.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698