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

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: Remove TypesettingFeatures check 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 {
drott 2015/06/30 15:07:56 One more comment perhaps - can we move ShapeResult
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 static inline void addGlyphToBuffer(GlyphBuffer* glyphBuffer, float advance,
201 hb_direction_t direction, const SimpleFontData* fontData,
202 const HarfBuzzRunGlyphData& glyphData)
203 {
204 FloatPoint startOffset = HB_DIRECTION_IS_HORIZONTAL(direction)
205 ? FloatPoint(advance, 0)
206 : FloatPoint(0, advance);
207 glyphBuffer->add(glyphData.glyph, fontData, startOffset + glyphData.offset);
208 }
209
210 template<TextDirection direction>
211 float ShapeResult::fillGlyphBufferForRun(GlyphBuffer* glyphBuffer,
212 const RunInfo* run, float initialAdvance, unsigned from, unsigned to,
213 unsigned runOffset)
214 {
215 float advanceSoFar = initialAdvance;
216 unsigned numGlyphs = run->m_numGlyphs;
217 for (unsigned i = 0; i < numGlyphs; ++i) {
218 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
219 uint16_t currentCharacterIndex = run->m_startIndex +
220 glyphData.characterIndex + runOffset;
221 if ((direction == RTL && currentCharacterIndex >= to)
222 || (direction == LTR && currentCharacterIndex < from)) {
223 advanceSoFar += glyphData.advance;
224 } else if ((direction == RTL && currentCharacterIndex >= from)
225 || (direction == LTR && currentCharacterIndex < to)) {
226 addGlyphToBuffer(glyphBuffer, advanceSoFar, run->m_direction,
227 run->m_fontData, glyphData);
228 advanceSoFar += glyphData.advance;
229 }
230 }
231
232 return advanceSoFar - initialAdvance;
233 }
234
235 static inline unsigned countGraphemesInCluster(const UChar* str,
236 unsigned strLength, uint16_t startIndex, uint16_t endIndex)
237 {
238 if (startIndex > endIndex) {
239 uint16_t tempIndex = startIndex;
240 startIndex = endIndex;
241 endIndex = tempIndex;
242 }
243 uint16_t length = endIndex - startIndex;
244 ASSERT(static_cast<unsigned>(startIndex + length) <= strLength);
245 TextBreakIterator* cursorPosIterator = cursorMovementIterator(&str[startInde x], length);
246
247 int cursorPos = cursorPosIterator->current();
248 int numGraphemes = -1;
249 while (0 <= cursorPos) {
250 cursorPos = cursorPosIterator->next();
251 numGraphemes++;
252 }
253 return numGraphemes < 0 ? 0 : numGraphemes;
254 }
255
256 static inline void addEmphasisMark(GlyphBuffer* buffer,
257 const GlyphData* emphasisData, FloatPoint glyphCenter,
258 float midGlyphOffset)
259 {
260 ASSERT(buffer);
261 ASSERT(emphasisData);
262
263 const SimpleFontData* emphasisFontData = emphasisData->fontData;
264 ASSERT(emphasisFontData);
265
266 bool isVertical = emphasisFontData->platformData().isVerticalAnyUpright()
267 && emphasisFontData->verticalData();
268
269 if (!isVertical) {
270 buffer->add(emphasisData->glyph, emphasisFontData,
271 midGlyphOffset - glyphCenter.x());
272 } else {
273 buffer->add(emphasisData->glyph, emphasisFontData,
274 FloatPoint(-glyphCenter.x(), midGlyphOffset - glyphCenter.y()));
275 }
276 }
277
278 float ShapeResult::fillGlyphBuffer(Vector<RefPtr<ShapeResult>>& results,
279 GlyphBuffer* glyphBuffer, const TextRun& textRun,
280 unsigned from, unsigned to)
281 {
282 float advance = 0;
283 if (textRun.rtl()) {
284 unsigned wordOffset = textRun.length();
285 for (unsigned j = 0; j < results.size(); j++) {
286 unsigned resolvedIndex = results.size() - 1 - j;
287 RefPtr<ShapeResult>& wordResult = results[resolvedIndex];
288 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
289 advance += wordResult->fillGlyphBufferForRun<RTL>(glyphBuffer,
290 wordResult->m_runs[i], advance, from, to,
291 wordOffset - wordResult->numCharacters());
292 }
293 wordOffset -= wordResult->numCharacters();
294 }
295 } else {
296 unsigned wordOffset = 0;
297 for (unsigned j = 0; j < results.size(); j++) {
298 RefPtr<ShapeResult>& wordResult = results[j];
299 for (unsigned i = 0; i < wordResult->m_runs.size(); i++) {
300 advance += wordResult->fillGlyphBufferForRun<LTR>(glyphBuffer,
301 wordResult->m_runs[i], advance, from, to, wordOffset);
302 }
303 wordOffset += wordResult->numCharacters();
304 }
305 }
306
307 return advance;
308 }
309
310 float ShapeResult::fillGlyphBufferForTextEmphasis(
311 Vector<RefPtr<ShapeResult>>& results, GlyphBuffer* glyphBuffer,
312 const TextRun& textRun, const GlyphData* emphasisData,
313 unsigned from, unsigned to)
314 {
315 unsigned graphemesInCluster = 1;
316 float clusterAdvance = 0;
317 uint16_t clusterStart;
318
319 FloatPoint glyphCenter = emphasisData->fontData->
320 boundsForGlyph(emphasisData->glyph).center();
321
322 float advanceSoFar = 0;
323 TextDirection direction = textRun.direction();
324
325 unsigned wordOffset = 0;
326 for (unsigned j = 0; j < results.size(); j++) {
327 RefPtr<ShapeResult> result = results[j];
328
329 unsigned numRuns = result->m_runs.size();
330 for (unsigned k = 0; k < numRuns; k++) {
331 const RunInfo* run = result->m_runs[direction == LTR ? k : (numRuns - k - 1)];
332
333 // A "cluster" in this context means a cluster as it is used by Harf Buzz:
334 // The minimal group of characters and corresponding glyphs, that ca nnot be broken
335 // down further from a text shaping point of view.
336 // A cluster can contain multiple glyphs and grapheme clusters, with mutually
337 // overlapping boundaries. Below we count grapheme clusters per Harf Buzz clusters,
338 // then linearly split the sum of corresponding glyph advances by th e number of
339 // grapheme clusters in order to find positions for emphasis mark dr awing.
340 if (direction == RTL)
341 clusterStart = run->m_startIndex + run->m_numCharacters;
342 else
343 clusterStart = run->glyphToCharacterIndex(0);
344
345 unsigned numGlyphs = run->m_numGlyphs;
346 for (unsigned i = 0; i < numGlyphs; ++i) {
347 const HarfBuzzRunGlyphData& glyphData = run->m_glyphData[i];
348 uint16_t currentCharacterIndex = run->m_startIndex +
349 glyphData.characterIndex + wordOffset;
350 bool isRunEnd = (i + 1 == numGlyphs);
351 bool isClusterEnd = isRunEnd || (run->glyphToCharacterIndex(i + 1) != currentCharacterIndex);
352
353 if ((direction == RTL && currentCharacterIndex >= to) || (direct ion != RTL && currentCharacterIndex < from)) {
354 advanceSoFar += glyphData.advance;
355 direction == RTL ? --clusterStart : ++clusterStart;
356 continue;
357 }
358
359 clusterAdvance += glyphData.advance;
360
361 if (textRun.is8Bit()) {
362 float glyphAdvanceX = glyphData.advance;
363 if (Character::canReceiveTextEmphasis(textRun[currentCharact erIndex])) {
364 addEmphasisMark(glyphBuffer, emphasisData, glyphCenter, advanceSoFar + glyphAdvanceX / 2);
365 }
366 advanceSoFar += glyphAdvanceX;
367 } else if (isClusterEnd) {
368 uint16_t clusterEnd;
369 if (direction == RTL)
370 clusterEnd = currentCharacterIndex;
371 else
372 clusterEnd = isRunEnd ? run->m_startIndex + run->m_numCh aracters : run->glyphToCharacterIndex(i + 1);
373
374 graphemesInCluster = countGraphemesInCluster(textRun.charact ers16(), textRun.charactersLength(), clusterStart, clusterEnd);
375 if (!graphemesInCluster || !clusterAdvance)
376 continue;
377
378 float glyphAdvanceX = clusterAdvance / graphemesInCluster;
379 for (unsigned j = 0; j < graphemesInCluster; ++j) {
380 // Do not put emphasis marks on space, separator, and co ntrol characters.
381 if (Character::canReceiveTextEmphasis(textRun[currentCha racterIndex]))
382 addEmphasisMark(glyphBuffer, emphasisData, glyphCent er, advanceSoFar + glyphAdvanceX / 2);
383 advanceSoFar += glyphAdvanceX;
384 }
385 clusterStart = clusterEnd;
386 clusterAdvance = 0;
387 }
388 }
389 }
390 wordOffset += result->numCharacters();
391 }
392
393 return advanceSoFar;
394 }
395
396 FloatRect ShapeResult::selectionRect(Vector<RefPtr<ShapeResult>>& results,
397 TextDirection direction, float totalWidth, const FloatPoint& point,
398 int height, unsigned absoluteFrom, unsigned absoluteTo)
399 {
400 float currentX = 0;
401 float fromX = 0;
402 float toX = 0;
403 bool foundFromX = false;
404 bool foundToX = false;
405
406 if (direction == RTL)
407 currentX = totalWidth;
408
409 // The absoluteFrom and absoluteTo arguments represent the start/end offset
410 // for the entire run, from/to are continuously updated to be relative to
411 // the current word (ShapeResult instance).
412 int from = absoluteFrom;
413 int to = absoluteTo;
414
415 unsigned wordOffset = 0;
416 for (unsigned j = 0; j < results.size(); j++) {
417 RefPtr<ShapeResult> result = results[j];
418 for (unsigned i = 0; i < result->m_runs.size(); i++) {
419 if (direction == RTL)
420 currentX -= result->m_runs[i]->m_width;
421 int numCharacters = result->m_runs[i]->m_numCharacters;
422 if (!foundFromX && from >= 0 && from < numCharacters) {
423 fromX = result->m_runs[i]->xPositionForOffset(from) + currentX;
424 foundFromX = true;
425 } else {
426 from -= numCharacters;
427 }
428
429 if (!foundToX && to >= 0 && to < numCharacters) {
430 toX = result->m_runs[i]->xPositionForOffset(to) + currentX;
431 foundToX = true;
432 } else {
433 to -= numCharacters;
434 }
435
436 if (foundFromX && foundToX)
437 break;
438 if (direction != RTL)
439 currentX += result->m_runs[i]->m_width;
440 }
441 wordOffset += result->numCharacters();
442 totalWidth += result->width();
443 }
444
445 // The position in question might be just after the text.
446 if (!foundFromX)
447 fromX = 0;
448 if (!foundToX)
449 toX = direction == RTL ? 0 : totalWidth;
450
451 // None of our runs is part of the selection, possibly invalid arguments.
452 if (!foundToX && !foundFromX)
453 fromX = toX = 0;
454
455 if (fromX < toX)
456 return FloatRect(point.x() + fromX, point.y(), toX - fromX, height);
457 return FloatRect(point.x() + toX, point.y(), fromX - toX, height);
458 }
459
460 int ShapeResult::offsetForPosition(float targetX)
461 {
462 int charactersSoFar = 0;
463 float currentX = 0;
464
465 if (m_direction == RTL) {
466 charactersSoFar = m_numCharacters;
467 for (unsigned i = 0; i < m_runs.size(); ++i) {
468 charactersSoFar -= m_runs[i]->m_numCharacters;
469 float nextX = currentX + m_runs[i]->m_width;
470 float offsetForRun = targetX - currentX;
471 if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
472 // The x value in question is within this script run.
473 const unsigned index = m_runs[i]->characterIndexForXPosition(off setForRun);
474 return charactersSoFar + index;
475 }
476 currentX = nextX;
477 }
478 } else {
479 for (unsigned i = 0; i < m_runs.size(); ++i) {
480 float nextX = currentX + m_runs[i]->m_width;
481 float offsetForRun = targetX - currentX;
482 if (offsetForRun >= 0 && offsetForRun <= m_runs[i]->m_width) {
483 const unsigned index = m_runs[i]->characterIndexForXPosition(off setForRun);
484 return charactersSoFar + index;
485 }
486 charactersSoFar += m_runs[i]->m_numCharacters;
487 currentX = nextX;
488 }
489 }
490
491 return charactersSoFar;
492 }
493
494 unsigned ShapeResult::numberOfRunsForTesting() const
495 {
496 return m_runs.size();
497 }
498
499 bool ShapeResult::runInfoForTesting(unsigned runIndex, unsigned& startIndex,
500 unsigned& numGlyphs, hb_script_t& script)
501 {
502 if (runIndex < m_runs.size() && m_runs[runIndex]) {
503 startIndex = m_runs[runIndex]->m_startIndex;
504 numGlyphs = m_runs[runIndex]->m_numGlyphs;
505 script = m_runs[runIndex]->m_script;
506 return true;
507 }
508 return false;
509 }
510
511 uint16_t ShapeResult::glyphForTesting(unsigned runIndex, size_t glyphIndex)
512 {
513 return m_runs[runIndex]->m_glyphData[glyphIndex].glyph;
514 }
515
516 float ShapeResult::advanceForTesting(unsigned runIndex, size_t glyphIndex)
517 {
518 return m_runs[runIndex]->m_glyphData[glyphIndex].advance;
519 }
520
57 template<typename T> 521 template<typename T>
58 class HarfBuzzScopedPtr { 522 class HarfBuzzScopedPtr {
59 public: 523 public:
60 typedef void (*DestroyFunction)(T*); 524 typedef void (*DestroyFunction)(T*);
61 525
62 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy) 526 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
63 : m_ptr(ptr) 527 : m_ptr(ptr)
64 , m_destroy(destroy) 528 , m_destroy(destroy)
65 { 529 {
66 ASSERT(m_destroy); 530 ASSERT(m_destroy);
67 } 531 }
68 ~HarfBuzzScopedPtr() 532 ~HarfBuzzScopedPtr()
69 { 533 {
70 if (m_ptr) 534 if (m_ptr)
71 (*m_destroy)(m_ptr); 535 (*m_destroy)(m_ptr);
72 } 536 }
73 537
74 T* get() { return m_ptr; } 538 T* get() { return m_ptr; }
75 void set(T* ptr) { m_ptr = ptr; } 539 void set(T* ptr) { m_ptr = ptr; }
76 private: 540 private:
77 T* m_ptr; 541 T* m_ptr;
78 DestroyFunction m_destroy; 542 DestroyFunction m_destroy;
79 }; 543 };
80 544
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) 545 static inline float harfBuzzPositionToFloat(hb_position_t value)
214 { 546 {
215 return static_cast<float>(value) / (1 << 16); 547 return static_cast<float>(value) / (1 << 16);
216 } 548 }
217 549
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) 550 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, hb_direction_t direction, hb_script _t script)
239 : m_fontData(fontData) 551 : m_fontData(fontData)
240 , m_startIndex(startIndex) 552 , m_startIndex(startIndex)
241 , m_numCharacters(numCharacters) 553 , m_numCharacters(numCharacters)
242 , m_numGlyphs(0) 554 , m_numGlyphs(0)
243 , m_direction(direction) 555 , m_direction(direction)
244 , m_script(script) 556 , m_script(script)
245 , m_width(0)
246 { 557 {
247 } 558 }
248 559
249 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const HarfBuzzRun& rhs) 560 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const HarfBuzzRun& rhs)
250 : m_fontData(rhs.m_fontData) 561 : m_fontData(rhs.m_fontData)
251 , m_startIndex(rhs.m_startIndex) 562 , m_startIndex(rhs.m_startIndex)
252 , m_numCharacters(rhs.m_numCharacters) 563 , m_numCharacters(rhs.m_numCharacters)
253 , m_numGlyphs(rhs.m_numGlyphs) 564 , m_numGlyphs(rhs.m_numGlyphs)
254 , m_direction(rhs.m_direction) 565 , m_direction(rhs.m_direction)
255 , m_script(rhs.m_script) 566 , m_script(rhs.m_script)
256 , m_glyphData(rhs.m_glyphData)
257 , m_width(rhs.m_width)
258 { 567 {
259 } 568 }
260 569
261 HarfBuzzShaper::HarfBuzzRun::~HarfBuzzRun() 570 HarfBuzzShaper::HarfBuzzRun::~HarfBuzzRun()
262 { 571 {
263 } 572 }
264 573
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) 574 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest ination, unsigned* destinationLength)
344 { 575 {
345 unsigned position = 0; 576 unsigned position = 0;
346 bool error = false; 577 bool error = false;
347 const UChar* source; 578 const UChar* source;
348 String stringFor8BitRun; 579 String stringFor8BitRun;
349 if (run.is8Bit()) { 580 if (run.is8Bit()) {
350 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length()); 581 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length());
351 source = stringFor8BitRun.characters16(); 582 source = stringFor8BitRun.characters16();
352 } else { 583 } else {
(...skipping 10 matching lines...) Expand all
363 else if (Character::treatAsSpace(character) && character != tabulationCh aracter) 594 else if (Character::treatAsSpace(character) && character != tabulationCh aracter)
364 character = spaceCharacter; 595 character = spaceCharacter;
365 else if (Character::treatAsZeroWidthSpaceInComplexScript(character)) 596 else if (Character::treatAsZeroWidthSpaceInComplexScript(character))
366 character = zeroWidthSpaceCharacter; 597 character = zeroWidthSpaceCharacter;
367 598
368 U16_APPEND(destination, *destinationLength, length, character, error); 599 U16_APPEND(destination, *destinationLength, length, character, error);
369 ASSERT_UNUSED(error, !error); 600 ASSERT_UNUSED(error, !error);
370 } 601 }
371 } 602 }
372 603
373 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run, const Glyph Data* emphasisData, 604 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run,
374 HashSet<const SimpleFontData*>* fallbackFonts, FloatRect* bounds) 605 HashSet<const SimpleFontData*>* fallbackFonts)
375 : Shaper(font, run, emphasisData, fallbackFonts, bounds) 606 : Shaper(font, run, nullptr, fallbackFonts)
376 , m_normalizedBufferLength(0) 607 , m_normalizedBufferLength(0)
377 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing()) 608 , m_wordSpacingAdjustment(font->fontDescription().wordSpacing())
378 , m_letterSpacing(font->fontDescription().letterSpacing()) 609 , m_letterSpacing(font->fontDescription().letterSpacing())
379 , m_expansionOpportunityCount(0) 610 , m_expansionOpportunityCount(0)
380 , m_fromIndex(0)
381 , m_toIndex(m_textRun.length())
382 , m_totalWidth(0)
383 { 611 {
384 m_normalizedBuffer = adoptArrayPtr(new UChar[m_textRun.length() + 1]); 612 m_normalizedBuffer = adoptArrayPtr(new UChar[m_textRun.length() + 1]);
385 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength); 613 normalizeCharacters(m_textRun, m_textRun.length(), m_normalizedBuffer.get(), &m_normalizedBufferLength);
386 setExpansion(m_textRun.expansion()); 614 setExpansion(m_textRun.expansion());
387 setFontFeatures(); 615 setFontFeatures();
388 } 616 }
389 617
390 float HarfBuzzShaper::nextExpansionPerOpportunity() 618 float HarfBuzzShaper::nextExpansionPerOpportunity()
391 { 619 {
392 if (!m_expansionOpportunityCount) { 620 if (!m_expansionOpportunityCount) {
(...skipping 25 matching lines...) Expand all
418 ASSERT(m_expansionOpportunityCount > 0); 646 ASSERT(m_expansionOpportunityCount > 0);
419 --m_expansionOpportunityCount; 647 --m_expansionOpportunityCount;
420 } 648 }
421 649
422 if (m_expansionOpportunityCount) 650 if (m_expansionOpportunityCount)
423 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount; 651 m_expansionPerOpportunity = m_expansion / m_expansionOpportunityCount;
424 else 652 else
425 m_expansionPerOpportunity = 0; 653 m_expansionPerOpportunity = 0;
426 } 654 }
427 655
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() 656 void HarfBuzzShaper::setFontFeatures()
438 { 657 {
439 const FontDescription& description = m_font->fontDescription(); 658 const FontDescription& description = m_font->fontDescription();
440 659
441 static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) }; 660 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) }; 661 static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) };
443 switch (description.kerning()) { 662 switch (description.kerning()) {
444 case FontDescription::NormalKerning: 663 case FontDescription::NormalKerning:
445 // kern/vkrn are enabled by default 664 // kern/vkrn are enabled by default
446 break; 665 break;
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
524 hb_feature_t feature; 743 hb_feature_t feature;
525 const AtomicString& tag = settings->at(i).tag(); 744 const AtomicString& tag = settings->at(i).tag();
526 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]); 745 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
527 feature.value = settings->at(i).value(); 746 feature.value = settings->at(i).value();
528 feature.start = 0; 747 feature.start = 0;
529 feature.end = static_cast<unsigned>(-1); 748 feature.end = static_cast<unsigned>(-1);
530 m_features.append(feature); 749 m_features.append(feature);
531 } 750 }
532 } 751 }
533 752
534 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer) 753 PassRefPtr<ShapeResult> HarfBuzzShaper::shapeResult()
535 { 754 {
536 if (!createHarfBuzzRuns()) 755 if (!createHarfBuzzRuns())
537 return false; 756 return nullptr;
538 757
539 if (!shapeHarfBuzzRuns()) 758 ShapeResult* result = new ShapeResult();
540 return false; 759 result->m_numCharacters = m_normalizedBufferLength;
760 result->m_direction = m_textRun.direction();
541 761
542 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer)) 762 if (!shapeHarfBuzzRuns(result)) {
543 return false; 763 delete result;
764 return nullptr;
765 }
544 766
545 return true; 767 return adoptRef(result);
546 } 768 }
547 769
548 struct CandidateRun { 770 struct CandidateRun {
549 UChar32 character; 771 UChar32 character;
550 unsigned start; 772 unsigned start;
551 unsigned end; 773 unsigned end;
552 const SimpleFontData* fontData; 774 const SimpleFontData* fontData;
553 UScriptCode script; 775 UScriptCode script;
554 }; 776 };
555 777
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after
759 ASSERT(endCharacter > startCharacter); 981 ASSERT(endCharacter > startCharacter);
760 ASSERT(script != USCRIPT_INVALID_CODE); 982 ASSERT(script != USCRIPT_INVALID_CODE);
761 if (m_fallbackFonts) 983 if (m_fallbackFonts)
762 trackNonPrimaryFallbackFont(fontData); 984 trackNonPrimaryFallbackFont(fontData);
763 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData, 985 return m_harfBuzzRuns.append(HarfBuzzRun::create(fontData,
764 startCharacter, endCharacter - startCharacter, 986 startCharacter, endCharacter - startCharacter,
765 TextDirectionToHBDirection(m_textRun.direction(), m_font->fontDescriptio n().orientation(), fontData), 987 TextDirectionToHBDirection(m_textRun.direction(), m_font->fontDescriptio n().orientation(), fontData),
766 ICUScriptToHBScript(script))); 988 ICUScriptToHBScript(script)));
767 } 989 }
768 990
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) 991 static const uint16_t* toUint16(const UChar* src)
781 { 992 {
782 // FIXME: This relies on undefined behavior however it works on the 993 // FIXME: This relies on undefined behavior however it works on the
783 // current versions of all compilers we care about and avoids making 994 // current versions of all compilers we care about and avoids making
784 // a copy of the string. 995 // a copy of the string.
785 static_assert(sizeof(UChar) == sizeof(uint16_t), "UChar should be the same s ize as uint16_t"); 996 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); 997 return reinterpret_cast<const uint16_t*>(src);
787 } 998 }
788 999
789 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer, 1000 static inline void addToHarfBuzzBufferInternal(hb_buffer_t* buffer,
790 const FontDescription& fontDescription, const UChar* normalizedBuffer, 1001 const FontDescription& fontDescription, const UChar* normalizedBuffer,
791 unsigned startIndex, unsigned numCharacters) 1002 unsigned startIndex, unsigned numCharacters)
792 { 1003 {
793 if (fontDescription.variant() == FontVariantSmallCaps 1004 if (fontDescription.variant() == FontVariantSmallCaps
794 && u_islower(normalizedBuffer[startIndex])) { 1005 && u_islower(normalizedBuffer[startIndex])) {
795 String upperText = String(normalizedBuffer + startIndex, numCharacters) 1006 String upperText = String(normalizedBuffer + startIndex, numCharacters)
796 .upper(); 1007 .upper();
797 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call 1008 // TextRun is 16 bit, therefore upperText is 16 bit, even after we call
798 // makeUpper(). 1009 // makeUpper().
799 ASSERT(!upperText.is8Bit()); 1010 ASSERT(!upperText.is8Bit());
800 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()), 1011 hb_buffer_add_utf16(buffer, toUint16(upperText.characters16()),
801 numCharacters, 0, numCharacters); 1012 numCharacters, 0, numCharacters);
802 } else { 1013 } else {
803 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex), 1014 hb_buffer_add_utf16(buffer, toUint16(normalizedBuffer + startIndex),
804 numCharacters, 0, numCharacters); 1015 numCharacters, 0, numCharacters);
805 } 1016 }
806 } 1017 }
807 1018
808 bool HarfBuzzShaper::shapeHarfBuzzRuns() 1019 bool HarfBuzzShaper::shapeHarfBuzzRuns(ShapeResult* result)
809 { 1020 {
810 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy); 1021 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy);
811 1022
812 HarfBuzzRunCache& runCache = harfBuzzRunCache();
813 const FontDescription& fontDescription = m_font->fontDescription(); 1023 const FontDescription& fontDescription = m_font->fontDescription();
814 const String& localeString = fontDescription.locale(); 1024 const String& localeString = fontDescription.locale();
815 CString locale = localeString.latin1(); 1025 CString locale = localeString.latin1();
816 const hb_language_t language = hb_language_from_string(locale.data(), locale .length()); 1026 const hb_language_t language = hb_language_from_string(locale.data(), locale .length());
817 1027
1028 result->m_runs.resize(m_harfBuzzRuns.size());
818 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) { 1029 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
819 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i; 1030 unsigned runIndex = m_textRun.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
820 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get(); 1031 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
821 1032
822 const SimpleFontData* currentFontData = currentRun->fontData(); 1033 const SimpleFontData* currentFontData = currentRun->fontData();
823 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData()); 1034 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData());
824 HarfBuzzFace* face = platformData->harfBuzzFace(); 1035 HarfBuzzFace* face = platformData->harfBuzzFace();
825 if (!face) 1036 if (!face)
826 return false; 1037 return false;
827 1038
828 hb_buffer_set_language(harfBuzzBuffer.get(), language); 1039 hb_buffer_set_language(harfBuzzBuffer.get(), language);
829 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script()); 1040 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
830 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction()); 1041 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->direction());
831 1042
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 1043 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle
850 // for combining marks at the beginning of runs. 1044 // for combining marks at the beginning of runs.
851 static const uint16_t preContext = spaceCharacter; 1045 static const uint16_t preContext = spaceCharacter;
852 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0); 1046 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
853 1047
854 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(), 1048 addToHarfBuzzBufferInternal(harfBuzzBuffer.get(),
855 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(), 1049 fontDescription, m_normalizedBuffer.get(), currentRun->startIndex(),
856 currentRun->numCharacters()); 1050 currentRun->numCharacters());
857 1051
858 if (fontDescription.isVerticalAnyUpright()) 1052 if (fontDescription.isVerticalAnyUpright())
859 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get()); 1053 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
860 1054
861 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy); 1055 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy);
1056 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
1057 shapeResult(result, i, currentRun, harfBuzzBuffer.get());
862 1058
863 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size()); 1059 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 } 1060 }
871 1061
872 // We should have consumed all expansion opportunities. 1062 // We should have consumed all expansion opportunities.
873 // Failures here means that our logic does not match to the one in expansion OpportunityCount(). 1063 // 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, 1064 // 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 1065 // 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. 1066 // 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. 1067 // It's to be fixed because they're very rarely used, and a broken justifica tion is still somewhat readable.
878 1068
879 return true; 1069 return true;
880 } 1070 }
881 1071
882 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb _buffer_t* harfBuzzBuffer) 1072 void HarfBuzzShaper::shapeResult(ShapeResult* result, unsigned index,
1073 HarfBuzzRun* currentRun, hb_buffer_t* harfBuzzBuffer)
883 { 1074 {
884 // Skip runs that only contain control characters. 1075 unsigned numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
885 if (!currentRun->numGlyphs()) 1076 if (!numGlyphs) {
1077 result->m_runs[index] = nullptr;
886 return; 1078 return;
1079 }
1080
1081 currentRun->setNumGlyphs(numGlyphs);
1082 ShapeResult::RunInfo* run = new ShapeResult::RunInfo(currentRun->fontData(),
1083 currentRun->direction(), currentRun->script(), currentRun->startIndex(),
1084 numGlyphs, currentRun->numCharacters());
1085 result->m_runs[index] = run;
1086 result->m_numGlyphs += numGlyphs;
887 1087
888 const SimpleFontData* currentFontData = currentRun->fontData(); 1088 const SimpleFontData* currentFontData = currentRun->fontData();
889 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0); 1089 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); 1090 hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzz Buffer, 0);
891 1091
892 unsigned numGlyphs = currentRun->numGlyphs();
893 float totalAdvance = 0; 1092 float totalAdvance = 0;
894 FloatPoint glyphOrigin; 1093 FloatPoint glyphOrigin;
895 float offsetX, offsetY; 1094 float offsetX, offsetY;
896 float* directionOffset = m_font->fontDescription().isVerticalAnyUpright() ? &offsetY : &offsetX; 1095 float* directionOffset = m_font->fontDescription().isVerticalAnyUpright() ? &offsetY : &offsetX;
897 1096
898 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL. 1097 // HarfBuzz returns result in visual order, no need to flip for RTL.
899 for (size_t i = 0; i < numGlyphs; ++i) { 1098 for (size_t i = 0; i < numGlyphs; ++i) {
900 bool runEnd = i + 1 == numGlyphs; 1099 bool runEnd = i + 1 == numGlyphs;
901 uint16_t glyph = glyphInfos[i].codepoint; 1100 uint16_t glyph = glyphInfos[i].codepoint;
902 offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset); 1101 offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
903 offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset); 1102 offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
1103
904 // One out of x_advance and y_advance is zero, depending on 1104 // One out of x_advance and y_advance is zero, depending on
905 // whether the buffer direction is horizontal or vertical. 1105 // whether the buffer direction is horizontal or vertical.
906 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance); 1106 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance - gl yphPositions[i].y_advance);
907
908 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster; 1107 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster;
909 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex); 1108 RELEASE_ASSERT(m_normalizedBufferLength > currentCharacterIndex);
910 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster; 1109 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster;
911 float spacing = 0; 1110 float spacing = 0;
912 1111
913 currentRun->glyphData(i).characterIndex = glyphInfos[i].cluster; 1112 run->m_glyphData[i].characterIndex = glyphInfos[i].cluster;
914 1113
915 if (isClusterEnd) 1114 if (isClusterEnd)
916 spacing += adjustSpacing(currentRun, i, currentCharacterIndex, *dire ctionOffset, totalAdvance); 1115 spacing += adjustSpacing(run, i, currentCharacterIndex, *directionOf fset, totalAdvance);
917 1116
918 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) { 1117 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
919 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0); 1118 run->setGlyphAndPositions(i, glyph, 0, 0, 0);
920 continue; 1119 continue;
921 } 1120 }
922 1121
923 advance += spacing; 1122 advance += spacing;
924 if (m_textRun.rtl()) { 1123 if (m_textRun.rtl()) {
925 // In RTL, spacing should be added to left side of glyphs. 1124 // In RTL, spacing should be added to left side of glyphs.
926 *directionOffset += spacing; 1125 *directionOffset += spacing;
927 if (!isClusterEnd) 1126 if (!isClusterEnd)
928 *directionOffset += m_letterSpacing; 1127 *directionOffset += m_letterSpacing;
929 } 1128 }
930 1129
931 currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY); 1130 run->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
1131 totalAdvance += advance;
932 1132
933 if (m_glyphBoundingBox) { 1133 FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph);
934 FloatRect glyphBounds = currentFontData->boundsForGlyph(glyph); 1134 glyphBounds.move(glyphOrigin.x(), glyphOrigin.y());
935 glyphBounds.move(glyphOrigin.x(), glyphOrigin.y()); 1135 result->m_glyphBoundingBox.unite(glyphBounds);
936 m_glyphBoundingBox->unite(glyphBounds); 1136 glyphOrigin += FloatSize(advance + offsetX, offsetY);
937 glyphOrigin += FloatSize(advance + offsetX, offsetY); 1137 }
938 }
939 1138
940 totalAdvance += advance; 1139 run->m_width = totalAdvance > 0.0 ? totalAdvance : 0.0;
941 } 1140 result->m_width += run->m_width;
942 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
943 m_totalWidth += currentRun->width();
944 } 1141 }
945 1142
946 float HarfBuzzShaper::adjustSpacing(HarfBuzzRun* currentRun, size_t glyphIndex, unsigned currentCharacterIndex, float& offset, float& totalAdvance) 1143 float HarfBuzzShaper::adjustSpacing(ShapeResult::RunInfo* run, size_t glyphIndex , unsigned currentCharacterIndex, float& offset, float& totalAdvance)
947 { 1144 {
948 float spacing = 0; 1145 float spacing = 0;
949 UChar32 character = m_normalizedBuffer[currentCharacterIndex]; 1146 UChar32 character = m_normalizedBuffer[currentCharacterIndex];
950 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character)) 1147 if (m_letterSpacing && !Character::treatAsZeroWidthSpace(character))
951 spacing += m_letterSpacing; 1148 spacing += m_letterSpacing;
952 1149
953 bool treatAsSpace = Character::treatAsSpace(character); 1150 bool treatAsSpace = Character::treatAsSpace(character);
954 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu n.allowTabs())) 1151 if (treatAsSpace && currentCharacterIndex && (character != '\t' || !m_textRu n.allowTabs()))
955 spacing += m_wordSpacingAdjustment; 1152 spacing += m_wordSpacingAdjustment;
956 1153
(...skipping 18 matching lines...) Expand all
975 if (!Character::isCJKIdeographOrSymbol(character)) { 1172 if (!Character::isCJKIdeographOrSymbol(character)) {
976 m_isAfterExpansion = false; 1173 m_isAfterExpansion = false;
977 return spacing; 1174 return spacing;
978 } 1175 }
979 1176
980 if (!m_isAfterExpansion) { 1177 if (!m_isAfterExpansion) {
981 // Take the expansion opportunity before this ideograph. 1178 // Take the expansion opportunity before this ideograph.
982 float expandBefore = nextExpansionPerOpportunity(); 1179 float expandBefore = nextExpansionPerOpportunity();
983 if (expandBefore) { 1180 if (expandBefore) {
984 if (glyphIndex > 0) { 1181 if (glyphIndex > 0) {
985 currentRun->addAdvance(glyphIndex - 1, expandBefore); 1182 run->addAdvance(glyphIndex - 1, expandBefore);
986 totalAdvance += expandBefore; 1183 totalAdvance += expandBefore;
987 } else { 1184 } else {
988 offset += expandBefore; 1185 offset += expandBefore;
989 spacing += expandBefore; 1186 spacing += expandBefore;
990 } 1187 }
991 } 1188 }
992 if (!m_expansionOpportunityCount) 1189 if (!m_expansionOpportunityCount)
993 return spacing; 1190 return spacing;
994 } 1191 }
995 1192
996 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere d by !m_expansionOpportunityCount above 1193 // Don't need to check m_textRun.allowsTrailingExpansion() since it's covere d by !m_expansionOpportunityCount above
997 spacing += nextExpansionPerOpportunity(); 1194 spacing += nextExpansionPerOpportunity();
998 m_isAfterExpansion = true; 1195 m_isAfterExpansion = true;
999 return spacing; 1196 return spacing;
1000 } 1197 }
1001 1198
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 1199 } // namespace blink
OLDNEW
« no previous file with comments | « Source/platform/fonts/shaping/HarfBuzzShaper.h ('k') | Source/platform/fonts/shaping/HarfBuzzShaperTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698