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

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: 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 : m_font(font) 351 : m_font(font)
381 , m_normalizedBufferLength(0)
382 , m_run(run) 352 , m_run(run)
383 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) 353 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing())
384 , m_expansion(0) 354 , m_expansion(0)
385 , m_letterSpacing(font->fontDescription().letterSpacing()) 355 , m_letterSpacing(font->fontDescription().letterSpacing())
386 , m_expansionPerOpportunity(0) 356 , m_expansionPerOpportunity(0)
387 , m_expansionOpportunityCount(0) 357 , m_expansionOpportunityCount(0)
388 , m_isAfterExpansion(!run.allowsLeadingExpansion()) 358 , m_isAfterExpansion(!run.allowsLeadingExpansion())
389 , m_fromIndex(0) 359 , m_fromIndex(0)
390 , m_toIndex(m_run.length()) 360 , m_toIndex(m_run.length())
391 , m_forTextEmphasis(forTextEmphasis) 361 , m_forTextEmphasis(forTextEmphasis)
392 , m_glyphBoundingBox(bounds) 362 , m_glyphBoundingBox(bounds)
393 , m_fallbackFonts(fallbackFonts) 363 , m_fallbackFonts(fallbackFonts)
394 { 364 {
395 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
396 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm alizedBufferLength);
397 setExpansion(m_run.expansion()); 365 setExpansion(m_run.expansion());
398 setFontFeatures(); 366 setFontFeatures();
399 } 367 }
400 368
401 float HarfBuzzShaper::nextExpansionPerOpportunity() 369 float HarfBuzzShaper::nextExpansionPerOpportunity()
402 { 370 {
403 if (!m_expansionOpportunityCount) { 371 if (!m_expansionOpportunityCount) {
404 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha per does not match to the one in expansionOpportunityCount() 372 ASSERT_NOT_REACHED(); // failures indicate that the logic in HarfBuzzSha per does not match to the one in expansionOpportunityCount()
405 return 0; 373 return 0;
406 } 374 }
(...skipping 10 matching lines...) Expand all
417 // WebKit uses this to justify text. 385 // WebKit uses this to justify text.
418 void HarfBuzzShaper::setExpansion(float padding) 386 void HarfBuzzShaper::setExpansion(float padding)
419 { 387 {
420 m_expansion = padding; 388 m_expansion = padding;
421 if (!m_expansion) 389 if (!m_expansion)
422 return; 390 return;
423 391
424 // If we have padding to distribute, then we try to give an equal 392 // If we have padding to distribute, then we try to give an equal
425 // amount to each expansion opportunity. 393 // amount to each expansion opportunity.
426 bool isAfterExpansion = m_isAfterExpansion; 394 bool isAfterExpansion = m_isAfterExpansion;
427 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_normali zedBuffer.get(), m_normalizedBufferLength, m_run.direction(), isAfterExpansion, m_run.textJustify()); 395 if (m_run.is8Bit())
396 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_run .characters8(), m_run.length(), m_run.direction(), isAfterExpansion, m_run.textJ ustify());
397 else
398 m_expansionOpportunityCount = Character::expansionOpportunityCount(m_run .characters16(), m_run.length(), m_run.direction(), isAfterExpansion, m_run.text Justify());
399
428 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) { 400 if (isAfterExpansion && !m_run.allowsTrailingExpansion()) {
429 ASSERT(m_expansionOpportunityCount > 0); 401 ASSERT(m_expansionOpportunityCount > 0);
430 --m_expansionOpportunityCount; 402 --m_expansionOpportunityCount;
431 } 403 }
432 404
433 if (m_expansionOpportunityCount) 405 if (m_expansionOpportunityCount)
434 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; 406 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount;
435 else 407 else
436 m_expansionPerOpportunity = 0; 408 m_expansionPerOpportunity = 0;
437 } 409 }
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); 509 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
538 feature.value = settings->at(i).value(); 510 feature.value = settings->at(i).value();
539 feature.start = 0; 511 feature.start = 0;
540 feature.end = static_cast<unsigned>(-1); 512 feature.end = static_cast<unsigned>(-1);
541 m_features.append(feature); 513 m_features.append(feature);
542 } 514 }
543 } 515 }
544 516
545 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) 517 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
546 { 518 {
547 if (!createHarfBuzzRuns()) 519 if (m_run.is8Bit())
548 return false; 520 return shapeInternal<LChar>(glyphBuffer);
549 521 return shapeInternal<UChar>(glyphBuffer);
550 m_totalWidth = 0;
551 if (!shapeHarfBuzzRuns())
552 return false;
553
554 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
555 return false;
556
557 return true;
558 } 522 }
559 523
560 static inline int handleMultipleUChar( 524 static inline int handleMultipleUChar(
561 UChar32 character, 525 UChar32 character,
562 unsigned clusterLength, 526 unsigned clusterLength,
563 const SimpleFontData* currentFontData, 527 const SimpleFontData* currentFontData,
564 const UChar* currentCharacterPosition, 528 const UChar* currentCharacterPosition,
565 const UChar* markCharactersEnd, 529 const UChar* markCharactersEnd,
566 const UChar* normalizedBufferEnd) 530 const UChar* strEnd)
567 { 531 {
568 if (U_GET_GC_MASK(character) & U_GC_M_MASK) { 532 if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
569 int markLength = clusterLength; 533 int markLength = clusterLength;
570 while (markCharactersEnd < normalizedBufferEnd) { 534 while (markCharactersEnd < strEnd) {
571 UChar32 nextCharacter; 535 UChar32 nextCharacter;
572 int nextCharacterLength = 0; 536 int nextCharacterLength = 0;
573 U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedBufferEnd - markCharactersEnd, nextCharacter); 537 U16_NEXT(markCharactersEnd, nextCharacterLength, strEnd - markCharac tersEnd, nextCharacter);
574 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK)) 538 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
575 break; 539 break;
576 markLength += nextCharacterLength; 540 markLength += nextCharacterLength;
577 markCharactersEnd += nextCharacterLength; 541 markCharactersEnd += nextCharacterLength;
578 } 542 }
579 543
580 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacte rPosition, markCharactersEnd - currentCharacterPosition)) { 544 if (currentFontData->canRenderCombiningCharacterSequence(currentCharacte rPosition, markCharactersEnd - currentCharacterPosition)) {
581 return markLength; 545 return markLength;
582 } 546 }
583 } 547 }
584 return 0; 548 return 0;
585 } 549 }
586 550
587 struct CandidateRun { 551 struct CandidateRun {
588 UChar32 character; 552 UChar32 character;
589 unsigned start; 553 unsigned start;
590 unsigned end; 554 unsigned end;
591 const SimpleFontData* fontData; 555 const SimpleFontData* fontData;
592 UScriptCode script; 556 UScriptCode script;
593 }; 557 };
594 558
595 static inline bool collectCandidateRuns(const UChar* normalizedBuffer, 559 template<typename CharType>
596 size_t bufferLength, const Font* font, Vector<CandidateRun>* runs, bool isSp aceNormalize) 560 bool collectCandidateRuns(const TextRun& textRun,
561 const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize)
597 { 562 {
598 const UChar* normalizedBufferEnd = normalizedBuffer + bufferLength; 563 const CharType* str = textRun.characters16();
599 SurrogatePairAwareTextIterator iterator(normalizedBuffer, 0, bufferLength, b ufferLength); 564 const CharType* strEnd = str + textRun.length();
565 SurrogatePairAwareTextIterator iterator(str, 0, textRun.length(), textRun.le ngth());
600 UChar32 character; 566 UChar32 character;
601 unsigned clusterLength = 0; 567 unsigned clusterLength = 0;
602 unsigned startIndexOfCurrentRun = 0; 568 unsigned startIndexOfCurrentRun = 0;
603 569
604 if (!iterator.consume(character, clusterLength)) 570 if (!iterator.consume(character, clusterLength))
605 return false; 571 return false;
606 572
607 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData; 573 const SimpleFontData* nextFontData = font->glyphDataForCharacter(character, false, isSpaceNormalize).fontData;
608 UErrorCode errorCode = U_ZERO_ERROR; 574 UErrorCode errorCode = U_ZERO_ERROR;
609 UScriptCode nextScript = uscript_getScript(character, &errorCode); 575 UScriptCode nextScript = uscript_getScript(character, &errorCode);
610 if (U_FAILURE(errorCode)) 576 if (U_FAILURE(errorCode))
611 return false; 577 return false;
612 578
613 do { 579 do {
614 const UChar* currentCharacterPosition = iterator.characters(); 580 const CharType* currentCharacterPosition = iterator.characters();
615 const SimpleFontData* currentFontData = nextFontData; 581 const SimpleFontData* currentFontData = nextFontData;
616 UScriptCode currentScript = nextScript; 582 UScriptCode currentScript = nextScript;
617 583
618 UChar32 lastCharacter = character; 584 UChar32 lastCharacter = character;
619 for (iterator.advance(clusterLength); iterator.consume(character, cluste rLength); iterator.advance(clusterLength)) { 585 for (iterator.advance(clusterLength); iterator.consume(character, cluste rLength); iterator.advance(clusterLength)) {
620 if (Character::treatAsZeroWidthSpace(character)) 586 if (Character::treatAsZeroWidthSpace(character))
621 continue; 587 continue;
622 588
623 int length = handleMultipleUChar(character, clusterLength, currentFo ntData, currentCharacterPosition, iterator.characters() + clusterLength, normali zedBufferEnd); 589 int length = handleMultipleUChar(character, clusterLength, currentFo ntData, currentCharacterPosition, iterator.characters() + clusterLength, strEnd) ;
624 if (length) { 590 if (length) {
625 clusterLength = length; 591 clusterLength = length;
626 continue; 592 continue;
627 } 593 }
628 594
629 nextFontData = font->glyphDataForCharacter(character, false, isSpace Normalize).fontData; 595 nextFontData = font->glyphDataForCharacter(character, false, isSpace Normalize).fontData;
630 nextScript = uscript_getScript(character, &errorCode); 596 nextScript = uscript_getScript(character, &errorCode);
631 if (U_FAILURE(errorCode)) 597 if (U_FAILURE(errorCode))
632 return false; 598 return false;
633 if (lastCharacter == zeroWidthJoiner) 599 if (lastCharacter == zeroWidthJoiner)
634 currentFontData = nextFontData; 600 currentFontData = nextFontData;
635 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript)))) 601 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript))))
636 break; 602 break;
637 currentCharacterPosition = iterator.characters(); 603 currentCharacterPosition = iterator.characters();
638 lastCharacter = character; 604 lastCharacter = character;
639 } 605 }
640 606
641 CandidateRun run = { character, startIndexOfCurrentRun, iterator.current Character(), currentFontData, currentScript }; 607 CandidateRun run = { character, startIndexOfCurrentRun, iterator.current Character(), currentFontData, currentScript };
642 runs->append(run); 608 runs->append(run);
643 609
644 startIndexOfCurrentRun = iterator.currentCharacter(); 610 startIndexOfCurrentRun = iterator.currentCharacter();
645 } while (iterator.consume(character, clusterLength)); 611 } while (iterator.consume(character, clusterLength));
646 612
647 return true; 613 return true;
648 } 614 }
649 615
616 template<>
617 bool collectCandidateRuns<LChar>(const TextRun& textRun,
618 const Font* font, Vector<CandidateRun>* runs, bool isSpaceNormalize)
619 {
620 const LChar* str = textRun.characters8();
621 UChar32 character = *str;
622 const SimpleFontData* fontData = font->glyphDataForCharacter(character,
623 false, isSpaceNormalize).fontData;
624
625 // For 8-bit runs we do not need to split based on script or check for
626 // clusters as the entire run is guaranteed to be latin-1.
627 CandidateRun run = { *str, 0, textRun.length(), fontData, USCRIPT_LATIN };
628 runs->append(run);
629 return true;
630 }
631
650 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length, 632 static inline bool matchesAdjacentRun(UScriptCode* scriptExtensions, int length,
651 CandidateRun& adjacentRun) 633 CandidateRun& adjacentRun)
652 { 634 {
653 for (int i = 0; i < length; i++) { 635 for (int i = 0; i < length; i++) {
654 if (scriptExtensions[i] == adjacentRun.script) 636 if (scriptExtensions[i] == adjacentRun.script)
655 return true; 637 return true;
656 } 638 }
657 return false; 639 return false;
658 } 640 }
659 641
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
729 711
730 i = std::max(i, nextResolvedRun); 712 i = std::max(i, nextResolvedRun);
731 } 713 }
732 return true; 714 return true;
733 } 715 }
734 716
735 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact er length 717 // For ideographic (CJK) documents, 90-95% of calls from width() are one charact er length
736 // because most characters have break opportunities both before and after. 718 // because most characters have break opportunities both before and after.
737 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter() 719 bool HarfBuzzShaper::createHarfBuzzRunsForSingleCharacter()
738 { 720 {
739 ASSERT(m_normalizedBufferLength == 1); 721 ASSERT(m_run.length() == 1);
740 UChar32 character = m_normalizedBuffer[0]; 722 UChar32 character = m_run[0];
741 if (!U16_IS_SINGLE(character)) 723 if (!U16_IS_SINGLE(character))
742 return false; 724 return false;
743 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character, fa lse, m_run.normalizeSpace()).fontData; 725 const SimpleFontData* fontData = m_font->glyphDataForCharacter(character,
726 false, m_run.normalizeSpace()).fontData;
744 UErrorCode errorCode = U_ZERO_ERROR; 727 UErrorCode errorCode = U_ZERO_ERROR;
745 UScriptCode script = uscript_getScript(character, &errorCode); 728 UScriptCode script = uscript_getScript(character, &errorCode);
746 if (U_FAILURE(errorCode)) 729 if (U_FAILURE(errorCode))
747 return false; 730 return false;
748 addHarfBuzzRun(0, 1, fontData, script); 731 addHarfBuzzRun(0, 1, fontData, script);
749 return true; 732 return true;
750 } 733 }
751 734
735 template<typename CharType>
736 bool HarfBuzzShaper::shapeInternal(GlyphBuffer* glyphBuffer)
737 {
738 if (!createHarfBuzzRuns<CharType>())
739 return false;
740
741 m_totalWidth = 0;
742 if (!shapeHarfBuzzRuns<CharType>())
743 return false;
744
745 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
746 return false;
747
748 return true;
749 }
750
751 template<typename CharType>
752 bool HarfBuzzShaper::createHarfBuzzRuns() 752 bool HarfBuzzShaper::createHarfBuzzRuns()
753 { 753 {
754 if (m_normalizedBufferLength == 1) 754 if (m_run.length() == 1)
755 return createHarfBuzzRunsForSingleCharacter(); 755 return createHarfBuzzRunsForSingleCharacter();
756 756
757 Vector<CandidateRun> candidateRuns; 757 Vector<CandidateRun> candidateRuns;
758 if (!collectCandidateRuns(m_normalizedBuffer.get(), 758 if (!collectCandidateRuns<CharType>(m_run, m_font, &candidateRuns,
759 m_normalizedBufferLength, m_font, &candidateRuns, m_run.normalizeSpace() )) 759 m_run.normalizeSpace()))
760 return false; 760 return false;
761 761
762 if (!resolveCandidateRuns(candidateRuns)) 762 if (!resolveCandidateRuns(candidateRuns))
763 return false; 763 return false;
764 764
765 size_t length = candidateRuns.size(); 765 size_t length = candidateRuns.size();
766 for (size_t i = 0; i < length; ) { 766 for (size_t i = 0; i < length; ) {
767 CandidateRun& run = candidateRuns[i]; 767 CandidateRun& run = candidateRuns[i];
768 CandidateRun lastMatchingRun = run; 768 CandidateRun lastMatchingRun = run;
769 for (i++; i < length; i++) { 769 for (i++; i < length; i++) {
770 if (candidateRuns[i].script != run.script 770 if (candidateRuns[i].script != run.script
771 || candidateRuns[i].fontData != run.fontData) 771 || candidateRuns[i].fontData != run.fontData)
772 break; 772 break;
773 lastMatchingRun = candidateRuns[i]; 773 lastMatchingRun = candidateRuns[i];
774 } 774 }
775 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.script) ; 775 if (lastMatchingRun.end > run.start)
776 addHarfBuzzRun(run.start, lastMatchingRun.end, run.fontData, run.scr ipt);
776 } 777 }
777 return !m_harfBuzzRuns.isEmpty(); 778 return !m_harfBuzzRuns.isEmpty();
778 } 779 }
779 780
780 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built 781 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
781 // without hb-icu. See http://crbug.com/356929 782 // without hb-icu. See http://crbug.com/356929
782 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) 783 static inline hb_script_t ICUScriptToHBScript(UScriptCode script)
783 { 784 {
784 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) 785 if (UNLIKELY(script == USCRIPT_INVALID_CODE))
785 return HB_SCRIPT_INVALID; 786 return HB_SCRIPT_INVALID;
(...skipping 14 matching lines...) Expand all
800 ASSERT(endCharacter > startCharacter); 801 ASSERT(endCharacter > startCharacter);
801 ASSERT(script != USCRIPT_INVALID_CODE); 802 ASSERT(script != USCRIPT_INVALID_CODE);
802 if (m_fallbackFonts) 803 if (m_fallbackFonts)
803 m_fallbackFonts->add(fontData); 804 m_fallbackFonts->add(fontData);
804 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, 805 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData,
805 startCharacter, endCharacter - startCharacter, 806 startCharacter, endCharacter - startCharacter,
806 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription(). orientation(), fontData), 807 TextDirectionToHBDirection(m_run.direction(), m_font->fontDescription(). orientation(), fontData),
807 ICUScriptToHBScript(script))); 808 ICUScriptToHBScript(script)));
808 } 809 }
809 810
810 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir,
811 const String& localeString, const CachedShapingResults* cachedResults)
812 {
813 ASSERT(cachedResults);
814 return cachedResults->dir == dir
815 && cachedResults->font == *font
816 && !cachedResults->font.loadingCustomFonts()
817 && !font->loadingCustomFonts()
818 && cachedResults->locale == localeString;
819 }
820
821 static const uint16_t* toUint16(const UChar* src) 811 static const uint16_t* toUint16(const UChar* src)
822 { 812 {
823 // FIXME: This relies on undefined behavior however it works on the 813 // FIXME: This relies on undefined behavior however it works on the
824 // current versions of all compilers we care about and avoids making 814 // current versions of all compilers we care about and avoids making
825 // a copy of the string. 815 // a copy of the string.
826 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t"); 816 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t");
827 return reinterpret_cast<const uint16_t*>(src); 817 return reinterpret_cast<const uint16_t*>(src);
828 } 818 }
829 819
830 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, 820 template<typename CharType>
831 const FontDescription& fontDescription, const UChar* normalizedBuffer, 821 inline const CharType* charactersForRun(const TextRun& textRun,
822 unsigned startIndex)
823 {
824 return textRun.data16(startIndex);
825 }
826
827 template<>
828 inline const LChar* charactersForRun<LChar>(const TextRun& textRun,
829 unsigned startIndex)
830 {
831 return textRun.data8(startIndex);
832 }
833
834 template<typename CharType>
835 inline const CharType* charactersForString(const String& string)
836 {
837 return string.characters16();
838 }
839
840 template<>
841 inline const LChar* charactersForString<LChar>(const String& string)
842 {
843 return string.characters8();
844 }
845
846 template<typename CharType>
847 inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer,
848 const CharType* characters, unsigned length)
849 {
850 hb_buffer_add_utf16(buffer, toUint16(characters), length, 0, length);
851 }
852
853 template<>
854 inline void addToHarfBuzzBufferInternal<LChar>(hb_buffer_t* buffer,
855 const LChar* characters, unsigned length)
856 {
857 // On linux we use the system version of harfbuzz so we cannot depend on
858 // hb_buffer_add_latin1 being available as it was only added in 0.9.38.
859 // FIXME: Remove this hack once all supported distros have HB >= 0.9.38.
skobes 2015/02/27 19:20:03 Is there a bug # to associate this FIXME with?
860 #if OS(LINUX)
861 String converted = String::make16BitFrom8BitSource(characters, length);
862 hb_buffer_add_utf16(buffer, toUint16(converted.characters16()),
863 length, 0, length);
864 #else
865 hb_buffer_add_latin1(buffer, characters, length, 0, length);
866 #endif
867 }
868
869 template<typename CharType>
870 inline void addToHarfBuzzBuffer(hb_buffer_t* buffer,
871 const FontDescription& fontDescription, const TextRun& textRun,
832 unsigned startIndex, unsigned numCharacters) 872 unsigned startIndex, unsigned numCharacters)
833 { 873 {
834 if (fontDescription.variant() == FontVariantSmallCaps 874 if (fontDescription.variant() == FontVariantSmallCaps
835 && u_islower(normalizedBuffer[startIndex])) { 875 && u_islower(textRun[startIndex])) {
836 String upperText = String(normalizedBuffer + startIndex, numCharacters) 876 String upperText = String(charactersForRun<CharType>(
837 .upper(); 877 textRun, startIndex), numCharacters).upper();
838 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call 878 // If TextRun is 16 bit upperText should be 16 bit too.
839 // makeUpper(). 879 ASSERT(upperText.is8Bit() == textRun.is8Bit());
840 ASSERT(!upperText.is8Bit()); 880 addToHarfBuzzBufferInternal<CharType>(buffer,
841 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), 881 charactersForString<CharType>(upperText), numCharacters);
842 numCharacters, 0, numCharacters);
843 } else { 882 } else {
844 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex), 883 addToHarfBuzzBufferInternal(buffer,
845 numCharacters, 0, numCharacters); 884 charactersForRun<CharType>(textRun, startIndex), numCharacters);
846 } 885 }
847 } 886 }
848 887
888 static inline UChar32 normalizeCharacter(UChar32 character,
889 bool normalizeSpace)
890 {
891 if (normalizeSpace && Character::isNormalizedCanvasSpaceCharacter(character) )
892 return space;
893 if (Character::treatAsSpace(character) && character != characterTabulation)
894 return space;
895 if (Character::treatAsZeroWidthSpaceInComplexScript(character))
896 return zeroWidthSpace;
897 return character;
898 }
899
900 static inline void normalizeHarfBuzzBuffer(hb_buffer_t* buffer,
901 bool normalizeSpace)
902 {
903 unsigned length;
904 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(buffer, &length);
905 for (unsigned i = 0; i < length; i++) {
906 UChar32 character = glyphInfos[i].codepoint;
907 UChar32 normalized = normalizeCharacter(character, normalizeSpace);
908 if (character != normalized)
909 glyphInfos[i].codepoint = normalized;
910 }
911 }
912
913 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir,
914 const String& localeString, const CachedShapingResults* cachedResults)
915 {
916 ASSERT(cachedResults);
917 return cachedResults->dir == dir
918 && cachedResults->font == *font
919 && !cachedResults->font.loadingCustomFonts()
920 && !font->loadingCustomFonts()
921 && cachedResults->locale == localeString;
922 }
923
924 template<typename CharType>
849 bool HarfBuzzShaper::shapeHarfBuzzRuns() 925 bool HarfBuzzShaper::shapeHarfBuzzRuns()
850 { 926 {
851 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy); 927 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy);
852 928
853 HarfBuzzRunCache& runCache = harfBuzzRunCache(); 929 HarfBuzzRunCache& runCache = harfBuzzRunCache();
854 const FontDescription& fontDescription = m_font->fontDescription(); 930 const FontDescription& fontDescription = m_font->fontDescription();
855 const String& localeString = fontDescription.locale(); 931 const String& localeString = fontDescription.locale();
856 CString locale = localeString.latin1(); 932 CString locale = localeString.latin1();
857 HarfBuzzRun* previousRun = nullptr; 933 HarfBuzzRun* previousRun = nullptr;
858 934
859 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 935 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
860 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; 936 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
861 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 937 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
862 938
863 const SimpleFontData* currentFontData = currentRun->fontData(); 939 const SimpleFontData* currentFontData = currentRun->fontData();
864 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData()); 940 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData());
865 HarfBuzzFace* face = platformData->harfBuzzFace(); 941 HarfBuzzFace* face = platformData->harfBuzzFace();
866 if (!face) 942 if (!face)
867 return false; 943 return false;
868 944
869 hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(loc ale.data(), locale.length())); 945 hb_buffer_set_language(harfBuzzBuffer.get(), hb_language_from_string(loc ale.data(), locale.length()));
870 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); 946 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
871 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction()); 947 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction());
872 948
873 const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex(); 949 const CharType* src = charactersForRun<CharType>(m_run, currentRun->star tIndex());
874 std::wstring key(src, src + currentRun->numCharacters()); 950 std::wstring key(src, src + currentRun->numCharacters());
875 951
876 CachedShapingResults* cachedResults = runCache.find(key); 952 CachedShapingResults* cachedResults = runCache.find(key);
877 if (cachedResults) { 953 if (cachedResults) {
878 if (isValidCachedResult(m_font, currentRun->direction(), 954 if (isValidCachedResult(m_font, currentRun->direction(),
879 localeString, cachedResults)) { 955 localeString, cachedResults)) {
880 currentRun->applyShapeResult(cachedResults->buffer); 956 currentRun->applyShapeResult(cachedResults->buffer);
881 setGlyphPositionsForHarfBuzzRun(currentRun, 957 setGlyphPositionsForHarfBuzzRun(currentRun,
882 cachedResults->buffer, previousRun); 958 cachedResults->buffer, previousRun);
883 hb_buffer_clear_contents(harfBuzzBuffer.get()); 959 hb_buffer_clear_contents(harfBuzzBuffer.get());
884 runCache.moveToBack(cachedResults); 960 runCache.moveToBack(cachedResults);
885 previousRun = currentRun; 961 previousRun = currentRun;
886 continue; 962 continue;
887 } 963 }
888 runCache.remove(cachedResults); 964 runCache.remove(cachedResults);
889 } 965 }
890 966
891 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle 967 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle
892 // for combining marks at the beginning of runs. 968 // for combining marks at the beginning of runs.
893 static const uint16_t preContext = space; 969 static const uint16_t preContext = space;
894 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); 970 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
895 971
896 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), 972 addToHarfBuzzBuffer<CharType>(harfBuzzBuffer.get(),
897 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(), 973 fontDescription, m_run, currentRun->startIndex(),
898 currentRun->numCharacters()); 974 currentRun->numCharacters());
975 normalizeHarfBuzzBuffer(harfBuzzBuffer.get(), m_run.normalizeSpace());
899 976
900 if (fontDescription.orientation() == Vertical) 977 if (fontDescription.orientation() == Vertical)
901 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); 978 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
902 979
903 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy); 980 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy);
904 981
905 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); 982 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
906 currentRun->applyShapeResult(harfBuzzBuffer.get()); 983 currentRun->applyShapeResult(harfBuzzBuffer.get());
907 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get(), previo usRun); 984 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get(), previo usRun);
908 985
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
941 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. 1018 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
942 for (size_t i = 0; i < numGlyphs; ++i) { 1019 for (size_t i = 0; i < numGlyphs; ++i) {
943 bool runEnd = i + 1 == numGlyphs; 1020 bool runEnd = i + 1 == numGlyphs;
944 uint16_t glyph = glyphInfos[i].codepoint; 1021 uint16_t glyph = glyphInfos[i].codepoint;
945 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); 1022 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
946 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); 1023 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
947 // One out of x_advance and y_advance is zero, depending on 1024 // One out of x_advance and y_advance is zero, depending on
948 // whether the buffer direction is horizontal or vertical. 1025 // whether the buffer direction is horizontal or vertical.
949 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance); 1026 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance);
950 1027
951 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster; 1028 int currentCharacterIndex = currentRun->startIndex() + glyphInfos[i].clu ster;
skobes 2015/02/27 19:20:03 Why is the index signed here, but unsigned in adju
952 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); 1029 RELEASE_ASSERT(m_run.length() > currentCharacterIndex);
953 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster; 1030 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster;
954 float spacing = 0; 1031 float spacing = 0;
955 1032
956 glyphToCharacterIndexes[i] = glyphInfos[i].cluster; 1033 glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
957 1034
958 if (isClusterEnd) 1035 if (isClusterEnd)
959 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, previ ousRun, offsetX, totalAdvance); 1036 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, previ ousRun, offsetX, totalAdvance);
960 1037
961 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { 1038 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
962 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); 1039 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
(...skipping 19 matching lines...) Expand all
982 1059
983 totalAdvance += advance; 1060 totalAdvance += advance;
984 } 1061 }
985 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0); 1062 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
986 m_totalWidth += currentRun->width(); 1063 m_totalWidth += currentRun->width();
987 } 1064 }
988 1065
989 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex, unsigned currentCharacterIndex, HarfBuzzRun* previousRun, float& offsetX, float& totalAdvance) 1066 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex, unsigned currentCharacterIndex, HarfBuzzRun* previousRun, float& offsetX, float& totalAdvance)
990 { 1067 {
991 float spacing = 0; 1068 float spacing = 0;
992 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; 1069 UChar32 character = normalizeCharacter(m_run[currentCharacterIndex], m_run.n ormalizeSpace());
993 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) 1070 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character))
994 spacing += m_letterSpacing; 1071 spacing += m_letterSpacing;
995 1072
996 bool treatAsSpace = Character::treatAsSpace(character); 1073 bool treatAsSpace = Character::treatAsSpace(character);
997 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al lowTabs())) 1074 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_run.al lowTabs()))
998 spacing += m_wordSpacingAdjustment; 1075 spacing += m_wordSpacingAdjustment;
999 1076
1000 if (!m_expansionOpportunityCount) 1077 if (!m_expansionOpportunityCount)
1001 return spacing; 1078 return spacing;
1002 1079
1003 if (treatAsSpace) { 1080 if (treatAsSpace) {
1004 spacing += nextExpansionPerOpportunity(); 1081 spacing += nextExpansionPerOpportunity();
1005 m_isAfterExpansion = true; 1082 m_isAfterExpansion = true;
1006 return spacing; 1083 return spacing;
1007 } 1084 }
1008 1085
1009 if (m_run.textJustify() != TextJustify::TextJustifyAuto) { 1086 if (m_run.textJustify() != TextJustify::TextJustifyAuto) {
1010 m_isAfterExpansion = false; 1087 m_isAfterExpansion = false;
1011 return spacing; 1088 return spacing;
1012 } 1089 }
1013 1090
1014 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte r each character. 1091 // isCJKIdeographOrSymbol() has expansion opportunities both before and afte r each character.
1015 // http://www.w3.org/TR/jlreq/#line_adjustment 1092 // http://www.w3.org/TR/jlreq/#line_adjustment
1016 if (U16_IS_LEAD(character) && currentCharacterIndex + 1 < m_normalizedBuffer Length && U16_IS_TRAIL(m_normalizedBuffer[currentCharacterIndex + 1])) 1093 if (!m_run.is8Bit() && U16_IS_LEAD(character) && currentCharacterIndex + 1 < static_cast<unsigned>(m_run.charactersLength()) && U16_IS_TRAIL(m_run[currentCh aracterIndex + 1]))
1017 character = U16_GET_SUPPLEMENTARY(character, m_normalizedBuffer[currentC haracterIndex + 1]); 1094 character = U16_GET_SUPPLEMENTARY(character, normalizeCharacter(m_run[cu rrentCharacterIndex + 1], m_run.normalizeSpace()));
1018 if (!Character::isCJKIdeographOrSymbol(character)) { 1095 if (!Character::isCJKIdeographOrSymbol(character)) {
1019 m_isAfterExpansion = false; 1096 m_isAfterExpansion = false;
1020 return spacing; 1097 return spacing;
1021 } 1098 }
1022 1099
1023 if (!m_isAfterExpansion) { 1100 if (!m_isAfterExpansion) {
1024 // Take the expansion opportunity before this ideograph. 1101 // Take the expansion opportunity before this ideograph.
1025 float expandBefore = nextExpansionPerOpportunity(); 1102 float expandBefore = nextExpansionPerOpportunity();
1026 if (expandBefore) { 1103 if (expandBefore) {
1027 if (glyphIndex > 0) { 1104 if (glyphIndex > 0) {
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after
1123 1200
1124 clusterAdvance += advances[i]; 1201 clusterAdvance += advances[i];
1125 1202
1126 if (isClusterEnd) { 1203 if (isClusterEnd) {
1127 uint16_t clusterEnd; 1204 uint16_t clusterEnd;
1128 if (m_run.rtl()) 1205 if (m_run.rtl())
1129 clusterEnd = currentCharacterIndex; 1206 clusterEnd = currentCharacterIndex;
1130 else 1207 else
1131 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];
1132 1209
1133 graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get( ), m_normalizedBufferLength, clusterStart, clusterEnd); 1210 graphemesInCluster = m_run.is8Bit() ? 1 : countGraphemesInCluster(m_ run.characters16(), m_run.length(), clusterStart, clusterEnd);
1134 if (!graphemesInCluster || !clusterAdvance) 1211 if (!graphemesInCluster || !clusterAdvance)
1135 continue; 1212 continue;
1136 1213
1137 float glyphAdvanceX = clusterAdvance / graphemesInCluster; 1214 float glyphAdvanceX = clusterAdvance / graphemesInCluster;
1138 for (unsigned j = 0; j < graphemesInCluster; ++j) { 1215 for (unsigned j = 0; j < graphemesInCluster; ++j) {
1139 // 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.
1140 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[curre ntCharacterIndex]) ? 1 : 0; 1217 Glyph glyphToAdd = Character::canReceiveTextEmphasis(m_run[curre ntCharacterIndex]) ? 1 : 0;
1141 // The emphasis code expects mid-glyph offsets. 1218 // The emphasis code expects mid-glyph offsets.
1142 glyphBuffer->add(glyphToAdd, currentRun->fontData(), advanceSoFa r + glyphAdvanceX / 2); 1219 glyphBuffer->add(glyphToAdd, currentRun->fontData(), advanceSoFa r + glyphAdvanceX / 2);
1143 advanceSoFar += glyphAdvanceX; 1220 advanceSoFar += glyphAdvanceX;
(...skipping 23 matching lines...) Expand all
1167 } 1244 }
1168 return glyphBuffer->size(); 1245 return glyphBuffer->size();
1169 } 1246 }
1170 1247
1171 int HarfBuzzShaper::offsetForPosition(float targetX) 1248 int HarfBuzzShaper::offsetForPosition(float targetX)
1172 { 1249 {
1173 int charactersSoFar = 0; 1250 int charactersSoFar = 0;
1174 float currentX = 0; 1251 float currentX = 0;
1175 1252
1176 if (m_run.rtl()) { 1253 if (m_run.rtl()) {
1177 charactersSoFar = m_normalizedBufferLength; 1254 charactersSoFar = m_run.length();
1178 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) { 1255 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
1179 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters(); 1256 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
1180 float nextX = currentX + m_harfBuzzRuns[i]->width(); 1257 float nextX = currentX + m_harfBuzzRuns[i]->width();
1181 float offsetForRun = targetX - currentX; 1258 float offsetForRun = targetX - currentX;
1182 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) { 1259 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
1183 // The x value in question is within this script run. 1260 // The x value in question is within this script run.
1184 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun); 1261 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun);
1185 return charactersSoFar + index; 1262 return charactersSoFar + index;
1186 } 1263 }
1187 currentX = nextX; 1264 currentX = nextX;
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1245 // possibly invalid from, to arguments. 1322 // possibly invalid from, to arguments.
1246 if (!foundToX && !foundFromX) 1323 if (!foundToX && !foundFromX)
1247 fromX = toX = 0; 1324 fromX = toX = 0;
1248 1325
1249 if (fromX < toX) 1326 if (fromX < toX)
1250 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height); 1327 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
1251 return FloatRect(point.x() + toX, point.y(), fromX - toX, height); 1328 return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
1252 } 1329 }
1253 1330
1254 } // 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