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

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

Issue 2507063010: Moving string normalization out of HarfBuzz (Closed)
Patch Set: Merge w/HEAD Created 4 years 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
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 13 matching lines...) Expand all
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32 #include "platform/fonts/shaping/HarfBuzzShaper.h" 32 #include "platform/fonts/shaping/HarfBuzzShaper.h"
33 33
34 #include "platform/RuntimeEnabledFeatures.h"
35 #include "platform/fonts/Font.h" 34 #include "platform/fonts/Font.h"
36 #include "platform/fonts/FontDescription.h" 35 #include "platform/fonts/FontDescription.h"
37 #include "platform/fonts/FontFallbackIterator.h" 36 #include "platform/fonts/FontFallbackIterator.h"
38 #include "platform/fonts/GlyphBuffer.h" 37 #include "platform/fonts/GlyphBuffer.h"
39 #include "platform/fonts/SmallCapsIterator.h" 38 #include "platform/fonts/SmallCapsIterator.h"
40 #include "platform/fonts/UTF16TextIterator.h" 39 #include "platform/fonts/UTF16TextIterator.h"
41 #include "platform/fonts/opentype/OpenTypeCapsSupport.h" 40 #include "platform/fonts/opentype/OpenTypeCapsSupport.h"
42 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h" 41 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h"
43 #include "platform/fonts/shaping/HarfBuzzFace.h" 42 #include "platform/fonts/shaping/HarfBuzzFace.h"
44 #include "platform/fonts/shaping/RunSegmenter.h" 43 #include "platform/fonts/shaping/RunSegmenter.h"
45 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" 44 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
46 #include "platform/text/Character.h"
47 #include "platform/text/TextBreakIterator.h" 45 #include "platform/text/TextBreakIterator.h"
48 #include "wtf/Compiler.h" 46 #include "wtf/Compiler.h"
49 #include "wtf/MathExtras.h" 47 #include "wtf/MathExtras.h"
50 #include "wtf/PtrUtil.h" 48 #include "wtf/PtrUtil.h"
51 #include "wtf/text/Unicode.h" 49 #include "wtf/text/Unicode.h"
52 #include <algorithm> 50 #include <algorithm>
53 #include <hb.h> 51 #include <hb.h>
54 #include <memory> 52 #include <memory>
55 #include <unicode/uchar.h> 53 #include <unicode/uchar.h>
56 #include <unicode/uscript.h> 54 #include <unicode/uscript.h>
(...skipping 19 matching lines...) Expand all
76 } 74 }
77 75
78 T* get() { return m_ptr; } 76 T* get() { return m_ptr; }
79 void set(T* ptr) { m_ptr = ptr; } 77 void set(T* ptr) { m_ptr = ptr; }
80 78
81 private: 79 private:
82 T* m_ptr; 80 T* m_ptr;
83 DestroyFunction m_destroy; 81 DestroyFunction m_destroy;
84 }; 82 };
85 83
86 static void normalizeCharacters(const TextRun& run, 84 HarfBuzzShaper::HarfBuzzShaper(const UChar* text,
87 unsigned length, 85 unsigned length,
88 UChar* destination, 86 TextDirection direction)
89 unsigned* destinationLength) { 87 : m_normalizedBuffer(text),
90 unsigned position = 0; 88 m_normalizedBufferLength(length),
91 bool error = false; 89 m_textDirection(direction) {}
92 const UChar* source;
93 String stringFor8BitRun;
94 if (run.is8Bit()) {
95 stringFor8BitRun =
96 String::make16BitFrom8BitSource(run.characters8(), run.length());
97 source = stringFor8BitRun.characters16();
98 } else {
99 source = run.characters16();
100 }
101
102 *destinationLength = 0;
103 while (position < length) {
104 UChar32 character;
105 U16_NEXT(source, position, length, character);
106 // Don't normalize tabs as they are not treated as spaces for word-end.
107 if (run.normalizeSpace() &&
108 Character::isNormalizedCanvasSpaceCharacter(character)) {
109 character = spaceCharacter;
110 } else if (Character::treatAsSpace(character) &&
111 character != noBreakSpaceCharacter) {
112 character = spaceCharacter;
113 } else if (!RuntimeEnabledFeatures::
114 renderUnicodeControlCharactersEnabled() &&
115 Character::legacyTreatAsZeroWidthSpaceInComplexScript(
116 character)) {
117 character = zeroWidthSpaceCharacter;
118 } else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) {
119 character = zeroWidthSpaceCharacter;
120 }
121
122 U16_APPEND(destination, *destinationLength, length, character, error);
123 DCHECK(!error);
124 }
125 }
126
127 HarfBuzzShaper::HarfBuzzShaper(const TextRun& run)
128 : m_textRun(run), m_normalizedBufferLength(0) {
129 m_normalizedBuffer = wrapArrayUnique(new UChar[m_textRun.length() + 1]);
130 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(),
131 &m_normalizedBufferLength);
132 }
133 90
134 namespace { 91 namespace {
135 92
136 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built 93 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
137 // without hb-icu. See http://crbug.com/356929 94 // without hb-icu. See http://crbug.com/356929
138 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) { 95 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) {
139 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) 96 if (UNLIKELY(script == USCRIPT_INVALID_CODE))
140 return HB_SCRIPT_INVALID; 97 return HB_SCRIPT_INVALID;
141 98
142 return hb_script_from_string(uscript_getShortName(script), -1); 99 return hb_script_from_string(uscript_getShortName(script), -1);
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
296 253
297 // If numCharacters is 0, that means we hit a NotDef before shaping the 254 // If numCharacters is 0, that means we hit a NotDef before shaping the
298 // whole grapheme. We do not append it here. For the next glyph we 255 // whole grapheme. We do not append it here. For the next glyph we
299 // encounter, atChange will be true, and the characters corresponding to 256 // encounter, atChange will be true, and the characters corresponding to
300 // the grapheme will be added to the TODO queue again, attempting to 257 // the grapheme will be added to the TODO queue again, attempting to
301 // shape the whole grapheme with the next font. 258 // shape the whole grapheme with the next font.
302 // When we're getting here with the last resort font, we have no other 259 // When we're getting here with the last resort font, we have no other
303 // choice than adding boxes to the ShapeResult. 260 // choice than adding boxes to the ShapeResult.
304 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) { 261 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) {
305 hb_direction_t direction = TextDirectionToHBDirection( 262 hb_direction_t direction = TextDirectionToHBDirection(
306 m_textRun.direction(), font->getFontDescription().orientation(), 263 m_textDirection, font->getFontDescription().orientation(),
307 currentFont); 264 currentFont);
308 // Here we need to specify glyph positions. 265 // Here we need to specify glyph positions.
309 ShapeResult::RunInfo* run = new ShapeResult::RunInfo( 266 ShapeResult::RunInfo* run = new ShapeResult::RunInfo(
310 currentFont, direction, ICUScriptToHBScript(currentRunScript), 267 currentFont, direction, ICUScriptToHBScript(currentRunScript),
311 startIndex, numGlyphsToInsert, numCharacters); 268 startIndex, numGlyphsToInsert, numCharacters);
312 shapeResult->insertRun(wrapUnique(run), lastChangePosition, 269 shapeResult->insertRun(wrapUnique(run), lastChangePosition,
313 numGlyphsToInsert, harfBuzzBuffer); 270 numGlyphsToInsert, harfBuzzBuffer);
314 } 271 }
315 lastChangePosition = glyphIndex; 272 lastChangePosition = glyphIndex;
316 } 273 }
(...skipping 24 matching lines...) Expand all
341 hint.clear(); 298 hint.clear();
342 299
343 size_t numCharsAdded = 0; 300 size_t numCharsAdded = 0;
344 for (auto it = holesQueue.begin(); it != holesQueue.end(); ++it) { 301 for (auto it = holesQueue.begin(); it != holesQueue.end(); ++it) {
345 if (it->m_action == HolesQueueNextFont) 302 if (it->m_action == HolesQueueNextFont)
346 break; 303 break;
347 304
348 UChar32 hintChar; 305 UChar32 hintChar;
349 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= 306 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <=
350 m_normalizedBufferLength); 307 m_normalizedBufferLength);
351 UTF16TextIterator iterator(m_normalizedBuffer.get() + it->m_startIndex, 308 UTF16TextIterator iterator(m_normalizedBuffer + it->m_startIndex,
352 it->m_numCharacters); 309 it->m_numCharacters);
353 while (iterator.consume(hintChar)) { 310 while (iterator.consume(hintChar)) {
354 hint.append(hintChar); 311 hint.append(hintChar);
355 numCharsAdded++; 312 numCharsAdded++;
356 iterator.advance(); 313 iterator.advance();
357 } 314 }
358 } 315 }
359 return numCharsAdded > 0; 316 return numCharsAdded > 0;
360 } 317 }
361 318
(...skipping 228 matching lines...) Expand 10 before | Expand all | Expand 10 after
590 m_countFeatures++; 547 m_countFeatures++;
591 } 548 }
592 549
593 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() { 550 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() {
594 m_features->remove(0, m_countFeatures); 551 m_features->remove(0, m_countFeatures);
595 } 552 }
596 553
597 } // namespace 554 } // namespace
598 555
599 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult(const Font* font) const { 556 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult(const Font* font) const {
600 RefPtr<ShapeResult> result = ShapeResult::create( 557 RefPtr<ShapeResult> result =
601 font, m_normalizedBufferLength, m_textRun.direction()); 558 ShapeResult::create(font, m_normalizedBufferLength, m_textDirection);
602 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), 559 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(),
603 hb_buffer_destroy); 560 hb_buffer_destroy);
604 FeaturesVector fontFeatures; 561 FeaturesVector fontFeatures;
605 setFontFeatures(font, &fontFeatures); 562 setFontFeatures(font, &fontFeatures);
606 const FontDescription& fontDescription = font->getFontDescription(); 563 const FontDescription& fontDescription = font->getFontDescription();
607 const hb_language_t language = 564 const hb_language_t language =
608 fontDescription.localeOrDefault().harfbuzzLanguage(); 565 fontDescription.localeOrDefault().harfbuzzLanguage();
609 566
610 bool needsCapsHandling = 567 bool needsCapsHandling =
611 fontDescription.variantCaps() != FontDescription::CapsNormal; 568 fontDescription.variantCaps() != FontDescription::CapsNormal;
612 OpenTypeCapsSupport capsSupport; 569 OpenTypeCapsSupport capsSupport;
613 FontOrientation orientation = font->getFontDescription().orientation(); 570 FontOrientation orientation = font->getFontDescription().orientation();
614 571
615 RunSegmenter::RunSegmenterRange segmentRange = { 572 RunSegmenter::RunSegmenterRange segmentRange = {
616 0, 0, USCRIPT_INVALID_CODE, OrientationIterator::OrientationInvalid, 573 0, 0, USCRIPT_INVALID_CODE, OrientationIterator::OrientationInvalid,
617 FontFallbackPriority::Invalid}; 574 FontFallbackPriority::Invalid};
618 RunSegmenter runSegmenter(m_normalizedBuffer.get(), m_normalizedBufferLength, 575 RunSegmenter runSegmenter(m_normalizedBuffer, m_normalizedBufferLength,
619 orientation); 576 orientation);
620 577
621 Vector<UChar32> fallbackCharsHint; 578 Vector<UChar32> fallbackCharsHint;
622 579
623 // TODO: Check whether this treatAsZerowidthspace from the previous script 580 // TODO: Check whether this treatAsZerowidthspace from the previous script
624 // segmentation plays a role here, does the new scriptRuniterator handle that 581 // segmentation plays a role here, does the new scriptRuniterator handle that
625 // correctly? 582 // correctly?
626 Deque<HolesQueueItem> holesQueue; 583 Deque<HolesQueueItem> holesQueue;
627 while (runSegmenter.consume(&segmentRange)) { 584 while (runSegmenter.consume(&segmentRange)) {
628 RefPtr<FontFallbackIterator> fallbackIterator = 585 RefPtr<FontFallbackIterator> fallbackIterator =
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
663 620
664 const SimpleFontData* fontData = currentFontDataForRangeSet->fontData(); 621 const SimpleFontData* fontData = currentFontDataForRangeSet->fontData();
665 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior = 622 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior =
666 SmallCapsIterator::SmallCapsSameCase; 623 SmallCapsIterator::SmallCapsSameCase;
667 if (needsCapsHandling) { 624 if (needsCapsHandling) {
668 capsSupport = 625 capsSupport =
669 OpenTypeCapsSupport(fontData->platformData().harfBuzzFace(), 626 OpenTypeCapsSupport(fontData->platformData().harfBuzzFace(),
670 fontDescription.variantCaps(), 627 fontDescription.variantCaps(),
671 ICUScriptToHBScript(segmentRange.script)); 628 ICUScriptToHBScript(segmentRange.script));
672 if (capsSupport.needsRunCaseSplitting()) { 629 if (capsSupport.needsRunCaseSplitting()) {
673 splitUntilNextCaseChange(m_normalizedBuffer.get(), &holesQueue, 630 splitUntilNextCaseChange(m_normalizedBuffer, &holesQueue,
674 currentQueueItem, smallCapsBehavior); 631 currentQueueItem, smallCapsBehavior);
675 } 632 }
676 } 633 }
677 634
678 ASSERT(currentQueueItem.m_numCharacters); 635 ASSERT(currentQueueItem.m_numCharacters);
679 636
680 const SimpleFontData* smallcapsAdjustedFont = 637 const SimpleFontData* smallcapsAdjustedFont =
681 needsCapsHandling && capsSupport.needsSyntheticFont(smallCapsBehavior) 638 needsCapsHandling && capsSupport.needsSyntheticFont(smallCapsBehavior)
682 ? fontData->smallCapsFontData(fontDescription).get() 639 ? fontData->smallCapsFontData(fontDescription).get()
683 : fontData; 640 : fontData;
684 641
685 // Compatibility with SimpleFontData approach of keeping a flag for 642 // Compatibility with SimpleFontData approach of keeping a flag for
686 // overriding drawing direction. 643 // overriding drawing direction.
687 // TODO: crbug.com/506224 This should go away in favor of storing that 644 // TODO: crbug.com/506224 This should go away in favor of storing that
688 // information elsewhere, for example in ShapeResult. 645 // information elsewhere, for example in ShapeResult.
689 const SimpleFontData* directionAndSmallCapsAdjustedFont = 646 const SimpleFontData* directionAndSmallCapsAdjustedFont =
690 fontDataAdjustedForOrientation(smallcapsAdjustedFont, orientation, 647 fontDataAdjustedForOrientation(smallcapsAdjustedFont, orientation,
691 segmentRange.renderOrientation); 648 segmentRange.renderOrientation);
692 649
693 CaseMapIntend caseMapIntend = CaseMapIntend::KeepSameCase; 650 CaseMapIntend caseMapIntend = CaseMapIntend::KeepSameCase;
694 if (needsCapsHandling) 651 if (needsCapsHandling)
695 caseMapIntend = capsSupport.needsCaseChange(smallCapsBehavior); 652 caseMapIntend = capsSupport.needsCaseChange(smallCapsBehavior);
696 653
697 CaseMappingHarfBuzzBufferFiller( 654 CaseMappingHarfBuzzBufferFiller(
698 caseMapIntend, fontDescription.localeOrDefault(), 655 caseMapIntend, fontDescription.localeOrDefault(),
699 harfBuzzBuffer.get(), m_normalizedBuffer.get(), 656 harfBuzzBuffer.get(), m_normalizedBuffer, m_normalizedBufferLength,
700 m_normalizedBufferLength, currentQueueItem.m_startIndex, 657 currentQueueItem.m_startIndex, currentQueueItem.m_numCharacters);
701 currentQueueItem.m_numCharacters);
702 658
703 CapsFeatureSettingsScopedOverlay capsOverlay( 659 CapsFeatureSettingsScopedOverlay capsOverlay(
704 &fontFeatures, capsSupport.fontFeatureToUse(smallCapsBehavior)); 660 &fontFeatures, capsSupport.fontFeatureToUse(smallCapsBehavior));
705 661
706 hb_direction_t direction = 662 hb_direction_t direction = TextDirectionToHBDirection(
707 TextDirectionToHBDirection(m_textRun.direction(), orientation, 663 m_textDirection, orientation, directionAndSmallCapsAdjustedFont);
708 directionAndSmallCapsAdjustedFont);
709 664
710 if (!shapeRange(harfBuzzBuffer.get(), 665 if (!shapeRange(harfBuzzBuffer.get(),
711 fontFeatures.isEmpty() ? 0 : fontFeatures.data(), 666 fontFeatures.isEmpty() ? 0 : fontFeatures.data(),
712 fontFeatures.size(), directionAndSmallCapsAdjustedFont, 667 fontFeatures.size(), directionAndSmallCapsAdjustedFont,
713 currentFontDataForRangeSet->ranges(), segmentRange.script, 668 currentFontDataForRangeSet->ranges(), segmentRange.script,
714 direction, language)) 669 direction, language))
715 DLOG(ERROR) << "Shaping range failed."; 670 DLOG(ERROR) << "Shaping range failed.";
716 671
717 if (!extractShapeResults( 672 if (!extractShapeResults(
718 harfBuzzBuffer.get(), result.get(), fontCycleQueued, &holesQueue, 673 harfBuzzBuffer.get(), result.get(), fontCycleQueued, &holesQueue,
719 currentQueueItem, font, directionAndSmallCapsAdjustedFont, 674 currentQueueItem, font, directionAndSmallCapsAdjustedFont,
720 segmentRange.script, !fallbackIterator->hasNext())) 675 segmentRange.script, !fallbackIterator->hasNext()))
721 DLOG(ERROR) << "Shape result extraction failed."; 676 DLOG(ERROR) << "Shape result extraction failed.";
722 677
723 hb_buffer_reset(harfBuzzBuffer.get()); 678 hb_buffer_reset(harfBuzzBuffer.get());
724 } 679 }
725 } 680 }
726 return result.release(); 681 return result.release();
727 } 682 }
728 683
729 } // namespace blink 684 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698