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

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

Issue 2686503003: Add support for shaping a substring to HarfBuzzShaper (Closed)
Patch Set: Fix windows compiler error Created 3 years, 10 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
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 22 matching lines...) Expand all
33 33
34 #include "platform/fonts/Font.h" 34 #include "platform/fonts/Font.h"
35 #include "platform/fonts/FontDescription.h" 35 #include "platform/fonts/FontDescription.h"
36 #include "platform/fonts/FontFallbackIterator.h" 36 #include "platform/fonts/FontFallbackIterator.h"
37 #include "platform/fonts/GlyphBuffer.h" 37 #include "platform/fonts/GlyphBuffer.h"
38 #include "platform/fonts/SmallCapsIterator.h" 38 #include "platform/fonts/SmallCapsIterator.h"
39 #include "platform/fonts/UTF16TextIterator.h" 39 #include "platform/fonts/UTF16TextIterator.h"
40 #include "platform/fonts/opentype/OpenTypeCapsSupport.h" 40 #include "platform/fonts/opentype/OpenTypeCapsSupport.h"
41 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h" 41 #include "platform/fonts/shaping/CaseMappingHarfBuzzBufferFiller.h"
42 #include "platform/fonts/shaping/HarfBuzzFace.h" 42 #include "platform/fonts/shaping/HarfBuzzFace.h"
43 #include "platform/fonts/shaping/RunSegmenter.h"
44 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h" 43 #include "platform/fonts/shaping/ShapeResultInlineHeaders.h"
45 #include "platform/text/TextBreakIterator.h" 44 #include "platform/text/TextBreakIterator.h"
46 #include "wtf/Compiler.h" 45 #include "wtf/Compiler.h"
47 #include "wtf/MathExtras.h" 46 #include "wtf/MathExtras.h"
48 #include "wtf/PtrUtil.h" 47 #include "wtf/PtrUtil.h"
49 #include "wtf/text/Unicode.h" 48 #include "wtf/text/Unicode.h"
50 #include <algorithm> 49 #include <algorithm>
51 #include <hb.h> 50 #include <hb.h>
52 #include <memory> 51 #include <memory>
53 #include <unicode/uchar.h> 52 #include <unicode/uchar.h>
54 #include <unicode/uscript.h> 53 #include <unicode/uscript.h>
55 54
56 namespace blink { 55 namespace blink {
57 using FeaturesVector = Vector<hb_feature_t, 6>; 56 using FeaturesVector = Vector<hb_feature_t, 6>;
58 57
58 enum HolesQueueItemAction { HolesQueueNextFont, HolesQueueRange };
59
60 struct HolesQueueItem {
61 DISALLOW_NEW_EXCEPT_PLACEMENT_NEW();
62 HolesQueueItemAction m_action;
63 unsigned m_startIndex;
64 unsigned m_numCharacters;
65 HolesQueueItem(HolesQueueItemAction action, unsigned start, unsigned num)
66 : m_action(action), m_startIndex(start), m_numCharacters(num){};
67 };
68
59 template <typename T> 69 template <typename T>
60 class HarfBuzzScopedPtr { 70 class HarfBuzzScopedPtr {
61 STACK_ALLOCATED(); 71 STACK_ALLOCATED();
62 WTF_MAKE_NONCOPYABLE(HarfBuzzScopedPtr); 72 WTF_MAKE_NONCOPYABLE(HarfBuzzScopedPtr);
63 73
64 public: 74 public:
65 typedef void (*DestroyFunction)(T*); 75 typedef void (*DestroyFunction)(T*);
66 76
67 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy) 77 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
68 : m_ptr(ptr), m_destroy(destroy) { 78 : m_ptr(ptr), m_destroy(destroy) {
69 ASSERT(m_destroy); 79 ASSERT(m_destroy);
70 } 80 }
71 ~HarfBuzzScopedPtr() { 81 ~HarfBuzzScopedPtr() {
72 if (m_ptr) 82 if (m_ptr)
73 (*m_destroy)(m_ptr); 83 (*m_destroy)(m_ptr);
74 } 84 }
75 85
76 T* get() { return m_ptr; } 86 T* get() { return m_ptr; }
77 void set(T* ptr) { m_ptr = ptr; } 87 void set(T* ptr) { m_ptr = ptr; }
78 88
79 private: 89 private:
80 T* m_ptr; 90 T* m_ptr;
81 DestroyFunction m_destroy; 91 DestroyFunction m_destroy;
82 }; 92 };
83 93
84 HarfBuzzShaper::HarfBuzzShaper(const UChar* text, 94 HarfBuzzShaper::HarfBuzzShaper(const UChar* text, unsigned length)
85 unsigned length, 95 : m_text(text), m_textLength(length) {}
86 TextDirection direction)
87 : m_normalizedBuffer(text),
88 m_normalizedBufferLength(length),
89 m_textDirection(direction) {}
90 96
91 namespace { 97 namespace {
92 98
93 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built 99 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
94 // without hb-icu. See http://crbug.com/356929 100 // without hb-icu. See http://crbug.com/356929
95 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) { 101 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) {
96 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) 102 if (UNLIKELY(script == USCRIPT_INVALID_CODE))
97 return HB_SCRIPT_INVALID; 103 return HB_SCRIPT_INVALID;
98 104
99 return hb_script_from_string(uscript_getShortName(script), -1); 105 return hb_script_from_string(uscript_getShortName(script), -1);
100 } 106 }
101 107
102 static inline hb_direction_t TextDirectionToHBDirection( 108 static inline hb_direction_t TextDirectionToHBDirection(
103 TextDirection dir, 109 TextDirection dir,
104 FontOrientation orientation, 110 FontOrientation orientation,
105 const SimpleFontData* fontData) { 111 const SimpleFontData* fontData) {
106 hb_direction_t harfBuzzDirection = 112 hb_direction_t harfBuzzDirection =
107 isVerticalAnyUpright(orientation) && 113 isVerticalAnyUpright(orientation) &&
108 !fontData->isTextOrientationFallback() 114 !fontData->isTextOrientationFallback()
109 ? HB_DIRECTION_TTB 115 ? HB_DIRECTION_TTB
110 : HB_DIRECTION_LTR; 116 : HB_DIRECTION_LTR;
111 return dir == TextDirection::kRtl ? HB_DIRECTION_REVERSE(harfBuzzDirection) 117 return dir == TextDirection::kRtl ? HB_DIRECTION_REVERSE(harfBuzzDirection)
112 : harfBuzzDirection; 118 : harfBuzzDirection;
113 } 119 }
114 120
115 inline bool shapeRange(hb_buffer_t* harfBuzzBuffer, 121 inline bool shapeRange(hb_buffer_t* buffer,
116 hb_feature_t* fontFeatures, 122 hb_feature_t* fontFeatures,
117 unsigned fontFeaturesSize, 123 unsigned fontFeaturesSize,
118 const SimpleFontData* currentFont, 124 const SimpleFontData* currentFont,
119 PassRefPtr<UnicodeRangeSet> currentFontRangeSet, 125 PassRefPtr<UnicodeRangeSet> currentFontRangeSet,
120 UScriptCode currentRunScript, 126 UScriptCode currentRunScript,
121 hb_direction_t direction, 127 hb_direction_t direction,
122 hb_language_t language) { 128 hb_language_t language) {
123 const FontPlatformData* platformData = &(currentFont->platformData()); 129 const FontPlatformData* platformData = &(currentFont->platformData());
124 HarfBuzzFace* face = platformData->harfBuzzFace(); 130 HarfBuzzFace* face = platformData->harfBuzzFace();
125 if (!face) { 131 if (!face) {
126 DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData."; 132 DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData.";
127 return false; 133 return false;
128 } 134 }
129 135
130 hb_buffer_set_language(harfBuzzBuffer, language); 136 hb_buffer_set_language(buffer, language);
131 hb_buffer_set_script(harfBuzzBuffer, ICUScriptToHBScript(currentRunScript)); 137 hb_buffer_set_script(buffer, ICUScriptToHBScript(currentRunScript));
132 hb_buffer_set_direction(harfBuzzBuffer, direction); 138 hb_buffer_set_direction(buffer, direction);
133 139
134 hb_font_t* hbFont = face->getScaledFont(std::move(currentFontRangeSet)); 140 hb_font_t* hbFont = face->getScaledFont(std::move(currentFontRangeSet));
135 hb_shape(hbFont, harfBuzzBuffer, fontFeatures, fontFeaturesSize); 141 hb_shape(hbFont, buffer, fontFeatures, fontFeaturesSize);
136 142
137 return true; 143 return true;
138 } 144 }
139 145
140 } // namespace 146 } // namespace
141 147
142 bool HarfBuzzShaper::extractShapeResults(hb_buffer_t* harfBuzzBuffer, 148 bool HarfBuzzShaper::extractShapeResults(hb_buffer_t* buffer,
143 ShapeResult* shapeResult, 149 ShapeResult* shapeResult,
144 bool& fontCycleQueued, 150 bool& fontCycleQueued,
145 Deque<HolesQueueItem>* holesQueue, 151 Deque<HolesQueueItem>* holesQueue,
146 const HolesQueueItem& currentQueueItem, 152 const HolesQueueItem& currentQueueItem,
147 const Font* font, 153 const Font* font,
154 TextDirection textDirection,
148 const SimpleFontData* currentFont, 155 const SimpleFontData* currentFont,
149 UScriptCode currentRunScript, 156 UScriptCode currentRunScript,
150 bool isLastResort) const { 157 bool isLastResort) const {
151 enum ClusterResult { Shaped, NotDef, Unknown }; 158 enum ClusterResult { Shaped, NotDef, Unknown };
152 ClusterResult currentClusterResult = Unknown; 159 ClusterResult currentClusterResult = Unknown;
153 ClusterResult previousClusterResult = Unknown; 160 ClusterResult previousClusterResult = Unknown;
154 unsigned previousCluster = 0; 161 unsigned previousCluster = 0;
155 unsigned currentCluster = 0; 162 unsigned currentCluster = 0;
156 163
157 // Find first notdef glyph in harfBuzzBuffer. 164 // Find first notdef glyph in buffer.
158 unsigned numGlyphs = hb_buffer_get_length(harfBuzzBuffer); 165 unsigned numGlyphs = hb_buffer_get_length(buffer);
159 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); 166 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos(buffer, 0);
160 167
161 unsigned lastChangePosition = 0; 168 unsigned lastChangePosition = 0;
162 169
163 if (!numGlyphs) { 170 if (!numGlyphs) {
164 DLOG(ERROR) << "HarfBuzz returned empty glyph buffer after shaping."; 171 DLOG(ERROR) << "HarfBuzz returned empty glyph buffer after shaping.";
165 return false; 172 return false;
166 } 173 }
167 174
168 for (unsigned glyphIndex = 0; glyphIndex <= numGlyphs; ++glyphIndex) { 175 for (unsigned glyphIndex = 0; glyphIndex <= numGlyphs; ++glyphIndex) {
169 // Iterating by clusters, check for when the state switches from shaped 176 // Iterating by clusters, check for when the state switches from shaped
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
205 previousClusterResult != Unknown; 212 previousClusterResult != Unknown;
206 if (!atChange) 213 if (!atChange)
207 continue; 214 continue;
208 215
209 // Compute the range indices of consecutive shaped or .notdef glyphs. 216 // Compute the range indices of consecutive shaped or .notdef glyphs.
210 // Cluster information for RTL runs becomes reversed, e.g. character 0 217 // Cluster information for RTL runs becomes reversed, e.g. character 0
211 // has cluster index 5 in a run of 6 characters. 218 // has cluster index 5 in a run of 6 characters.
212 unsigned numCharacters = 0; 219 unsigned numCharacters = 0;
213 unsigned numGlyphsToInsert = 0; 220 unsigned numGlyphsToInsert = 0;
214 unsigned startIndex = 0; 221 unsigned startIndex = 0;
215 if (HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer))) { 222 if (HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(buffer))) {
216 startIndex = glyphInfo[lastChangePosition].cluster; 223 startIndex = glyphInfo[lastChangePosition].cluster;
217 if (glyphIndex == numGlyphs) { 224 if (glyphIndex == numGlyphs) {
218 numCharacters = currentQueueItem.m_startIndex + 225 numCharacters = currentQueueItem.m_startIndex +
219 currentQueueItem.m_numCharacters - 226 currentQueueItem.m_numCharacters -
220 glyphInfo[lastChangePosition].cluster; 227 glyphInfo[lastChangePosition].cluster;
221 numGlyphsToInsert = numGlyphs - lastChangePosition; 228 numGlyphsToInsert = numGlyphs - lastChangePosition;
222 } else { 229 } else {
223 numCharacters = glyphInfo[glyphIndex].cluster - 230 numCharacters = glyphInfo[glyphIndex].cluster -
224 glyphInfo[lastChangePosition].cluster; 231 glyphInfo[lastChangePosition].cluster;
225 numGlyphsToInsert = glyphIndex - lastChangePosition; 232 numGlyphsToInsert = glyphIndex - lastChangePosition;
(...skipping 27 matching lines...) Expand all
253 260
254 // If numCharacters is 0, that means we hit a NotDef before shaping the 261 // If numCharacters is 0, that means we hit a NotDef before shaping the
255 // whole grapheme. We do not append it here. For the next glyph we 262 // whole grapheme. We do not append it here. For the next glyph we
256 // encounter, atChange will be true, and the characters corresponding to 263 // encounter, atChange will be true, and the characters corresponding to
257 // the grapheme will be added to the TODO queue again, attempting to 264 // the grapheme will be added to the TODO queue again, attempting to
258 // shape the whole grapheme with the next font. 265 // shape the whole grapheme with the next font.
259 // When we're getting here with the last resort font, we have no other 266 // When we're getting here with the last resort font, we have no other
260 // choice than adding boxes to the ShapeResult. 267 // choice than adding boxes to the ShapeResult.
261 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) { 268 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) {
262 hb_direction_t direction = TextDirectionToHBDirection( 269 hb_direction_t direction = TextDirectionToHBDirection(
263 m_textDirection, font->getFontDescription().orientation(), 270 textDirection, font->getFontDescription().orientation(), currentFont);
264 currentFont);
265 // Here we need to specify glyph positions. 271 // Here we need to specify glyph positions.
266 ShapeResult::RunInfo* run = new ShapeResult::RunInfo( 272 ShapeResult::RunInfo* run = new ShapeResult::RunInfo(
267 currentFont, direction, ICUScriptToHBScript(currentRunScript), 273 currentFont, direction, ICUScriptToHBScript(currentRunScript),
268 startIndex, numGlyphsToInsert, numCharacters); 274 startIndex, numGlyphsToInsert, numCharacters);
269 shapeResult->insertRun(WTF::wrapUnique(run), lastChangePosition, 275 shapeResult->insertRun(WTF::wrapUnique(run), lastChangePosition,
270 numGlyphsToInsert, harfBuzzBuffer); 276 numGlyphsToInsert, buffer);
271 } 277 }
272 lastChangePosition = glyphIndex; 278 lastChangePosition = glyphIndex;
273 } 279 }
274 return true; 280 return true;
275 } 281 }
276 282
277 static inline const SimpleFontData* fontDataAdjustedForOrientation( 283 static inline const SimpleFontData* fontDataAdjustedForOrientation(
278 const SimpleFontData* originalFont, 284 const SimpleFontData* originalFont,
279 FontOrientation runOrientation, 285 FontOrientation runOrientation,
280 OrientationIterator::RenderOrientation renderOrientation) { 286 OrientationIterator::RenderOrientation renderOrientation) {
281 if (!isVerticalBaseline(runOrientation)) 287 if (!isVerticalBaseline(runOrientation))
282 return originalFont; 288 return originalFont;
283 289
284 if (runOrientation == FontOrientation::VerticalRotated || 290 if (runOrientation == FontOrientation::VerticalRotated ||
285 (runOrientation == FontOrientation::VerticalMixed && 291 (runOrientation == FontOrientation::VerticalMixed &&
286 renderOrientation == OrientationIterator::OrientationRotateSideways)) 292 renderOrientation == OrientationIterator::OrientationRotateSideways))
287 return originalFont->verticalRightOrientationFontData().get(); 293 return originalFont->verticalRightOrientationFontData().get();
288 294
289 return originalFont; 295 return originalFont;
290 } 296 }
291 297
292 bool HarfBuzzShaper::collectFallbackHintChars( 298 bool HarfBuzzShaper::collectFallbackHintChars(
293 const Deque<HolesQueueItem>& holesQueue, 299 const Deque<HolesQueueItem>* holesQueue,
294 Vector<UChar32>& hint) const { 300 Vector<UChar32>& hint) const {
295 if (!holesQueue.size()) 301 DCHECK(holesQueue);
302 if (!holesQueue->size())
296 return false; 303 return false;
297 304
298 hint.clear(); 305 hint.clear();
299 306
300 size_t numCharsAdded = 0; 307 size_t numCharsAdded = 0;
301 for (auto it = holesQueue.begin(); it != holesQueue.end(); ++it) { 308 for (auto it = holesQueue->begin(); it != holesQueue->end(); ++it) {
302 if (it->m_action == HolesQueueNextFont) 309 if (it->m_action == HolesQueueNextFont)
303 break; 310 break;
304 311
305 UChar32 hintChar; 312 UChar32 hintChar;
306 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= 313 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= m_textLength);
307 m_normalizedBufferLength); 314 UTF16TextIterator iterator(m_text + it->m_startIndex, it->m_numCharacters);
308 UTF16TextIterator iterator(m_normalizedBuffer + it->m_startIndex,
309 it->m_numCharacters);
310 while (iterator.consume(hintChar)) { 315 while (iterator.consume(hintChar)) {
311 hint.push_back(hintChar); 316 hint.push_back(hintChar);
312 numCharsAdded++; 317 numCharsAdded++;
313 iterator.advance(); 318 iterator.advance();
314 } 319 }
315 } 320 }
316 return numCharsAdded > 0; 321 return numCharsAdded > 0;
317 } 322 }
318 323
319 namespace { 324 namespace {
320 using HolesQueueItem = HarfBuzzShaper::HolesQueueItem;
321 using HolesQueueItemAction = HarfBuzzShaper::HolesQueueItemAction;
322 325
323 void splitUntilNextCaseChange( 326 void splitUntilNextCaseChange(
324 const UChar* normalizedBuffer, 327 const UChar* normalizedBuffer,
325 Deque<HolesQueueItem>* queue, 328 Deque<blink::HolesQueueItem>* queue,
326 HolesQueueItem& currentQueueItem, 329 blink::HolesQueueItem& currentQueueItem,
327 SmallCapsIterator::SmallCapsBehavior& smallCapsBehavior) { 330 SmallCapsIterator::SmallCapsBehavior& smallCapsBehavior) {
328 unsigned numCharactersUntilCaseChange = 0; 331 unsigned numCharactersUntilCaseChange = 0;
329 SmallCapsIterator smallCapsIterator( 332 SmallCapsIterator smallCapsIterator(
330 normalizedBuffer + currentQueueItem.m_startIndex, 333 normalizedBuffer + currentQueueItem.m_startIndex,
331 currentQueueItem.m_numCharacters); 334 currentQueueItem.m_numCharacters);
332 smallCapsIterator.consume(&numCharactersUntilCaseChange, &smallCapsBehavior); 335 smallCapsIterator.consume(&numCharactersUntilCaseChange, &smallCapsBehavior);
333 if (numCharactersUntilCaseChange > 0 && 336 if (numCharactersUntilCaseChange > 0 &&
334 numCharactersUntilCaseChange < currentQueueItem.m_numCharacters) { 337 numCharactersUntilCaseChange < currentQueueItem.m_numCharacters) {
335 queue->prepend(HolesQueueItem( 338 queue->prepend(blink::HolesQueueItem(
336 HolesQueueItemAction::HolesQueueRange, 339 blink::HolesQueueItemAction::HolesQueueRange,
337 currentQueueItem.m_startIndex + numCharactersUntilCaseChange, 340 currentQueueItem.m_startIndex + numCharactersUntilCaseChange,
338 currentQueueItem.m_numCharacters - numCharactersUntilCaseChange)); 341 currentQueueItem.m_numCharacters - numCharactersUntilCaseChange));
339 currentQueueItem.m_numCharacters = numCharactersUntilCaseChange; 342 currentQueueItem.m_numCharacters = numCharactersUntilCaseChange;
340 } 343 }
341 } 344 }
342 345
343 hb_feature_t createFeature(hb_tag_t tag, uint32_t value = 0) { 346 hb_feature_t createFeature(hb_tag_t tag, uint32_t value = 0) {
344 return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */}; 347 return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */};
345 } 348 }
346 349
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 m_features->prepend(feature); 542 m_features->prepend(feature);
540 m_countFeatures++; 543 m_countFeatures++;
541 } 544 }
542 545
543 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() { 546 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() {
544 m_features->remove(0, m_countFeatures); 547 m_features->remove(0, m_countFeatures);
545 } 548 }
546 549
547 } // namespace 550 } // namespace
548 551
549 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult(const Font* font) const { 552 void HarfBuzzShaper::shapeSegment(ShapeResult* result,
550 RefPtr<ShapeResult> result = 553 Deque<HolesQueueItem>* holesQueue,
551 ShapeResult::create(font, m_normalizedBufferLength, m_textDirection); 554 hb_buffer_t* buffer,
552 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), 555 const Font* font,
553 hb_buffer_destroy); 556 FeaturesVector* fontFeatures,
554 FeaturesVector fontFeatures; 557 RunSegmenter::RunSegmenterRange segment,
555 setFontFeatures(font, &fontFeatures); 558 unsigned start,
559 unsigned end,
560 TextDirection textDirection) const {
561 DCHECK(result);
562 DCHECK(holesQueue);
563 DCHECK(buffer);
564
565 holesQueue->append(HolesQueueItem(HolesQueueNextFont, 0, 0));
566 holesQueue->append(HolesQueueItem(HolesQueueRange, segment.start,
567 segment.end - segment.start));
568
569 RefPtr<FontFallbackIterator> fallbackIterator =
570 font->createFontFallbackIterator(segment.fontFallbackPriority);
571
572 RefPtr<FontDataForRangeSet> currentFontDataForRangeSet;
573
556 const FontDescription& fontDescription = font->getFontDescription(); 574 const FontDescription& fontDescription = font->getFontDescription();
575 bool fontCycleQueued = false;
576 bool needsCapsHandling =
577 fontDescription.variantCaps() != FontDescription::CapsNormal;
578 FontOrientation orientation = fontDescription.orientation();
557 const hb_language_t language = 579 const hb_language_t language =
558 fontDescription.localeOrDefault().harfbuzzLanguage(); 580 fontDescription.localeOrDefault().harfbuzzLanguage();
559 581
560 bool needsCapsHandling =
561 fontDescription.variantCaps() != FontDescription::CapsNormal;
562 OpenTypeCapsSupport capsSupport; 582 OpenTypeCapsSupport capsSupport;
583 Vector<UChar32> fallbackCharsHint;
584 while (holesQueue->size()) {
585 HolesQueueItem currentQueueItem = holesQueue->takeFirst();
586 DCHECK(currentQueueItem.m_numCharacters);
587
588 if (currentQueueItem.m_action == HolesQueueNextFont) {
589 // For now, we're building a character list with which we probe
590 // for needed fonts depending on the declared unicode-range of a
591 // segmented CSS font. Alternatively, we can build a fake font
592 // for the shaper and check whether any glyphs were found, or
593 // define a new API on the shaper which will give us coverage
594 // information?
595 if (!collectFallbackHintChars(holesQueue, fallbackCharsHint)) {
596 // Give up shaping since we cannot retrieve a font fallback
597 // font without a hintlist.
598 holesQueue->clear();
599 break;
600 }
601
602 currentFontDataForRangeSet = fallbackIterator->next(fallbackCharsHint);
603 if (!currentFontDataForRangeSet->fontData()) {
604 DCHECK(!holesQueue->size());
605 break;
606 }
607 fontCycleQueued = false;
608 continue;
609 }
610
611 const SimpleFontData* fontData = currentFontDataForRangeSet->fontData();
612 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior =
613 SmallCapsIterator::SmallCapsSameCase;
614 if (needsCapsHandling) {
615 capsSupport = OpenTypeCapsSupport(fontData->platformData().harfBuzzFace(),
616 fontDescription.variantCaps(),
617 ICUScriptToHBScript(segment.script));
618 if (capsSupport.needsRunCaseSplitting()) {
619 splitUntilNextCaseChange(m_text, holesQueue, currentQueueItem,
620 smallCapsBehavior);
621 }
622 }
623
624 const SimpleFontData* smallcapsAdjustedFont =
625 needsCapsHandling && capsSupport.needsSyntheticFont(smallCapsBehavior)
626 ? fontData->smallCapsFontData(fontDescription).get()
627 : fontData;
628
629 // Compatibility with SimpleFontData approach of keeping a flag for
630 // overriding drawing direction.
631 // TODO: crbug.com/506224 This should go away in favor of storing that
632 // information elsewhere, for example in ShapeResult.
633 const SimpleFontData* directionAndSmallCapsAdjustedFont =
634 fontDataAdjustedForOrientation(smallcapsAdjustedFont, orientation,
635 segment.renderOrientation);
636
637 CaseMapIntend caseMapIntend = CaseMapIntend::KeepSameCase;
638 if (needsCapsHandling)
639 caseMapIntend = capsSupport.needsCaseChange(smallCapsBehavior);
640
641 CaseMappingHarfBuzzBufferFiller(
642 caseMapIntend, fontDescription.localeOrDefault(), buffer,
643 m_text + start, m_textLength, currentQueueItem.m_startIndex,
644 currentQueueItem.m_numCharacters);
645
646 CapsFeatureSettingsScopedOverlay capsOverlay(
647 fontFeatures, capsSupport.fontFeatureToUse(smallCapsBehavior));
648 hb_direction_t direction = TextDirectionToHBDirection(
649 textDirection, orientation, directionAndSmallCapsAdjustedFont);
650
651 if (!shapeRange(buffer, fontFeatures->isEmpty() ? 0 : fontFeatures->data(),
652 fontFeatures->size(), directionAndSmallCapsAdjustedFont,
653 currentFontDataForRangeSet->ranges(), segment.script,
654 direction, language))
655 DLOG(ERROR) << "Shaping range failed.";
656
657 if (!extractShapeResults(buffer, result, fontCycleQueued, holesQueue,
658 currentQueueItem, font, textDirection,
659 directionAndSmallCapsAdjustedFont, segment.script,
660 !fallbackIterator->hasNext()))
661 DLOG(ERROR) << "Shape result extraction failed.";
662
663 hb_buffer_reset(buffer);
664 }
665 }
666
667 PassRefPtr<ShapeResult> HarfBuzzShaper::shape(const Font* font,
668 TextDirection textDirection,
669 unsigned start,
670 unsigned end) const {
671 DCHECK(end >= start);
672 DCHECK(end <= m_textLength);
673
674 unsigned length = end - start;
675 RefPtr<ShapeResult> result = ShapeResult::create(font, length, textDirection);
676 HarfBuzzScopedPtr<hb_buffer_t> buffer(hb_buffer_create(), hb_buffer_destroy);
677
678 FeaturesVector fontFeatures;
679 setFontFeatures(font, &fontFeatures);
563 FontOrientation orientation = font->getFontDescription().orientation(); 680 FontOrientation orientation = font->getFontDescription().orientation();
564 681
565 RunSegmenter::RunSegmenterRange segmentRange = { 682 Deque<HolesQueueItem> holesQueue;
566 0, 0, USCRIPT_INVALID_CODE, OrientationIterator::OrientationInvalid, 683 RunSegmenter::RunSegmenterRange segmentRange = RunSegmenter::nullRange();
567 FontFallbackPriority::Invalid}; 684 RunSegmenter runSegmenter(m_text + start, length, orientation);
drott 2017/02/07 23:12:41 Offsetting the RunSegmenter to a start at an offse
568 RunSegmenter runSegmenter(m_normalizedBuffer, m_normalizedBufferLength,
569 orientation);
570
571 Vector<UChar32> fallbackCharsHint;
572 685
573 // TODO: Check whether this treatAsZerowidthspace from the previous script 686 // TODO: Check whether this treatAsZerowidthspace from the previous script
574 // segmentation plays a role here, does the new scriptRuniterator handle that 687 // segmentation plays a role here, does the new scriptRuniterator handle
575 // correctly? 688 // that correctly?
576 Deque<HolesQueueItem> holesQueue;
577 while (runSegmenter.consume(&segmentRange)) { 689 while (runSegmenter.consume(&segmentRange)) {
578 RefPtr<FontFallbackIterator> fallbackIterator = 690 shapeSegment(result.get(), &holesQueue, buffer.get(), font, &fontFeatures,
579 font->createFontFallbackIterator(segmentRange.fontFallbackPriority); 691 segmentRange, start, end, textDirection);
692 }
580 693
581 holesQueue.append(HolesQueueItem(HolesQueueNextFont, 0, 0));
582 holesQueue.append(HolesQueueItem(HolesQueueRange, segmentRange.start,
583 segmentRange.end - segmentRange.start));
584
585 RefPtr<FontDataForRangeSet> currentFontDataForRangeSet;
586
587 bool fontCycleQueued = false;
588 while (holesQueue.size()) {
589 HolesQueueItem currentQueueItem = holesQueue.takeFirst();
590
591 if (currentQueueItem.m_action == HolesQueueNextFont) {
592 // For now, we're building a character list with which we probe
593 // for needed fonts depending on the declared unicode-range of a
594 // segmented CSS font. Alternatively, we can build a fake font
595 // for the shaper and check whether any glyphs were found, or
596 // define a new API on the shaper which will give us coverage
597 // information?
598 if (!collectFallbackHintChars(holesQueue, fallbackCharsHint)) {
599 // Give up shaping since we cannot retrieve a font fallback
600 // font without a hintlist.
601 holesQueue.clear();
602 break;
603 }
604
605 currentFontDataForRangeSet = fallbackIterator->next(fallbackCharsHint);
606 if (!currentFontDataForRangeSet->fontData()) {
607 DCHECK(!holesQueue.size());
608 break;
609 }
610 fontCycleQueued = false;
611 continue;
612 }
613
614 const SimpleFontData* fontData = currentFontDataForRangeSet->fontData();
615 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior =
616 SmallCapsIterator::SmallCapsSameCase;
617 if (needsCapsHandling) {
618 capsSupport =
619 OpenTypeCapsSupport(fontData->platformData().harfBuzzFace(),
620 fontDescription.variantCaps(),
621 ICUScriptToHBScript(segmentRange.script));
622 if (capsSupport.needsRunCaseSplitting()) {
623 splitUntilNextCaseChange(m_normalizedBuffer, &holesQueue,
624 currentQueueItem, smallCapsBehavior);
625 }
626 }
627
628 ASSERT(currentQueueItem.m_numCharacters);
629
630 const SimpleFontData* smallcapsAdjustedFont =
631 needsCapsHandling && capsSupport.needsSyntheticFont(smallCapsBehavior)
632 ? fontData->smallCapsFontData(fontDescription).get()
633 : fontData;
634
635 // Compatibility with SimpleFontData approach of keeping a flag for
636 // overriding drawing direction.
637 // TODO: crbug.com/506224 This should go away in favor of storing that
638 // information elsewhere, for example in ShapeResult.
639 const SimpleFontData* directionAndSmallCapsAdjustedFont =
640 fontDataAdjustedForOrientation(smallcapsAdjustedFont, orientation,
641 segmentRange.renderOrientation);
642
643 CaseMapIntend caseMapIntend = CaseMapIntend::KeepSameCase;
644 if (needsCapsHandling)
645 caseMapIntend = capsSupport.needsCaseChange(smallCapsBehavior);
646
647 CaseMappingHarfBuzzBufferFiller(
648 caseMapIntend, fontDescription.localeOrDefault(),
649 harfBuzzBuffer.get(), m_normalizedBuffer, m_normalizedBufferLength,
650 currentQueueItem.m_startIndex, currentQueueItem.m_numCharacters);
651
652 CapsFeatureSettingsScopedOverlay capsOverlay(
653 &fontFeatures, capsSupport.fontFeatureToUse(smallCapsBehavior));
654
655 hb_direction_t direction = TextDirectionToHBDirection(
656 m_textDirection, orientation, directionAndSmallCapsAdjustedFont);
657
658 if (!shapeRange(harfBuzzBuffer.get(),
659 fontFeatures.isEmpty() ? 0 : fontFeatures.data(),
660 fontFeatures.size(), directionAndSmallCapsAdjustedFont,
661 currentFontDataForRangeSet->ranges(), segmentRange.script,
662 direction, language))
663 DLOG(ERROR) << "Shaping range failed.";
664
665 if (!extractShapeResults(
666 harfBuzzBuffer.get(), result.get(), fontCycleQueued, &holesQueue,
667 currentQueueItem, font, directionAndSmallCapsAdjustedFont,
668 segmentRange.script, !fallbackIterator->hasNext()))
669 DLOG(ERROR) << "Shape result extraction failed.";
670
671 hb_buffer_reset(harfBuzzBuffer.get());
672 }
673 }
674 return result.release(); 694 return result.release();
675 } 695 }
676 696
697 PassRefPtr<ShapeResult> HarfBuzzShaper::shape(
698 const Font* font,
699 TextDirection textDirection) const {
700 return shape(font, textDirection, 0, m_textLength);
701 }
677 } // namespace blink 702 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698