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

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