OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 Loading... | |
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*>(¤tF ontData->platformData()); | 1034 FontPlatformData* platformData = const_cast<FontPlatformData*>(¤tF 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 Loading... | |
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 |
OLD | NEW |