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

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: Cleanup comments and adjust tolerance 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,
85 unsigned length, 95 unsigned length,
86 TextDirection direction) 96 TextDirection direction)
87 : m_normalizedBuffer(text), 97 : m_text(text), m_textLength(length), m_paragraphDirection(direction) {}
88 m_normalizedBufferLength(length),
89 m_textDirection(direction) {}
90 98
91 namespace { 99 namespace {
92 100
93 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built 101 // A port of hb_icu_script_to_script because harfbuzz on CrOS is built
94 // without hb-icu. See http://crbug.com/356929 102 // without hb-icu. See http://crbug.com/356929
95 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) { 103 static inline hb_script_t ICUScriptToHBScript(UScriptCode script) {
96 if (UNLIKELY(script == USCRIPT_INVALID_CODE)) 104 if (UNLIKELY(script == USCRIPT_INVALID_CODE))
97 return HB_SCRIPT_INVALID; 105 return HB_SCRIPT_INVALID;
98 106
99 return hb_script_from_string(uscript_getShortName(script), -1); 107 return hb_script_from_string(uscript_getShortName(script), -1);
100 } 108 }
101 109
102 static inline hb_direction_t TextDirectionToHBDirection( 110 static inline hb_direction_t TextDirectionToHBDirection(
103 TextDirection dir, 111 TextDirection dir,
104 FontOrientation orientation, 112 FontOrientation orientation,
105 const SimpleFontData* fontData) { 113 const SimpleFontData* fontData) {
106 hb_direction_t harfBuzzDirection = 114 hb_direction_t harfBuzzDirection =
107 isVerticalAnyUpright(orientation) && 115 isVerticalAnyUpright(orientation) &&
108 !fontData->isTextOrientationFallback() 116 !fontData->isTextOrientationFallback()
109 ? HB_DIRECTION_TTB 117 ? HB_DIRECTION_TTB
110 : HB_DIRECTION_LTR; 118 : HB_DIRECTION_LTR;
111 return dir == TextDirection::kRtl ? HB_DIRECTION_REVERSE(harfBuzzDirection) 119 return dir == TextDirection::kRtl ? HB_DIRECTION_REVERSE(harfBuzzDirection)
112 : harfBuzzDirection; 120 : harfBuzzDirection;
113 } 121 }
114 122
115 inline bool shapeRange(hb_buffer_t* harfBuzzBuffer, 123 inline bool shapeRange(hb_buffer_t* buffer,
116 hb_feature_t* fontFeatures, 124 hb_feature_t* fontFeatures,
117 unsigned fontFeaturesSize, 125 unsigned fontFeaturesSize,
118 const SimpleFontData* currentFont, 126 const SimpleFontData* currentFont,
119 PassRefPtr<UnicodeRangeSet> currentFontRangeSet, 127 PassRefPtr<UnicodeRangeSet> currentFontRangeSet,
120 UScriptCode currentRunScript, 128 UScriptCode currentRunScript,
121 hb_direction_t direction, 129 hb_direction_t direction,
122 hb_language_t language) { 130 hb_language_t language) {
123 const FontPlatformData* platformData = &(currentFont->platformData()); 131 const FontPlatformData* platformData = &(currentFont->platformData());
124 HarfBuzzFace* face = platformData->harfBuzzFace(); 132 HarfBuzzFace* face = platformData->harfBuzzFace();
125 if (!face) { 133 if (!face) {
126 DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData."; 134 DLOG(ERROR) << "Could not create HarfBuzzFace from FontPlatformData.";
127 return false; 135 return false;
128 } 136 }
129 137
130 hb_buffer_set_language(harfBuzzBuffer, language); 138 hb_buffer_set_language(buffer, language);
131 hb_buffer_set_script(harfBuzzBuffer, ICUScriptToHBScript(currentRunScript)); 139 hb_buffer_set_script(buffer, ICUScriptToHBScript(currentRunScript));
132 hb_buffer_set_direction(harfBuzzBuffer, direction); 140 hb_buffer_set_direction(buffer, direction);
133 141
134 hb_font_t* hbFont = face->getScaledFont(std::move(currentFontRangeSet)); 142 hb_font_t* hbFont = face->getScaledFont(std::move(currentFontRangeSet));
135 hb_shape(hbFont, harfBuzzBuffer, fontFeatures, fontFeaturesSize); 143 hb_shape(hbFont, buffer, fontFeatures, fontFeaturesSize);
136 144
137 return true; 145 return true;
138 } 146 }
139 147
140 } // namespace 148 } // namespace
141 149
142 bool HarfBuzzShaper::extractShapeResults(hb_buffer_t* harfBuzzBuffer, 150 bool HarfBuzzShaper::extractShapeResults(hb_buffer_t* buffer,
143 ShapeResult* shapeResult, 151 ShapeResult* shapeResult,
144 bool& fontCycleQueued, 152 bool& fontCycleQueued,
145 Deque<HolesQueueItem>* holesQueue, 153 Deque<HolesQueueItem>* holesQueue,
146 const HolesQueueItem& currentQueueItem, 154 const HolesQueueItem& currentQueueItem,
147 const Font* font, 155 const Font* font,
148 const SimpleFontData* currentFont, 156 const SimpleFontData* currentFont,
149 UScriptCode currentRunScript, 157 UScriptCode currentRunScript,
150 bool isLastResort) const { 158 bool isLastResort) const {
151 enum ClusterResult { Shaped, NotDef, Unknown }; 159 enum ClusterResult { Shaped, NotDef, Unknown };
152 ClusterResult currentClusterResult = Unknown; 160 ClusterResult currentClusterResult = Unknown;
153 ClusterResult previousClusterResult = Unknown; 161 ClusterResult previousClusterResult = Unknown;
154 unsigned previousCluster = 0; 162 unsigned previousCluster = 0;
155 unsigned currentCluster = 0; 163 unsigned currentCluster = 0;
156 164
157 // Find first notdef glyph in harfBuzzBuffer. 165 // Find first notdef glyph in buffer.
158 unsigned numGlyphs = hb_buffer_get_length(harfBuzzBuffer); 166 unsigned numGlyphs = hb_buffer_get_length(buffer);
159 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); 167 hb_glyph_info_t* glyphInfo = hb_buffer_get_glyph_infos(buffer, 0);
160 168
161 unsigned lastChangePosition = 0; 169 unsigned lastChangePosition = 0;
162 170
163 if (!numGlyphs) { 171 if (!numGlyphs) {
164 DLOG(ERROR) << "HarfBuzz returned empty glyph buffer after shaping."; 172 DLOG(ERROR) << "HarfBuzz returned empty glyph buffer after shaping.";
165 return false; 173 return false;
166 } 174 }
167 175
168 for (unsigned glyphIndex = 0; glyphIndex <= numGlyphs; ++glyphIndex) { 176 for (unsigned glyphIndex = 0; glyphIndex <= numGlyphs; ++glyphIndex) {
169 // Iterating by clusters, check for when the state switches from shaped 177 // 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; 213 previousClusterResult != Unknown;
206 if (!atChange) 214 if (!atChange)
207 continue; 215 continue;
208 216
209 // Compute the range indices of consecutive shaped or .notdef glyphs. 217 // Compute the range indices of consecutive shaped or .notdef glyphs.
210 // Cluster information for RTL runs becomes reversed, e.g. character 0 218 // Cluster information for RTL runs becomes reversed, e.g. character 0
211 // has cluster index 5 in a run of 6 characters. 219 // has cluster index 5 in a run of 6 characters.
212 unsigned numCharacters = 0; 220 unsigned numCharacters = 0;
213 unsigned numGlyphsToInsert = 0; 221 unsigned numGlyphsToInsert = 0;
214 unsigned startIndex = 0; 222 unsigned startIndex = 0;
215 if (HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(harfBuzzBuffer))) { 223 if (HB_DIRECTION_IS_FORWARD(hb_buffer_get_direction(buffer))) {
216 startIndex = glyphInfo[lastChangePosition].cluster; 224 startIndex = glyphInfo[lastChangePosition].cluster;
217 if (glyphIndex == numGlyphs) { 225 if (glyphIndex == numGlyphs) {
218 numCharacters = currentQueueItem.m_startIndex + 226 numCharacters = currentQueueItem.m_startIndex +
219 currentQueueItem.m_numCharacters - 227 currentQueueItem.m_numCharacters -
220 glyphInfo[lastChangePosition].cluster; 228 glyphInfo[lastChangePosition].cluster;
221 numGlyphsToInsert = numGlyphs - lastChangePosition; 229 numGlyphsToInsert = numGlyphs - lastChangePosition;
222 } else { 230 } else {
223 numCharacters = glyphInfo[glyphIndex].cluster - 231 numCharacters = glyphInfo[glyphIndex].cluster -
224 glyphInfo[lastChangePosition].cluster; 232 glyphInfo[lastChangePosition].cluster;
225 numGlyphsToInsert = glyphIndex - lastChangePosition; 233 numGlyphsToInsert = glyphIndex - lastChangePosition;
(...skipping 27 matching lines...) Expand all
253 261
254 // If numCharacters is 0, that means we hit a NotDef before shaping the 262 // 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 263 // whole grapheme. We do not append it here. For the next glyph we
256 // encounter, atChange will be true, and the characters corresponding to 264 // encounter, atChange will be true, and the characters corresponding to
257 // the grapheme will be added to the TODO queue again, attempting to 265 // the grapheme will be added to the TODO queue again, attempting to
258 // shape the whole grapheme with the next font. 266 // shape the whole grapheme with the next font.
259 // When we're getting here with the last resort font, we have no other 267 // When we're getting here with the last resort font, we have no other
260 // choice than adding boxes to the ShapeResult. 268 // choice than adding boxes to the ShapeResult.
261 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) { 269 if ((currentClusterResult == NotDef && numCharacters) || isLastResort) {
262 hb_direction_t direction = TextDirectionToHBDirection( 270 hb_direction_t direction = TextDirectionToHBDirection(
263 m_textDirection, font->getFontDescription().orientation(), 271 m_paragraphDirection, font->getFontDescription().orientation(),
264 currentFont); 272 currentFont);
265 // Here we need to specify glyph positions. 273 // Here we need to specify glyph positions.
266 ShapeResult::RunInfo* run = new ShapeResult::RunInfo( 274 ShapeResult::RunInfo* run = new ShapeResult::RunInfo(
267 currentFont, direction, ICUScriptToHBScript(currentRunScript), 275 currentFont, direction, ICUScriptToHBScript(currentRunScript),
268 startIndex, numGlyphsToInsert, numCharacters); 276 startIndex, numGlyphsToInsert, numCharacters);
269 shapeResult->insertRun(WTF::wrapUnique(run), lastChangePosition, 277 shapeResult->insertRun(WTF::wrapUnique(run), lastChangePosition,
270 numGlyphsToInsert, harfBuzzBuffer); 278 numGlyphsToInsert, buffer);
271 } 279 }
272 lastChangePosition = glyphIndex; 280 lastChangePosition = glyphIndex;
273 } 281 }
274 return true; 282 return true;
275 } 283 }
276 284
277 static inline const SimpleFontData* fontDataAdjustedForOrientation( 285 static inline const SimpleFontData* fontDataAdjustedForOrientation(
278 const SimpleFontData* originalFont, 286 const SimpleFontData* originalFont,
279 FontOrientation runOrientation, 287 FontOrientation runOrientation,
280 OrientationIterator::RenderOrientation renderOrientation) { 288 OrientationIterator::RenderOrientation renderOrientation) {
281 if (!isVerticalBaseline(runOrientation)) 289 if (!isVerticalBaseline(runOrientation))
282 return originalFont; 290 return originalFont;
283 291
284 if (runOrientation == FontOrientation::VerticalRotated || 292 if (runOrientation == FontOrientation::VerticalRotated ||
285 (runOrientation == FontOrientation::VerticalMixed && 293 (runOrientation == FontOrientation::VerticalMixed &&
286 renderOrientation == OrientationIterator::OrientationRotateSideways)) 294 renderOrientation == OrientationIterator::OrientationRotateSideways))
287 return originalFont->verticalRightOrientationFontData().get(); 295 return originalFont->verticalRightOrientationFontData().get();
288 296
289 return originalFont; 297 return originalFont;
290 } 298 }
291 299
292 bool HarfBuzzShaper::collectFallbackHintChars( 300 bool HarfBuzzShaper::collectFallbackHintChars(
293 const Deque<HolesQueueItem>& holesQueue, 301 const Deque<HolesQueueItem>* holesQueue,
294 Vector<UChar32>& hint) const { 302 Vector<UChar32>& hint) const {
295 if (!holesQueue.size()) 303 DCHECK(holesQueue);
304 if (!holesQueue->size())
296 return false; 305 return false;
297 306
298 hint.clear(); 307 hint.clear();
299 308
300 size_t numCharsAdded = 0; 309 size_t numCharsAdded = 0;
301 for (auto it = holesQueue.begin(); it != holesQueue.end(); ++it) { 310 for (auto it = holesQueue->begin(); it != holesQueue->end(); ++it) {
302 if (it->m_action == HolesQueueNextFont) 311 if (it->m_action == HolesQueueNextFont)
303 break; 312 break;
304 313
305 UChar32 hintChar; 314 UChar32 hintChar;
306 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= 315 RELEASE_ASSERT(it->m_startIndex + it->m_numCharacters <= m_textLength);
307 m_normalizedBufferLength); 316 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)) { 317 while (iterator.consume(hintChar)) {
311 hint.push_back(hintChar); 318 hint.push_back(hintChar);
312 numCharsAdded++; 319 numCharsAdded++;
313 iterator.advance(); 320 iterator.advance();
314 } 321 }
315 } 322 }
316 return numCharsAdded > 0; 323 return numCharsAdded > 0;
317 } 324 }
318 325
319 namespace { 326 namespace {
320 using HolesQueueItem = HarfBuzzShaper::HolesQueueItem;
321 using HolesQueueItemAction = HarfBuzzShaper::HolesQueueItemAction;
322 327
323 void splitUntilNextCaseChange( 328 void splitUntilNextCaseChange(
324 const UChar* normalizedBuffer, 329 const UChar* normalizedBuffer,
325 Deque<HolesQueueItem>* queue, 330 Deque<blink::HolesQueueItem>* queue,
326 HolesQueueItem& currentQueueItem, 331 blink::HolesQueueItem& currentQueueItem,
327 SmallCapsIterator::SmallCapsBehavior& smallCapsBehavior) { 332 SmallCapsIterator::SmallCapsBehavior& smallCapsBehavior) {
328 unsigned numCharactersUntilCaseChange = 0; 333 unsigned numCharactersUntilCaseChange = 0;
329 SmallCapsIterator smallCapsIterator( 334 SmallCapsIterator smallCapsIterator(
330 normalizedBuffer + currentQueueItem.m_startIndex, 335 normalizedBuffer + currentQueueItem.m_startIndex,
331 currentQueueItem.m_numCharacters); 336 currentQueueItem.m_numCharacters);
332 smallCapsIterator.consume(&numCharactersUntilCaseChange, &smallCapsBehavior); 337 smallCapsIterator.consume(&numCharactersUntilCaseChange, &smallCapsBehavior);
333 if (numCharactersUntilCaseChange > 0 && 338 if (numCharactersUntilCaseChange > 0 &&
334 numCharactersUntilCaseChange < currentQueueItem.m_numCharacters) { 339 numCharactersUntilCaseChange < currentQueueItem.m_numCharacters) {
335 queue->prepend(HolesQueueItem( 340 queue->prepend(blink::HolesQueueItem(
336 HolesQueueItemAction::HolesQueueRange, 341 blink::HolesQueueItemAction::HolesQueueRange,
337 currentQueueItem.m_startIndex + numCharactersUntilCaseChange, 342 currentQueueItem.m_startIndex + numCharactersUntilCaseChange,
338 currentQueueItem.m_numCharacters - numCharactersUntilCaseChange)); 343 currentQueueItem.m_numCharacters - numCharactersUntilCaseChange));
339 currentQueueItem.m_numCharacters = numCharactersUntilCaseChange; 344 currentQueueItem.m_numCharacters = numCharactersUntilCaseChange;
340 } 345 }
341 } 346 }
342 347
343 hb_feature_t createFeature(hb_tag_t tag, uint32_t value = 0) { 348 hb_feature_t createFeature(hb_tag_t tag, uint32_t value = 0) {
344 return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */}; 349 return {tag, value, 0 /* start */, static_cast<unsigned>(-1) /* end */};
345 } 350 }
346 351
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after
539 m_features->prepend(feature); 544 m_features->prepend(feature);
540 m_countFeatures++; 545 m_countFeatures++;
541 } 546 }
542 547
543 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() { 548 CapsFeatureSettingsScopedOverlay::~CapsFeatureSettingsScopedOverlay() {
544 m_features->remove(0, m_countFeatures); 549 m_features->remove(0, m_countFeatures);
545 } 550 }
546 551
547 } // namespace 552 } // namespace
548 553
549 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult(const Font* font) const { 554 void HarfBuzzShaper::shapeSegment(ShapeResult* result,
550 RefPtr<ShapeResult> result = 555 Deque<HolesQueueItem>* holesQueue,
551 ShapeResult::create(font, m_normalizedBufferLength, m_textDirection); 556 hb_buffer_t* buffer,
552 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), 557 const Font* font,
553 hb_buffer_destroy); 558 FeaturesVector* fontFeatures,
554 FeaturesVector fontFeatures; 559 RunSegmenter::RunSegmenterRange segment,
555 setFontFeatures(font, &fontFeatures); 560 unsigned start,
561 unsigned end) const {
562 DCHECK(result);
563 DCHECK(holesQueue);
564 DCHECK(buffer);
565
556 const FontDescription& fontDescription = font->getFontDescription(); 566 const FontDescription& fontDescription = font->getFontDescription();
557 const hb_language_t language = 567 const hb_language_t language =
558 fontDescription.localeOrDefault().harfbuzzLanguage(); 568 fontDescription.localeOrDefault().harfbuzzLanguage();
559
560 bool needsCapsHandling = 569 bool needsCapsHandling =
561 fontDescription.variantCaps() != FontDescription::CapsNormal; 570 fontDescription.variantCaps() != FontDescription::CapsNormal;
562 OpenTypeCapsSupport capsSupport; 571 OpenTypeCapsSupport capsSupport;
572
573 FontOrientation orientation = font->getFontDescription().orientation();
574 RefPtr<FontFallbackIterator> fallbackIterator =
575 font->createFontFallbackIterator(segment.fontFallbackPriority);
576
577 holesQueue->append(HolesQueueItem(HolesQueueNextFont, 0, 0));
578 holesQueue->append(HolesQueueItem(HolesQueueRange, segment.start,
579 segment.end - segment.start));
580
581 bool fontCycleQueued = false;
582 Vector<UChar32> fallbackCharsHint;
583 RefPtr<FontDataForRangeSet> currentFontDataForRangeSet;
584 while (holesQueue->size()) {
585 HolesQueueItem currentQueueItem = holesQueue->takeFirst();
586
587 if (currentQueueItem.m_action == HolesQueueNextFont) {
588 // For now, we're building a character list with which we probe
589 // for needed fonts depending on the declared unicode-range of a
590 // segmented CSS font. Alternatively, we can build a fake font
591 // for the shaper and check whether any glyphs were found, or
592 // define a new API on the shaper which will give us coverage
593 // information?
594 if (!collectFallbackHintChars(holesQueue, fallbackCharsHint)) {
595 // Give up shaping since we cannot retrieve a font fallback
596 // font without a hintlist.
597 holesQueue->clear();
598 break;
599 }
600
601 currentFontDataForRangeSet = fallbackIterator->next(fallbackCharsHint);
602 if (!currentFontDataForRangeSet->fontData()) {
603 DCHECK(!holesQueue->size());
604 break;
605 }
606 fontCycleQueued = false;
607 continue;
608 }
609
610 const SimpleFontData* fontData = currentFontDataForRangeSet->fontData();
611 SmallCapsIterator::SmallCapsBehavior smallCapsBehavior =
612 SmallCapsIterator::SmallCapsSameCase;
613 if (needsCapsHandling) {
614 capsSupport = OpenTypeCapsSupport(fontData->platformData().harfBuzzFace(),
615 fontDescription.variantCaps(),
616 ICUScriptToHBScript(segment.script));
617 if (capsSupport.needsRunCaseSplitting()) {
618 splitUntilNextCaseChange(m_text, holesQueue, currentQueueItem,
619 smallCapsBehavior);
620 }
621 }
622
623 DCHECK(currentQueueItem.m_numCharacters);
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 // Clamp the start and end offsets of the queue item to the offsets
drott 2017/02/08 15:52:59 What do you anticipate these shapeStart and shapeE
642 // representing the shaping window.
643 unsigned shapeStart = std::max(start, currentQueueItem.m_startIndex);
644 unsigned shapeEnd = std::min(
645 end, currentQueueItem.m_startIndex + currentQueueItem.m_numCharacters);
646
647 CaseMappingHarfBuzzBufferFiller(
648 caseMapIntend, fontDescription.localeOrDefault(), buffer, m_text,
649 m_textLength, shapeStart, shapeEnd - shapeStart);
650
651 CapsFeatureSettingsScopedOverlay capsOverlay(
652 fontFeatures, capsSupport.fontFeatureToUse(smallCapsBehavior));
653 hb_direction_t direction = TextDirectionToHBDirection(
654 m_paragraphDirection, orientation, directionAndSmallCapsAdjustedFont);
655
656 if (!shapeRange(buffer, fontFeatures->isEmpty() ? 0 : fontFeatures->data(),
657 fontFeatures->size(), directionAndSmallCapsAdjustedFont,
658 currentFontDataForRangeSet->ranges(), segment.script,
659 direction, language))
660 DLOG(ERROR) << "Shaping range failed.";
661
662 if (!extractShapeResults(buffer, result, fontCycleQueued, holesQueue,
663 currentQueueItem, font,
664 directionAndSmallCapsAdjustedFont, segment.script,
665 !fallbackIterator->hasNext()))
666 DLOG(ERROR) << "Shape result extraction failed.";
667
668 hb_buffer_reset(buffer);
669 }
670 }
671
672 PassRefPtr<ShapeResult> HarfBuzzShaper::shape(const Font* font,
673 unsigned start,
674 unsigned end) const {
675 DCHECK(end >= start);
676 DCHECK(end <= m_textLength);
677
678 unsigned length = end - start;
679 RefPtr<ShapeResult> result =
680 ShapeResult::create(font, length, m_paragraphDirection);
681 HarfBuzzScopedPtr<hb_buffer_t> buffer(hb_buffer_create(), hb_buffer_destroy);
682
683 FeaturesVector fontFeatures;
684 setFontFeatures(font, &fontFeatures);
563 FontOrientation orientation = font->getFontDescription().orientation(); 685 FontOrientation orientation = font->getFontDescription().orientation();
564 686
565 RunSegmenter::RunSegmenterRange segmentRange = { 687 // Run segmentation needs to operate on the entire string, regardless of the
566 0, 0, USCRIPT_INVALID_CODE, OrientationIterator::OrientationInvalid, 688 // shaping window (defined by the start and end parameters).
567 FontFallbackPriority::Invalid}; 689 RunSegmenter::RunSegmenterRange segmentRange = RunSegmenter::nullRange();
568 RunSegmenter runSegmenter(m_normalizedBuffer, m_normalizedBufferLength, 690 RunSegmenter runSegmenter(m_text, m_textLength, orientation);
569 orientation);
570 691
571 Vector<UChar32> fallbackCharsHint;
572
573 // TODO: Check whether this treatAsZerowidthspace from the previous script
574 // segmentation plays a role here, does the new scriptRuniterator handle that
575 // correctly?
576 Deque<HolesQueueItem> holesQueue; 692 Deque<HolesQueueItem> holesQueue;
577 while (runSegmenter.consume(&segmentRange)) { 693 while (runSegmenter.consume(&segmentRange)) {
578 RefPtr<FontFallbackIterator> fallbackIterator = 694 // Only shape segments within the range indicated by start and end offsets.
drott 2017/02/08 15:52:59 IIUC the condition currently means: // Only shape
579 font->createFontFallbackIterator(segmentRange.fontFallbackPriority); 695 if (start < segmentRange.end && end > segmentRange.start) {
580 696 shapeSegment(result.get(), &holesQueue, buffer.get(), font, &fontFeatures,
581 holesQueue.append(HolesQueueItem(HolesQueueNextFont, 0, 0)); 697 segmentRange, start, end);
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 } 698 }
673 } 699 }
674 return result.release(); 700 return result.release();
675 } 701 }
676 702
703 PassRefPtr<ShapeResult> HarfBuzzShaper::shape(const Font* font) const {
704 return shape(font, 0, m_textLength);
705 }
677 } // namespace blink 706 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698