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

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

Issue 1192223002: Optimize Complex Text Shaping and Caching (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Addressing review comments Created 5 years, 6 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 | Annotate | Revision Log
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 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
47 47
48 #include <list> 48 #include <list>
49 #include <map> 49 #include <map>
50 #include <string> 50 #include <string>
51 #include <unicode/normlzr.h> 51 #include <unicode/normlzr.h>
52 #include <unicode/uchar.h> 52 #include <unicode/uchar.h>
53 #include <unicode/uscript.h> 53 #include <unicode/uscript.h>
54 54
55 namespace blink { 55 namespace blink {
56 56
57 struct HarfBuzzRunGlyphData {
58 uint16_t glyph;
59 uint16_t characterIndex;
60 float advance;
61 FloatSize offset;
62 };
63
64 struct ShapeResult::RunInfo {
65 RunInfo(const SimpleFontData* font, hb_direction_t dir, hb_script_t script,
66 unsigned startIndex, unsigned numGlyphs, unsigned numCharacters)
67 : m_fontData(font), m_direction(dir), m_script(script)
68 , m_startIndex(startIndex), m_numCharacters(numCharacters)
69 , m_numGlyphs(numGlyphs)
70 {
71 m_glyphData.resize(m_numGlyphs);
72 }
73
74 float xPositionForOffset(unsigned) const;
75 int characterIndexForXPosition(float) const;
76 void setGlyphAndPositions(unsigned index, uint16_t glyphId, float advance,
77 float offsetX, float offsetY);
78
79 void addAdvance(unsigned index, float advance)
80 {
81 m_glyphData[index].advance += advance;
82 }
83
84 size_t glyphToCharacterIndex(size_t i) const
85 {
86 return m_startIndex + m_glyphData[i].characterIndex;
87 }
88
89 const SimpleFontData* m_fontData;
90 hb_direction_t m_direction;
91 hb_script_t m_script;
92 Vector<HarfBuzzRunGlyphData> m_glyphData;
93 unsigned m_startIndex;
94 unsigned m_numCharacters;
95 unsigned m_numGlyphs;
96 float m_width;
97 };
98
99 float ShapeResult::RunInfo::xPositionForOffset(unsigned offset) const
100 {
101 ASSERT(offset < m_numCharacters);
102 unsigned glyphIndex = 0;
103 float position = 0;
104 if (m_direction == HB_DIRECTION_RTL) {
105 while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterInde x > offset) {
106 position += m_glyphData[glyphIndex].advance;
107 ++glyphIndex;
108 }
109 // For RTL, we need to return the right side boundary of the character.
110 // Add advance of glyphs which are part of the character.
111 while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].character Index == m_glyphData[glyphIndex + 1].characterIndex) {
112 position += m_glyphData[glyphIndex].advance;
113 ++glyphIndex;
114 }
115 position += m_glyphData[glyphIndex].advance;
116 } else {
117 while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterInde x < offset) {
118 position += m_glyphData[glyphIndex].advance;
119 ++glyphIndex;
120 }
121 }
122 return position;
123 }
124
125 int ShapeResult::RunInfo::characterIndexForXPosition(float targetX) const
126 {
127 ASSERT(targetX <= m_width);
128 float currentX = 0;
129 float currentAdvance = m_glyphData[0].advance;
130 unsigned glyphIndex = 0;
131
132 // Sum up advances that belong to the first character.
133 while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterInde x == m_glyphData[glyphIndex + 1].characterIndex)
134 currentAdvance += m_glyphData[++glyphIndex].advance;
135 currentAdvance = currentAdvance / 2.0;
136 if (targetX <= currentAdvance)
137 return m_direction == HB_DIRECTION_RTL ? m_numCharacters : 0;
138
139 currentX = currentAdvance;
140 ++glyphIndex;
141 while (glyphIndex < m_numGlyphs) {
142 unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex ;
143 float prevAdvance = currentAdvance;
144 currentAdvance = m_glyphData[glyphIndex].advance;
145 while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].character Index == m_glyphData[glyphIndex + 1].characterIndex)
146 currentAdvance += m_glyphData[++glyphIndex].advance;
147 currentAdvance = currentAdvance / 2.0;
148 float nextX = currentX + prevAdvance + currentAdvance;
149 if (currentX <= targetX && targetX <= nextX)
150 return m_direction == HB_DIRECTION_RTL ? prevCharacterIndex : m_glyp hData[glyphIndex].characterIndex;
151 currentX = nextX;
152 ++glyphIndex;
153 }
154
155 return m_direction == HB_DIRECTION_RTL ? 0 : m_numCharacters;
156 }
157
158 void ShapeResult::RunInfo::setGlyphAndPositions(unsigned index,
159 uint16_t glyphId, float advance, float offsetX, float offsetY)
160 {
161 HarfBuzzRunGlyphData& data = m_glyphData[index];
162 data.glyph = glyphId;
163 data.advance = advance;
164 data.offset = FloatSize(offsetX, offsetY);
165 }
166
167 ShapeResult::~ShapeResult()
168 {
169 unsigned destroyed = 0;
170 for (unsigned i = 0; i < m_runs.size(); i++) {
171 if (m_runs[i]) {
172 delete m_runs[i];
173 destroyed++;
174 }
175 }
176 }
177
178 float ShapeResult::fillGlyphBuffer(GlyphBuffer* glyphBuffer,
179 float initialAdvance, unsigned from, unsigned to, unsigned runOffset)
180 {
181 ASSERT(glyphBuffer);
182 unsigned numRuns = m_runs.size();
183 float advanceSoFar = initialAdvance;
184
185 if (m_direction == LTR) {
186 for (unsigned i = 0; i < numRuns; i++) {
187 advanceSoFar += fillGlyphBufferForRun<LTR>(glyphBuffer,
188 m_runs[i], advanceSoFar, from, to, runOffset);
189 }
190 } else {
191 for (unsigned i = 0; i < numRuns; i++) {
192 advanceSoFar += fillGlyphBufferForRun<RTL>(glyphBuffer,
193 m_runs[i], advanceSoFar, from, to, runOffset);
194 }
195 }
196
197 return advanceSoFar - initialAdvance;
198 }
199
200 float ShapeResult::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer,
201 float initialAdvance, const TextRun& textRun, const GlyphData* emphasisData,
202 unsigned from, unsigned to, unsigned runOffset)
203 {
204 ASSERT(glyphBuffer);
205 unsigned numRuns = m_runs.size();
206 float advanceSoFar = initialAdvance;
207 for (unsigned i = 0; i < numRuns; i++) {
208 const RunInfo* run = m_runs[m_direction == LTR ? i : (numRuns - i - 1)];
209 advanceSoFar += fillGlyphBufferForTextEmphasisRun(glyphBuffer,
210 run, textRun, emphasisData,
211 advanceSoFar, from, to, runOffset);
212 }
213
214 return advanceSoFar - initialAdvance;
215 }
216
217 static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
218 hb_direction_t direction, const SimpleFontData* fontData,
219 const HarfBuzzRunGlyphData& glyphData)
220 {
221 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
222 ? FloatPoint(advance, 0)
223 : FloatPoint(0, advance);
224 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
225 }
226
227 template<TextDirection direction>
drott 2015/06/23 12:45:52 I found this a bit surprising, why did you chose t
eae 2015/06/23 22:25:15 Less code duplication than having two copies of th
228 float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
229 const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
230 unsigned runOffset)
231 {
232 float advanceSoFar = initialAdvance;
233 unsigned numGlyphs = run->m_numGlyphs;
234 for (unsigned i = 0; i < numGlyphs; ++i) {
235 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
236 uint16_t currentCharacterIndex = run->m_startIndex +
237 glyphData.characterIndex + runOffset;
238 if ((direction == RTL && currentCharacterIndex >= to)
239 || (direction == LTR && currentCharacterIndex < from)) {
240 advanceSoFar += glyphData.advance;
241 } else if ((direction == RTL && currentCharacterIndex >= from)
242 || (direction == LTR && currentCharacterIndex < to)) {
243 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
244 run->m_fontData, glyphData);
245 advanceSoFar += glyphData.advance;
246 }
247 }
248
249 return advanceSoFar - initialAdvance;
250 }
251
252 static inline unsigned countGraphemesInCluster(const UChar* str,
253 unsigned strLength, uint16_t startIndex, uint16_t endIndex)
254 {
255 if (startIndex > endIndex) {
256 uint16_t tempIndex = startIndex;
257 startIndex = endIndex;
258 endIndex = tempIndex;
259 }
260 uint16_t length = endIndex - startIndex;
261 ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
262 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startInde x], length);
263
264 int cursorPos = cursorPosIterator->current();
265 int numGraphemes = -1;
266 while (0 <= cursorPos) {
267 cursorPos = cursorPosIterator->next();
268 numGraphemes++;
269 }
270 return numGraphemes < 0 ? 0 : numGraphemes;
271 }
272
273 static inline void addEmphasisMark(GlyphBuffer* buffer,
274 const GlyphData* emphasisData, FloatPoint glyphCenter,
275 float midGlyphOffset)
276 {
277 ASSERT(buffer);
278 ASSERT(emphasisData);
279
280 const SimpleFontData* emphasisFontData = emphasisData->fontData;
281 ASSERT(emphasisFontData);
282
283 bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright()
284 && emphasisFontData->verticalData();
285
286 if (!isVertical) {
287 buffer->add(emphasisData->glyph, emphasisFontData,
288 midGlyphOffset - glyphCenter.x());
289 } else {
290 buffer->add(emphasisData->glyph, emphasisFontData,
291 FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y()));
292 }
293 }
294
295 float ShapeResult::fillGlyphBufferForTextEmphasisRun(GlyphBuffer* glyphBuffer,
296 const RunInfo* run, const TextRun& textRun, const GlyphData* emphasisData,
297 float initialAdvance, unsigned from, unsigned to, unsigned runOffset)
298 {
299 unsigned numGlyphs = run->m_numGlyphs;
300 if (!numGlyphs)
301 return 0;
302
303 unsigned graphemesInCluster = 1;
304 float clusterAdvance = 0;
305 uint16_t clusterStart;
306
307 FloatPoint glyphCenter = emphasisData->fontData->
308 boundsForGlyph(emphasisData->glyph).center();
309
310 // A "cluster" in this context means a cluster as it is used by HarfBuzz:
311 // The minimal group of characters and corresponding glyphs, that cannot be broken
312 // down further from a text shaping point of view.
313 // A cluster can contain multiple glyphs and grapheme clusters, with mutuall y
314 // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clu sters,
315 // then linearly split the sum of corresponding glyph advances by the number of
316 // grapheme clusters in order to find positions for emphasis mark drawing.
317 if (m_direction == RTL)
318 clusterStart = run->m_startIndex + run->m_numCharacters;
319 else
320 clusterStart = run->glyphToCharacterIndex(0);
321
322 float advanceSoFar = initialAdvance;
323 for (unsigned i = 0; i < numGlyphs; ++i) {
324 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
325 uint16_t currentCharacterIndex = run->m_startIndex + runOffset +
326 glyphData.characterIndex;
327 bool isRunEnd = (i + 1 == numGlyphs);
328 bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) != c urrentCharacterIndex);
329
330 if ((m_direction == RTL && currentCharacterIndex >= to) || (m_direction != RTL && currentCharacterIndex < from)) {
331 advanceSoFar += glyphData.advance;
332 m_direction == RTL ? --clusterStart : ++clusterStart;
333 continue;
334 }
335
336 clusterAdvance += glyphData.advance;
337
338 if (textRun.is8Bit()) {
339 float glyphAdvanceX = glyphData.advance;
340 if (Character::canReceiveTextEmphasis(textRun[currentCharacterIndex] )) {
341 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceS oFar + glyphAdvanceX / 2);
342 }
343 advanceSoFar += glyphAdvanceX;
344 } else if (isClusterEnd) {
345 uint16_t clusterEnd;
346 if (m_direction == RTL)
347 clusterEnd = currentCharacterIndex;
348 else
349 clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCharacters : run->glyphToCharacterIndex(i + 1);
350
351 graphemesInCluster = countGraphemesInCluster(textRun.characters16(), textRun.charactersLength(), clusterStart, clusterEnd);
352 if (!graphemesInCluster || !clusterAdvance)
353 continue;
354
355 float glyphAdvanceX = clusterAdvance / graphemesInCluster;
356 for (unsigned j = 0; j < graphemesInCluster; ++j) {
357 // Do not put emphasis marks on space, separator, and control ch aracters.
358 if (Character::canReceiveTextEmphasis(textRun[currentCharacterIn dex]))
359 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, adva nceSoFar + glyphAdvanceX / 2);
360 advanceSoFar += glyphAdvanceX;
361 }
362 clusterStart = clusterEnd;
363 clusterAdvance = 0;
364 }
365 }
366
367 return advanceSoFar - initialAdvance;
368 }
369
370 FloatRect ShapeResult::selectionRect(const FloatPoint& point, int height,
371 unsigned from, unsigned to)
372 {
373 float currentX = 0;
374 float fromX = 0;
375 float toX = 0;
376 bool foundFromX = false;
377 bool foundToX = false;
378
379 if (m_direction == RTL)
380 currentX = m_width;
381 for (unsigned i = 0; i < m_runs.size(); i++) {
382 if (m_direction == RTL)
383 currentX -= m_runs[i]->m_width;
384 unsigned numCharacters = m_runs[i]->m_numCharacters;
385 if (!foundFromX && from < numCharacters) {
386 fromX = m_runs[i]->xPositionForOffset(from) + currentX;
387 foundFromX = true;
388 } else {
389 from -= numCharacters;
390 }
391
392 if (!foundToX && to < numCharacters) {
393 toX = m_runs[i]->xPositionForOffset(to) + currentX;
394 foundToX = true;
395 } else {
396 to -= numCharacters;
397 }
398
399 if (foundFromX && foundToX)
400 break;
401 if (m_direction != RTL)
402 currentX += m_runs[i]->m_width;
403 }
404
405 // The position in question might be just after the text.
406 if (!foundFromX)
407 fromX = 0;
408 if (!foundToX)
409 toX = m_direction == RTL ? 0 : m_width;
410 // None of our HarfBuzzRuns is part of the selection,
411 // possibly invalid from, to arguments.
412 if (!foundToX && !foundFromX)
413 fromX = toX = 0;
414
415 if (fromX < toX)
416 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
417 return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
418 }
419
420 int ShapeResult::offsetForPosition(float targetX)
421 {
422 int charactersSoFar = 0;
423 float currentX = 0;
424
425 if (m_direction == RTL) {
426 charactersSoFar = m_numCharacters;
427 for (unsigned i = 0; i < m_runs.size(); ++i) {
428 charactersSoFar -= m_runs[i]->m_numCharacters;
429 float nextX = currentX + m_runs[i]->m_width;
430 float offsetForRun = targetX - currentX;
431 if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
432 // The x value in question is within this script run.
433 const unsigned index = m_runs[i]->characterIndexForXPosition(off setForRun);
434 return charactersSoFar + index;
435 }
436 currentX = nextX;
437 }
438 } else {
439 for (unsigned i = 0; i < m_runs.size(); ++i) {
440 float nextX = currentX + m_runs[i]->m_width;
441 float offsetForRun = targetX - currentX;
442 if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
443 const unsigned index = m_runs[i]->characterIndexForXPosition(off setForRun);
444 return charactersSoFar + index;
445 }
446 charactersSoFar += m_runs[i]->m_numCharacters;
447 currentX = nextX;
448 }
449 }
450
451 return charactersSoFar;
452 }
453
454 unsigned ShapeResult::numberOfRunsForTesting() const
455 {
456 return m_runs.size();
457 }
458
459 bool ShapeResult::runInfoForTesting(unsigned runIndex, unsigned& startIndex,
460 unsigned& numGlyphs, hb_script_t& script)
461 {
462 if (runIndex < m_runs.size() && m_runs[runIndex]) {
463 startIndex = m_runs[runIndex]->m_startIndex;
464 numGlyphs = m_runs[runIndex]->m_numGlyphs;
465 script = m_runs[runIndex]->m_script;
466 return true;
467 }
468 return false;
469 }
470
471 uint16_t ShapeResult::glyphForTesting(unsigned runIndex, size_t glyphIndex)
472 {
473 return m_runs[runIndex]->m_glyphData[glyphIndex].glyph;
474 }
475
476 float ShapeResult::advanceForTesting(unsigned runIndex, size_t glyphIndex)
477 {
478 return m_runs[runIndex]->m_glyphData[glyphIndex].advance;
479 }
480
57 template<typename T> 481 template<typename T>
58 class HarfBuzzScopedPtr { 482 class HarfBuzzScopedPtr {
59 public: 483 public:
60 typedef void (*DestroyFunction)(T*); 484 typedef void (*DestroyFunction)(T*);
61 485
62 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy) 486 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
63 : m_ptr(ptr) 487 : m_ptr(ptr)
64 , m_destroy(destroy) 488 , m_destroy(destroy)
65 { 489 {
66 ASSERT(m_destroy); 490 ASSERT(m_destroy);
67 } 491 }
68 ~HarfBuzzScopedPtr() 492 ~HarfBuzzScopedPtr()
69 { 493 {
70 if (m_ptr) 494 if (m_ptr)
71 (*m_destroy)(m_ptr); 495 (*m_destroy)(m_ptr);
72 } 496 }
73 497
74 T* get() { return m_ptr; } 498 T* get() { return m_ptr; }
75 void set(T* ptr) { m_ptr = ptr; } 499 void set(T* ptr) { m_ptr = ptr; }
76 private: 500 private:
77 T* m_ptr; 501 T* m_ptr;
78 DestroyFunction m_destroy; 502 DestroyFunction m_destroy;
79 }; 503 };
80 504
81
82 static const unsigned cHarfBuzzCacheMaxSize = 256;
83
84 struct CachedShapingResultsLRUNode;
85 struct CachedShapingResults;
86 typedef std::map<std::wstring, CachedShapingResults*> CachedShapingResultsMap;
87 typedef std::list<CachedShapingResultsLRUNode*> CachedShapingResultsLRU;
88
89 struct CachedShapingResults {
90 CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_di rection_t runDir, const String& newLocale);
91 ~CachedShapingResults();
92
93 hb_buffer_t* buffer;
94 Font font;
95 hb_direction_t dir;
96 String locale;
97 CachedShapingResultsLRU::iterator lru;
98 };
99
100 struct CachedShapingResultsLRUNode {
101 CachedShapingResultsLRUNode(const CachedShapingResultsMap::iterator& cacheEn try);
102 ~CachedShapingResultsLRUNode();
103
104 CachedShapingResultsMap::iterator entry;
105 };
106
107 CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Fo nt* fontData, hb_direction_t dirData, const String& newLocale)
108 : buffer(harfBuzzBuffer)
109 , font(*fontData)
110 , dir(dirData)
111 , locale(newLocale)
112 {
113 }
114
115 CachedShapingResults::~CachedShapingResults()
116 {
117 hb_buffer_destroy(buffer);
118 }
119
120 CachedShapingResultsLRUNode::CachedShapingResultsLRUNode(const CachedShapingResu ltsMap::iterator& cacheEntry)
121 : entry(cacheEntry)
122 {
123 }
124
125 CachedShapingResultsLRUNode::~CachedShapingResultsLRUNode()
126 {
127 }
128
129 class HarfBuzzRunCache {
130 public:
131 HarfBuzzRunCache();
132 ~HarfBuzzRunCache();
133
134 CachedShapingResults* find(const std::wstring& key) const;
135 void remove(CachedShapingResults* node);
136 void moveToBack(CachedShapingResults* node);
137 bool insert(const std::wstring& key, CachedShapingResults* run);
138
139 private:
140 CachedShapingResultsMap m_harfBuzzRunMap;
141 CachedShapingResultsLRU m_harfBuzzRunLRU;
142 };
143
144
145 HarfBuzzRunCache::HarfBuzzRunCache()
146 {
147 }
148
149 HarfBuzzRunCache::~HarfBuzzRunCache()
150 {
151 for (CachedShapingResultsMap::iterator it = m_harfBuzzRunMap.begin(); it != m_harfBuzzRunMap.end(); ++it)
152 delete it->second;
153 for (CachedShapingResultsLRU::iterator it = m_harfBuzzRunLRU.begin(); it != m_harfBuzzRunLRU.end(); ++it)
154 delete *it;
155 }
156
157 bool HarfBuzzRunCache::insert(const std::wstring& key, CachedShapingResults* dat a)
158 {
159 std::pair<CachedShapingResultsMap::iterator, bool> results =
160 m_harfBuzzRunMap.insert(CachedShapingResultsMap::value_type(key, data));
161
162 if (!results.second)
163 return false;
164
165 CachedShapingResultsLRUNode* node = new CachedShapingResultsLRUNode(results. first);
166
167 m_harfBuzzRunLRU.push_back(node);
168 data->lru = --m_harfBuzzRunLRU.end();
169
170 if (m_harfBuzzRunMap.size() > cHarfBuzzCacheMaxSize) {
171 CachedShapingResultsLRUNode* lru = m_harfBuzzRunLRU.front();
172 CachedShapingResults* foo = lru->entry->second;
173 m_harfBuzzRunMap.erase(lru->entry);
174 m_harfBuzzRunLRU.pop_front();
175 delete foo;
176 delete lru;
177 }
178
179 return true;
180 }
181
182 inline CachedShapingResults* HarfBuzzRunCache::find(const std::wstring& key) con st
183 {
184 CachedShapingResultsMap::const_iterator it = m_harfBuzzRunMap.find(key);
185
186 return it != m_harfBuzzRunMap.end() ? it->second : 0;
187 }
188
189 inline void HarfBuzzRunCache::remove(CachedShapingResults* node)
190 {
191 CachedShapingResultsLRUNode* lruNode = *node->lru;
192
193 m_harfBuzzRunLRU.erase(node->lru);
194 m_harfBuzzRunMap.erase(lruNode->entry);
195 delete lruNode;
196 delete node;
197 }
198
199 inline void HarfBuzzRunCache::moveToBack(CachedShapingResults* node)
200 {
201 CachedShapingResultsLRUNode* lruNode = *node->lru;
202 m_harfBuzzRunLRU.erase(node->lru);
203 m_harfBuzzRunLRU.push_back(lruNode);
204 node->lru = --m_harfBuzzRunLRU.end();
205 }
206
207 HarfBuzzRunCache& harfBuzzRunCache()
208 {
209 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ());
210 return globalHarfBuzzRunCache;
211 }
212
213 static inline float harfBuzzPositionToFloat(hb_position_t value) 505 static inline float harfBuzzPositionToFloat(hb_position_t value)
214 { 506 {
215 return static_cast<float>(value) / (1 << 16); 507 return static_cast<float>(value) / (1 << 16);
216 } 508 }
217 509
218 static inline unsigned countGraphemesInCluster(const UChar* normalizedBuffer, un signed normalizedBufferLength, uint16_t startIndex, uint16_t endIndex)
219 {
220 if (startIndex > endIndex) {
221 uint16_t tempIndex = startIndex;
222 startIndex = endIndex;
223 endIndex = tempIndex;
224 }
225 uint16_t length = endIndex - startIndex;
226 ASSERT(static_cast<unsigned>(startIndex + length) <= normalizedBufferLength) ;
227 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&normalizedBuf fer[startIndex], length);
228
229 int cursorPos = cursorPosIterator->current();
230 int numGraphemes = -1;
231 while (0 <= cursorPos) {
232 cursorPos = cursorPosIterator->next();
233 numGraphemes++;
234 }
235 return numGraphemes < 0 ? 0 : numGraphemes;
236 }
237
238 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, hb_direction_t direction, hb_script _t script) 510 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, hb_direction_t direction, hb_script _t script)
239 : m_fontData(fontData) 511 : m_fontData(fontData)
240 , m_startIndex(startIndex) 512 , m_startIndex(startIndex)
241 , m_numCharacters(numCharacters) 513 , m_numCharacters(numCharacters)
242 , m_numGlyphs(0) 514 , m_numGlyphs(0)
243 , m_direction(direction) 515 , m_direction(direction)
244 , m_script(script) 516 , m_script(script)
245 , m_width(0)
246 { 517 {
247 } 518 }
248 519
249 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const HarfBuzzRun& rhs) 520 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const HarfBuzzRun& rhs)
250 : m_fontData(rhs.m_fontData) 521 : m_fontData(rhs.m_fontData)
251 , m_startIndex(rhs.m_startIndex) 522 , m_startIndex(rhs.m_startIndex)
252 , m_numCharacters(rhs.m_numCharacters) 523 , m_numCharacters(rhs.m_numCharacters)
253 , m_numGlyphs(rhs.m_numGlyphs) 524 , m_numGlyphs(rhs.m_numGlyphs)
254 , m_direction(rhs.m_direction) 525 , m_direction(rhs.m_direction)
255 , m_script(rhs.m_script) 526 , m_script(rhs.m_script)
256 , m_glyphData(rhs.m_glyphData)
257 , m_width(rhs.m_width)
258 { 527 {
259 } 528 }
260 529
261 HarfBuzzShaper::HarfBuzzRun::~HarfBuzzRun() 530 HarfBuzzShaper::HarfBuzzRun::~HarfBuzzRun()
262 { 531 {
263 } 532 }
264 533
265 inline void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfBuzzB uffer)
266 {
267 m_numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
268 m_glyphData.resize(m_numGlyphs);
269 }
270
271 inline void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, ui nt16_t glyphId, float advance, float offsetX, float offsetY)
272 {
273 HarfBuzzRunGlyphData& data = glyphData(index);
274 data.glyph = glyphId;
275 data.advance = advance;
276 data.offset = FloatSize(offsetX, offsetY);
277 }
278
279 void HarfBuzzShaper::HarfBuzzRun::addAdvance(unsigned index, float advance)
280 {
281 glyphData(index).advance += advance;
282 }
283
284 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
285 {
286 ASSERT(targetX <= m_width);
287 float currentX = 0;
288 float currentAdvance = m_glyphData[0].advance;
289 unsigned glyphIndex = 0;
290
291 // Sum up advances that belong to a character.
292 while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].characterInde x == m_glyphData[glyphIndex + 1].characterIndex)
293 currentAdvance += m_glyphData[++glyphIndex].advance;
294 currentAdvance = currentAdvance / 2.0;
295 if (targetX <= currentAdvance)
296 return rtl() ? m_numCharacters : 0;
297
298 currentX = currentAdvance;
299 ++glyphIndex;
300 while (glyphIndex < m_numGlyphs) {
301 unsigned prevCharacterIndex = m_glyphData[glyphIndex - 1].characterIndex ;
302 float prevAdvance = currentAdvance;
303 currentAdvance = m_glyphData[glyphIndex].advance;
304 while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].character Index == m_glyphData[glyphIndex + 1].characterIndex)
305 currentAdvance += m_glyphData[++glyphIndex].advance;
306 currentAdvance = currentAdvance / 2.0;
307 float nextX = currentX + prevAdvance + currentAdvance;
308 if (currentX <= targetX && targetX <= nextX)
309 return rtl() ? prevCharacterIndex : m_glyphData[glyphIndex].characte rIndex;
310 currentX = nextX;
311 ++glyphIndex;
312 }
313
314 return rtl() ? 0 : m_numCharacters;
315 }
316
317 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
318 {
319 ASSERT(offset < m_numCharacters);
320 unsigned glyphIndex = 0;
321 float position = 0;
322 if (rtl()) {
323 while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterInde x > offset) {
324 position += m_glyphData[glyphIndex].advance;
325 ++glyphIndex;
326 }
327 // For RTL, we need to return the right side boundary of the character.
328 // Add advance of glyphs which are part of the character.
329 while (glyphIndex < m_numGlyphs - 1 && m_glyphData[glyphIndex].character Index == m_glyphData[glyphIndex + 1].characterIndex) {
330 position += m_glyphData[glyphIndex].advance;
331 ++glyphIndex;
332 }
333 position += m_glyphData[glyphIndex].advance;
334 } else {
335 while (glyphIndex < m_numGlyphs && m_glyphData[glyphIndex].characterInde x < offset) {
336 position += m_glyphData[glyphIndex].advance;
337 ++glyphIndex;
338 }
339 }
340 return position;
341 }
342
343 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest ination, unsigned* destinationLength) 534 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest ination, unsigned* destinationLength)
344 { 535 {
345 unsigned position = 0; 536 unsigned position = 0;
346 bool error = false; 537 bool error = false;
347 const UChar* source; 538 const UChar* source;
348 String stringFor8BitRun; 539 String stringFor8BitRun;
349 if (run.is8Bit()) { 540 if (run.is8Bit()) {
350 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length()); 541 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length());
351 source = stringFor8BitRun.characters16(); 542 source = stringFor8BitRun.characters16();
352 } else { 543 } else {
(...skipping 10 matching lines...) Expand all
363 else if (Character::treatAsSpace(character) && character != tabulationCh aracter) 554 else if (Character::treatAsSpace(character) && character != tabulationCh aracter)
364 character = spaceCharacter; 555 character = spaceCharacter;
365 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) 556 else if (Character::treatAsZeroWidthSpaceInComplexScript(character))
366 character = zeroWidthSpaceCharacter; 557 character = zeroWidthSpaceCharacter;
367 558
368 U16_APPEND(destination, *destinationLength, length, character, error); 559 U16_APPEND(destination, *destinationLength, length, character, error);
369 ASSERT_UNUSED(error, !error); 560 ASSERT_UNUSED(error, !error);
370 } 561 }
371 } 562 }
372 563
373 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, const Glyph Data* emphasisData, 564 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run,
374 HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* bounds) 565 HashSet<const SimpleFontData*>* fallbackFonts)
375 : Shaper(font, run, emphasisData, fallbackFonts, bounds) 566 : Shaper(font, run, nullptr, fallbackFonts)
376 , m_normalizedBufferLength(0) 567 , m_normalizedBufferLength(0)
377 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) 568 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing())
378 , m_letterSpacing(font->fontDescription().letterSpacing()) 569 , m_letterSpacing(font->fontDescription().letterSpacing())
379 , m_expansionOpportunityCount(0) 570 , m_expansionOpportunityCount(0)
380 , m_fromIndex(0)
381 , m_toIndex(m_textRun.length())
382 , m_totalWidth(0)
383 { 571 {
384 m_normalizedBuffer = adoptArrayPtr(new UChar[m_textRun.length() + 1]); 572 m_normalizedBuffer = adoptArrayPtr(new UChar[m_textRun.length() + 1]);
385 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength); 573 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength);
386 setExpansion(m_textRun.expansion()); 574 setExpansion(m_textRun.expansion());
387 setFontFeatures(); 575 setFontFeatures();
388 } 576 }
389 577
390 float HarfBuzzShaper::nextExpansionPerOpportunity() 578 float HarfBuzzShaper::nextExpansionPerOpportunity()
391 { 579 {
392 if (!m_expansionOpportunityCount) { 580 if (!m_expansionOpportunityCount) {
(...skipping 25 matching lines...) Expand all
418 ASSERT(m_expansionOpportunityCount > 0); 606 ASSERT(m_expansionOpportunityCount > 0);
419 --m_expansionOpportunityCount; 607 --m_expansionOpportunityCount;
420 } 608 }
421 609
422 if (m_expansionOpportunityCount) 610 if (m_expansionOpportunityCount)
423 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; 611 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount;
424 else 612 else
425 m_expansionPerOpportunity = 0; 613 m_expansionPerOpportunity = 0;
426 } 614 }
427 615
428
429 void HarfBuzzShaper::setDrawRange(int from, int to)
430 {
431 ASSERT_WITH_SECURITY_IMPLICATION(from >= 0);
432 ASSERT_WITH_SECURITY_IMPLICATION(to <= m_textRun.length());
433 m_fromIndex = from;
434 m_toIndex = to;
435 }
436
437 void HarfBuzzShaper::setFontFeatures() 616 void HarfBuzzShaper::setFontFeatures()
438 { 617 {
439 const FontDescription& description = m_font->fontDescription(); 618 const FontDescription& description = m_font->fontDescription();
440 619
441 static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) }; 620 static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) };
442 static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) }; 621 static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) };
443 switch (description.kerning()) { 622 switch (description.kerning()) {
444 case FontDescription::NormalKerning: 623 case FontDescription::NormalKerning:
445 // kern/vkrn are enabled by default 624 // kern/vkrn are enabled by default
446 break; 625 break;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 hb_feature_t feature; 703 hb_feature_t feature;
525 const AtomicString& tag = settings->at(i).tag(); 704 const AtomicString& tag = settings->at(i).tag();
526 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); 705 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
527 feature.value = settings->at(i).value(); 706 feature.value = settings->at(i).value();
528 feature.start = 0; 707 feature.start = 0;
529 feature.end = static_cast<unsigned>(-1); 708 feature.end = static_cast<unsigned>(-1);
530 m_features.append(feature); 709 m_features.append(feature);
531 } 710 }
532 } 711 }
533 712
534 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) 713 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult()
535 { 714 {
536 if (!createHarfBuzzRuns()) 715 if (!createHarfBuzzRuns())
537 return false; 716 return nullptr;
538 717
539 if (!shapeHarfBuzzRuns()) 718 ShapeResult* result = new ShapeResult();
540 return false; 719 result->m_numCharacters = m_normalizedBufferLength;
720 result->m_direction = m_textRun.direction();
721 if (!shapeHarfBuzzRuns(result)) {
722 delete result;
723 return nullptr;
724 }
541 725
542 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer)) 726 return adoptRef(result);
543 return false;
544
545 return true;
546 } 727 }
547 728
548 struct CandidateRun { 729 struct CandidateRun {
549 UChar32 character; 730 UChar32 character;
550 unsigned start; 731 unsigned start;
551 unsigned end; 732 unsigned end;
552 const SimpleFontData* fontData; 733 const SimpleFontData* fontData;
553 UScriptCode script; 734 UScriptCode script;
554 }; 735 };
555 736
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 ASSERT(endCharacter > startCharacter); 940 ASSERT(endCharacter > startCharacter);
760 ASSERT(script != USCRIPT_INVALID_CODE); 941 ASSERT(script != USCRIPT_INVALID_CODE);
761 if (m_fallbackFonts) 942 if (m_fallbackFonts)
762 trackNonPrimaryFallbackFont(fontData); 943 trackNonPrimaryFallbackFont(fontData);
763 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, 944 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData,
764 startCharacter, endCharacter - startCharacter, 945 startCharacter, endCharacter - startCharacter,
765 TextDirectionToHBDirection(m_textRun.direction(), m_font->fontDescriptio n().orientation(), fontData), 946 TextDirectionToHBDirection(m_textRun.direction(), m_font->fontDescriptio n().orientation(), fontData),
766 ICUScriptToHBScript(script))); 947 ICUScriptToHBScript(script)));
767 } 948 }
768 949
769 static inline bool isValidCachedResult(const Font* font, hb_direction_t dir,
770 const String& localeString, const CachedShapingResults* cachedResults)
771 {
772 ASSERT(cachedResults);
773 return cachedResults->dir == dir
774 && cachedResults->font == *font
775 && !cachedResults->font.loadingCustomFonts()
776 && !font->loadingCustomFonts()
777 && cachedResults->locale == localeString;
778 }
779
780 static const uint16_t* toUint16(const UChar* src) 950 static const uint16_t* toUint16(const UChar* src)
781 { 951 {
782 // FIXME: This relies on undefined behavior however it works on the 952 // FIXME: This relies on undefined behavior however it works on the
783 // current versions of all compilers we care about and avoids making 953 // current versions of all compilers we care about and avoids making
784 // a copy of the string. 954 // a copy of the string.
785 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t"); 955 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t");
786 return reinterpret_cast<const uint16_t*>(src); 956 return reinterpret_cast<const uint16_t*>(src);
787 } 957 }
788 958
789 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, 959 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer,
790 const FontDescription& fontDescription, const UChar* normalizedBuffer, 960 const FontDescription& fontDescription, const UChar* normalizedBuffer,
791 unsigned startIndex, unsigned numCharacters) 961 unsigned startIndex, unsigned numCharacters)
792 { 962 {
793 if (fontDescription.variant() == FontVariantSmallCaps 963 if (fontDescription.variant() == FontVariantSmallCaps
794 && u_islower(normalizedBuffer[startIndex])) { 964 && u_islower(normalizedBuffer[startIndex])) {
795 String upperText = String(normalizedBuffer + startIndex, numCharacters) 965 String upperText = String(normalizedBuffer + startIndex, numCharacters)
796 .upper(); 966 .upper();
797 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call 967 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call
798 // makeUpper(). 968 // makeUpper().
799 ASSERT(!upperText.is8Bit()); 969 ASSERT(!upperText.is8Bit());
800 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), 970 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()),
801 numCharacters, 0, numCharacters); 971 numCharacters, 0, numCharacters);
802 } else { 972 } else {
803 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex), 973 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex),
804 numCharacters, 0, numCharacters); 974 numCharacters, 0, numCharacters);
805 } 975 }
806 } 976 }
807 977
808 bool HarfBuzzShaper::shapeHarfBuzzRuns() 978 bool HarfBuzzShaper::shapeHarfBuzzRuns(ShapeResult* result)
809 { 979 {
810 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy); 980 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy);
811 981
812 HarfBuzzRunCache& runCache = harfBuzzRunCache();
813 const FontDescription& fontDescription = m_font->fontDescription(); 982 const FontDescription& fontDescription = m_font->fontDescription();
814 const String& localeString = fontDescription.locale(); 983 const String& localeString = fontDescription.locale();
815 CString locale = localeString.latin1(); 984 CString locale = localeString.latin1();
816 const hb_language_t language = hb_language_from_string(locale.data(), locale .length()); 985 const hb_language_t language = hb_language_from_string(locale.data(), locale .length());
817 986
987 result->m_runs.resize(m_harfBuzzRuns.size());
818 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 988 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
819 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; 989 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
820 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 990 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
821 991
822 const SimpleFontData* currentFontData = currentRun->fontData(); 992 const SimpleFontData* currentFontData = currentRun->fontData();
823 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData()); 993 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData());
824 HarfBuzzFace* face = platformData->harfBuzzFace(); 994 HarfBuzzFace* face = platformData->harfBuzzFace();
825 if (!face) 995 if (!face)
826 return false; 996 return false;
827 997
828 hb_buffer_set_language(harfBuzzBuffer.get(), language); 998 hb_buffer_set_language(harfBuzzBuffer.get(), language);
829 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); 999 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
830 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction()); 1000 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction());
831 1001
832 const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex();
833 std::wstring key(src, src + currentRun->numCharacters());
834
835 CachedShapingResults* cachedResults = runCache.find(key);
836 if (cachedResults) {
837 if (isValidCachedResult(m_font, currentRun->direction(),
838 localeString, cachedResults)) {
839 currentRun->applyShapeResult(cachedResults->buffer);
840 setGlyphPositionsForHarfBuzzRun(currentRun,
841 cachedResults->buffer);
842 hb_buffer_clear_contents(harfBuzzBuffer.get());
843 runCache.moveToBack(cachedResults);
844 continue;
845 }
846 runCache.remove(cachedResults);
847 }
848
849 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle 1002 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle
850 // for combining marks at the beginning of runs. 1003 // for combining marks at the beginning of runs.
851 static const uint16_t preContext = spaceCharacter; 1004 static const uint16_t preContext = spaceCharacter;
852 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); 1005 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
853 1006
854 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), 1007 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(),
855 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(), 1008 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(),
856 currentRun->numCharacters()); 1009 currentRun->numCharacters());
857 1010
858 if (fontDescription.isVerticalAnyUpright()) 1011 if (fontDescription.isVerticalAnyUpright())
859 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); 1012 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
860 1013
861 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy); 1014 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy);
1015 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
1016 shapeResult(result, i, currentRun, harfBuzzBuffer.get());
862 1017
863 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); 1018 hb_buffer_reset(harfBuzzBuffer.get());
864 currentRun->applyShapeResult(harfBuzzBuffer.get());
865 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
866
867 runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_fo nt, currentRun->direction(), localeString));
868
869 harfBuzzBuffer.set(hb_buffer_create());
870 } 1019 }
871 1020
872 // We should have consumed all expansion opportunities. 1021 // We should have consumed all expansion opportunities.
873 // Failures here means that our logic does not match to the one in expansion OpportunityCount(). 1022 // Failures here means that our logic does not match to the one in expansion OpportunityCount().
874 // FIXME: Ideally, we should ASSERT(!m_expansionOpportunityCount) here to en sure that, 1023 // FIXME: Ideally, we should ASSERT(!m_expansionOpportunityCount) here to en sure that,
875 // or unify the two logics (and the one in SimplePath too,) but there are so me cases where our impl 1024 // or unify the two logics (and the one in SimplePath too,) but there are so me cases where our impl
876 // does not support justification very well yet such as U+3099, and it'll ca use the ASSERT to fail. 1025 // does not support justification very well yet such as U+3099, and it'll ca use the ASSERT to fail.
877 // It's to be fixed because they're very rarely used, and a broken justifica tion is still somewhat readable. 1026 // It's to be fixed because they're very rarely used, and a broken justifica tion is still somewhat readable.
878 1027
879 return true; 1028 return true;
880 } 1029 }
881 1030
882 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb _buffer_t* harfBuzzBuffer) 1031 void HarfBuzzShaper::shapeResult(ShapeResult* result, unsigned index,
1032 HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer)
883 { 1033 {
884 // Skip runs that only contain control characters. 1034 unsigned numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
885 if (!currentRun->numGlyphs()) 1035 if (!numGlyphs) {
1036 result->m_runs[index] = nullptr;
886 return; 1037 return;
1038 }
1039
1040 currentRun->setNumGlyphs(numGlyphs);
1041 ShapeResult::RunInfo* run = new ShapeResult::RunInfo(currentRun->fontData(),
1042 currentRun->direction(), currentRun->script(), currentRun->startIndex(),
1043 numGlyphs, currentRun->numCharacters());
1044 result->m_runs[index] = run;
1045 result->m_numGlyphs += numGlyphs;
887 1046
888 const SimpleFontData* currentFontData = currentRun->fontData(); 1047 const SimpleFontData* currentFontData = currentRun->fontData();
889 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); 1048 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
890 hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzz Buffer, 0); 1049 hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzz Buffer, 0);
891 1050
892 unsigned numGlyphs = currentRun->numGlyphs();
893 float totalAdvance = 0; 1051 float totalAdvance = 0;
894 FloatPoint glyphOrigin; 1052 FloatPoint glyphOrigin;
895 float offsetX, offsetY; 1053 float offsetX, offsetY;
896 float* directionOffset = m_font->fontDescription().isVerticalAnyUpright() ? &offsetY : &offsetX; 1054 float* directionOffset = m_font->fontDescription().isVerticalAnyUpright() ? &offsetY : &offsetX;
897 1055
898 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. 1056 // HarfBuzz returns result in visual order, no need to flip for RTL.
899 for (size_t i = 0; i < numGlyphs; ++i) { 1057 for (size_t i = 0; i < numGlyphs; ++i) {
900 bool runEnd = i + 1 == numGlyphs; 1058 bool runEnd = i + 1 == numGlyphs;
901 uint16_t glyph = glyphInfos[i].codepoint; 1059 uint16_t glyph = glyphInfos[i].codepoint;
902 offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); 1060 offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
903 offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); 1061 offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
1062
904 // One out of x_advance and y_advance is zero, depending on 1063 // One out of x_advance and y_advance is zero, depending on
905 // whether the buffer direction is horizontal or vertical. 1064 // whether the buffer direction is horizontal or vertical.
906 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance); 1065 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance);
907
908 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster; 1066 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster;
909 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); 1067 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex);
910 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster; 1068 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster;
911 float spacing = 0; 1069 float spacing = 0;
912 1070
913 currentRun->glyphData(i).characterIndex = glyphInfos[i].cluster; 1071 run->m_glyphData[i].characterIndex = glyphInfos[i].cluster;
914 1072
915 if (isClusterEnd) 1073 if (isClusterEnd)
916 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, *dire ctionOffset, totalAdvance); 1074 spacing += adjustSpacing(run, i, currentCharacterIndex, *directionOf fset, totalAdvance);
917 1075
918 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { 1076 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
919 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); 1077 run->setGlyphAndPositions(i, glyph, 0, 0, 0);
920 continue; 1078 continue;
921 } 1079 }
922 1080
923 advance += spacing; 1081 advance += spacing;
924 if (m_textRun.rtl()) { 1082 if (m_textRun.rtl()) {
925 // In RTL, spacing should be added to left side of glyphs. 1083 // In RTL, spacing should be added to left side of glyphs.
926 *directionOffset += spacing; 1084 *directionOffset += spacing;
927 if (!isClusterEnd) 1085 if (!isClusterEnd)
928 *directionOffset += m_letterSpacing; 1086 *directionOffset += m_letterSpacing;
929 } 1087 }
930 1088
931 currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); 1089 run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
1090 totalAdvance += advance;
932 1091
933 if (m_glyphBoundingBox) { 1092 FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph);
934 FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); 1093 glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
935 glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); 1094 result->m_glyphBoundingBox.unite(glyphBounds);
936 m_glyphBoundingBox->unite(glyphBounds); 1095 glyphOrigin += FloatSize(advance + offsetX, offsetY);
937 glyphOrigin += FloatSize(advance + offsetX, offsetY); 1096 }
938 }
939 1097
940 totalAdvance += advance; 1098 run->m_width = totalAdvance > 0.0 ? totalAdvance : 0.0;
941 } 1099 result->m_width += run->m_width;
942 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
943 m_totalWidth += currentRun->width();
944 } 1100 }
945 1101
946 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex, unsigned currentCharacterIndex, float& offset, float& totalAdvance) 1102 float HarfBuzzShaper::adjustSpacing(ShapeResult::RunInfo* run, size_t glyphIndex , unsigned currentCharacterIndex, float& offset, float& totalAdvance)
947 { 1103 {
948 float spacing = 0; 1104 float spacing = 0;
949 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; 1105 UChar32 character = m_normalizedBuffer[currentCharacterIndex];
950 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) 1106 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character))
951 spacing += m_letterSpacing; 1107 spacing += m_letterSpacing;
952 1108
953 bool treatAsSpace = Character::treatAsSpace(character); 1109 bool treatAsSpace = Character::treatAsSpace(character);
954 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu n.allowTabs())) 1110 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu n.allowTabs()))
955 spacing += m_wordSpacingAdjustment; 1111 spacing += m_wordSpacingAdjustment;
956 1112
(...skipping 18 matching lines...) Expand all
975 if (!Character::isCJKIdeographOrSymbol(character)) { 1131 if (!Character::isCJKIdeographOrSymbol(character)) {
976 m_isAfterExpansion = false; 1132 m_isAfterExpansion = false;
977 return spacing; 1133 return spacing;
978 } 1134 }
979 1135
980 if (!m_isAfterExpansion) { 1136 if (!m_isAfterExpansion) {
981 // Take the expansion opportunity before this ideograph. 1137 // Take the expansion opportunity before this ideograph.
982 float expandBefore = nextExpansionPerOpportunity(); 1138 float expandBefore = nextExpansionPerOpportunity();
983 if (expandBefore) { 1139 if (expandBefore) {
984 if (glyphIndex > 0) { 1140 if (glyphIndex > 0) {
985 currentRun->addAdvance(glyphIndex - 1, expandBefore); 1141 run->addAdvance(glyphIndex - 1, expandBefore);
986 totalAdvance += expandBefore; 1142 totalAdvance += expandBefore;
987 } else { 1143 } else {
988 offset += expandBefore; 1144 offset += expandBefore;
989 spacing += expandBefore; 1145 spacing += expandBefore;
990 } 1146 }
991 } 1147 }
992 if (!m_expansionOpportunityCount) 1148 if (!m_expansionOpportunityCount)
993 return spacing; 1149 return spacing;
994 } 1150 }
995 1151
996 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere d by !m_expansionOpportunityCount above 1152 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere d by !m_expansionOpportunityCount above
997 spacing += nextExpansionPerOpportunity(); 1153 spacing += nextExpansionPerOpportunity();
998 m_isAfterExpansion = true; 1154 m_isAfterExpansion = true;
999 return spacing; 1155 return spacing;
1000 } 1156 }
1001 1157
1002 float HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer,
1003 HarfBuzzRun* currentRun, float initialAdvance)
1004 {
1005 unsigned numGlyphs = currentRun->numGlyphs();
1006 float advanceSoFar = initialAdvance;
1007 if (m_textRun.rtl()) {
1008 for (unsigned i = 0; i < numGlyphs; ++i) {
1009 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i);
1010 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphDat a.characterIndex;
1011 if (currentCharacterIndex >= m_toIndex) {
1012 advanceSoFar += glyphData.advance;
1013 } else if (currentCharacterIndex >= m_fromIndex) {
1014 FloatPoint runStartOffset = HB_DIRECTION_IS_HORIZONTAL(currentRu n->direction()) ?
1015 FloatPoint(advanceSoFar, 0) : FloatPoint(0, advanceSoFar);
1016 glyphBuffer->add(glyphData.glyph, currentRun->fontData(), runSta rtOffset + glyphData.offset);
1017 advanceSoFar += glyphData.advance;
1018 }
1019 }
1020 } else {
1021 for (unsigned i = 0; i < numGlyphs; ++i) {
1022 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i);
1023 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphDat a.characterIndex;
1024 if (currentCharacterIndex < m_fromIndex) {
1025 advanceSoFar += glyphData.advance;
1026 } else if (currentCharacterIndex < m_toIndex) {
1027 FloatPoint runStartOffset = HB_DIRECTION_IS_HORIZONTAL(currentRu n->direction()) ?
1028 FloatPoint(advanceSoFar, 0) : FloatPoint(0, advanceSoFar);
1029 glyphBuffer->add(glyphData.glyph, currentRun->fontData(), runSta rtOffset + glyphData.offset);
1030 advanceSoFar += glyphData.advance;
1031 }
1032 }
1033 }
1034
1035 return advanceSoFar - initialAdvance;
1036 }
1037
1038 float HarfBuzzShaper::fillGlyphBufferForTextEmphasis(GlyphBuffer* glyphBuffer, H arfBuzzRun* currentRun, float initialAdvance)
1039 {
1040 unsigned numGlyphs = currentRun->numGlyphs();
1041 unsigned graphemesInCluster = 1;
1042 float clusterAdvance = 0;
1043 uint16_t clusterStart;
1044
1045 // A "cluster" in this context means a cluster as it is used by HarfBuzz:
1046 // The minimal group of characters and corresponding glyphs, that cannot be broken
1047 // down further from a text shaping point of view.
1048 // A cluster can contain multiple glyphs and grapheme clusters, with mutuall y
1049 // overlapping boundaries. Below we count grapheme clusters per HarfBuzz clu sters,
1050 // then linearly split the sum of corresponding glyph advances by the number of
1051 // grapheme clusters in order to find positions for emphasis mark drawing.
1052
1053 if (m_textRun.rtl())
1054 clusterStart = currentRun->startIndex() + currentRun->numCharacters();
1055 else
1056 clusterStart = currentRun->glyphToCharacterIndex(0);
1057
1058 float advanceSoFar = initialAdvance;
1059 for (unsigned i = 0; i < numGlyphs; ++i) {
1060 HarfBuzzRunGlyphData& glyphData = currentRun->glyphData(i);
1061 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphData.ch aracterIndex;
1062 bool isRunEnd = (i + 1 == numGlyphs);
1063 bool isClusterEnd = isRunEnd || (currentRun->glyphToCharacterIndex(i + 1) != currentCharacterIndex);
1064
1065 if ((m_textRun.rtl() && currentCharacterIndex >= m_toIndex) || (!m_textR un.rtl() && currentCharacterIndex < m_fromIndex)) {
1066 advanceSoFar += glyphData.advance;
1067 m_textRun.rtl() ? --clusterStart : ++clusterStart;
1068 continue;
1069 }
1070
1071 clusterAdvance += glyphData.advance;
1072
1073 if (isClusterEnd) {
1074 uint16_t clusterEnd;
1075 if (m_textRun.rtl())
1076 clusterEnd = currentCharacterIndex;
1077 else
1078 clusterEnd = isRunEnd ? currentRun->startIndex() + currentRun->n umCharacters() : currentRun->glyphToCharacterIndex(i + 1);
1079
1080 graphemesInCluster = countGraphemesInCluster(m_normalizedBuffer.get( ), m_normalizedBufferLength, clusterStart, clusterEnd);
1081 if (!graphemesInCluster || !clusterAdvance)
1082 continue;
1083
1084 float glyphAdvanceX = clusterAdvance / graphemesInCluster;
1085 for (unsigned j = 0; j < graphemesInCluster; ++j) {
1086 // Do not put emphasis marks on space, separator, and control ch aracters.
1087 if (Character::canReceiveTextEmphasis(m_textRun[currentCharacter Index]))
1088 addEmphasisMark(glyphBuffer, advanceSoFar + glyphAdvanceX / 2);
1089
1090 advanceSoFar += glyphAdvanceX;
1091 }
1092 clusterStart = clusterEnd;
1093 clusterAdvance = 0;
1094 }
1095 }
1096
1097 return advanceSoFar - initialAdvance;
1098 }
1099
1100 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
1101 {
1102 ASSERT(glyphBuffer);
1103
1104 unsigned numRuns = m_harfBuzzRuns.size();
1105 float advanceSoFar = 0;
1106 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
1107 HarfBuzzRun* currentRun = m_harfBuzzRuns[m_textRun.ltr() ? runIndex : nu mRuns - runIndex - 1].get();
1108 // Skip runs that only contain control characters.
1109 if (!currentRun->numGlyphs())
1110 continue;
1111 advanceSoFar += forTextEmphasis()
1112 ? fillGlyphBufferForTextEmphasis(glyphBuffer, currentRun, advanceSoF ar)
1113 : fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, advanceSoF ar);
1114 }
1115 return glyphBuffer->size();
1116 }
1117
1118 int HarfBuzzShaper::offsetForPosition(float targetX)
1119 {
1120 int charactersSoFar = 0;
1121 float currentX = 0;
1122
1123 if (m_textRun.rtl()) {
1124 charactersSoFar = m_normalizedBufferLength;
1125 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
1126 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
1127 float nextX = currentX + m_harfBuzzRuns[i]->width();
1128 float offsetForRun = targetX - currentX;
1129 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
1130 // The x value in question is within this script run.
1131 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun);
1132 return charactersSoFar + index;
1133 }
1134 currentX = nextX;
1135 }
1136 } else {
1137 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
1138 float nextX = currentX + m_harfBuzzRuns[i]->width();
1139 float offsetForRun = targetX - currentX;
1140 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
1141 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun);
1142 return charactersSoFar + index;
1143 }
1144 charactersSoFar += m_harfBuzzRuns[i]->numCharacters();
1145 currentX = nextX;
1146 }
1147 }
1148
1149 return charactersSoFar;
1150 }
1151
1152 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
1153 {
1154 float currentX = 0;
1155 float fromX = 0;
1156 float toX = 0;
1157 bool foundFromX = false;
1158 bool foundToX = false;
1159
1160 if (m_textRun.rtl())
1161 currentX = m_totalWidth;
1162 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
1163 if (m_textRun.rtl())
1164 currentX -= m_harfBuzzRuns[i]->width();
1165 int numCharacters = m_harfBuzzRuns[i]->numCharacters();
1166 if (!foundFromX && from >= 0 && from < numCharacters) {
1167 fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX;
1168 foundFromX = true;
1169 } else {
1170 from -= numCharacters;
1171 }
1172
1173 if (!foundToX && to >= 0 && to < numCharacters) {
1174 toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX;
1175 foundToX = true;
1176 } else {
1177 to -= numCharacters;
1178 }
1179
1180 if (foundFromX && foundToX)
1181 break;
1182 if (!m_textRun.rtl())
1183 currentX += m_harfBuzzRuns[i]->width();
1184 }
1185
1186 // The position in question might be just after the text.
1187 if (!foundFromX)
1188 fromX = 0;
1189 if (!foundToX)
1190 toX = m_textRun.rtl() ? 0 : m_totalWidth;
1191 // None of our HarfBuzzRuns is part of the selection,
1192 // possibly invalid from, to arguments.
1193 if (!foundToX && !foundFromX)
1194 fromX = toX = 0;
1195
1196 if (fromX < toX)
1197 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
1198 return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
1199 }
1200
1201 } // namespace blink 1158 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698