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

Side by Side Diff: Source/core/platform/graphics/harfbuzz/HarfBuzzShaper.cpp

Issue 99103006: Moving GraphicsContext and dependencies from core to platform. (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Final patch - fixes Android Created 7 years 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
(Empty)
1 /*
2 * Copyright (c) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2013 BlackBerry Limited. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
7 * met:
8 *
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * * Redistributions in binary form must reproduce the above
12 * copyright notice, this list of conditions and the following disclaimer
13 * in the documentation and/or other materials provided with the
14 * distribution.
15 * * Neither the name of Google Inc. nor the names of its
16 * contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */
31
32 #include "config.h"
33 #include "core/platform/graphics/harfbuzz/HarfBuzzShaper.h"
34
35 #include "RuntimeEnabledFeatures.h"
36 #include "core/platform/graphics/Font.h"
37 #include "core/platform/graphics/harfbuzz/HarfBuzzFace.h"
38 #include "hb-icu.h"
39 #include "platform/text/SurrogatePairAwareTextIterator.h"
40 #include "wtf/MathExtras.h"
41 #include "wtf/unicode/Unicode.h"
42 #include <unicode/normlzr.h>
43 #include <unicode/uchar.h>
44
45 #include <list>
46 #include <map>
47 #include <string>
48
49 namespace WebCore {
50
51 template<typename T>
52 class HarfBuzzScopedPtr {
53 public:
54 typedef void (*DestroyFunction)(T*);
55
56 HarfBuzzScopedPtr(T* ptr, DestroyFunction destroy)
57 : m_ptr(ptr)
58 , m_destroy(destroy)
59 {
60 ASSERT(m_destroy);
61 }
62 ~HarfBuzzScopedPtr()
63 {
64 if (m_ptr)
65 (*m_destroy)(m_ptr);
66 }
67
68 T* get() { return m_ptr; }
69 void set(T* ptr) { m_ptr = ptr; }
70 private:
71 T* m_ptr;
72 DestroyFunction m_destroy;
73 };
74
75
76 static const unsigned cHarfBuzzCacheMaxSize = 256;
77
78 struct CachedShapingResultsLRUNode;
79 struct CachedShapingResults;
80 typedef std::map<std::wstring, CachedShapingResults*> CachedShapingResultsMap;
81 typedef std::list<CachedShapingResultsLRUNode*> CachedShapingResultsLRU;
82
83 struct CachedShapingResults {
84 CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Font* runFont, hb_di rection_t runDir);
85 ~CachedShapingResults();
86
87 hb_buffer_t* buffer;
88 Font font;
89 hb_direction_t dir;
90 CachedShapingResultsLRU::iterator lru;
91 };
92
93 struct CachedShapingResultsLRUNode {
94 CachedShapingResultsLRUNode(const CachedShapingResultsMap::iterator& cacheEn try);
95 ~CachedShapingResultsLRUNode();
96
97 CachedShapingResultsMap::iterator entry;
98 };
99
100 CachedShapingResults::CachedShapingResults(hb_buffer_t* harfBuzzBuffer, const Fo nt* fontData, hb_direction_t dirData)
101 : buffer(harfBuzzBuffer)
102 , font(*fontData)
103 , dir(dirData)
104 {
105 }
106
107 CachedShapingResults::~CachedShapingResults()
108 {
109 hb_buffer_destroy(buffer);
110 }
111
112 CachedShapingResultsLRUNode::CachedShapingResultsLRUNode(const CachedShapingResu ltsMap::iterator& cacheEntry)
113 : entry(cacheEntry)
114 {
115 }
116
117 CachedShapingResultsLRUNode::~CachedShapingResultsLRUNode()
118 {
119 }
120
121 class HarfBuzzRunCache {
122 public:
123 HarfBuzzRunCache();
124 ~HarfBuzzRunCache();
125
126 CachedShapingResults* find(const std::wstring& key) const;
127 void remove(CachedShapingResults* node);
128 void moveToBack(CachedShapingResults* node);
129 bool insert(const std::wstring& key, CachedShapingResults* run);
130
131 private:
132 CachedShapingResultsMap m_harfBuzzRunMap;
133 CachedShapingResultsLRU m_harfBuzzRunLRU;
134 };
135
136
137 HarfBuzzRunCache::HarfBuzzRunCache()
138 {
139 }
140
141 HarfBuzzRunCache::~HarfBuzzRunCache()
142 {
143 for (CachedShapingResultsMap::iterator it = m_harfBuzzRunMap.begin(); it != m_harfBuzzRunMap.end(); ++it)
144 delete it->second;
145 for (CachedShapingResultsLRU::iterator it = m_harfBuzzRunLRU.begin(); it != m_harfBuzzRunLRU.end(); ++it)
146 delete *it;
147 }
148
149 bool HarfBuzzRunCache::insert(const std::wstring& key, CachedShapingResults* dat a)
150 {
151 std::pair<CachedShapingResultsMap::iterator, bool> results =
152 m_harfBuzzRunMap.insert(CachedShapingResultsMap::value_type(key, data));
153
154 if (!results.second)
155 return false;
156
157 CachedShapingResultsLRUNode* node = new CachedShapingResultsLRUNode(results. first);
158
159 m_harfBuzzRunLRU.push_back(node);
160 data->lru = --m_harfBuzzRunLRU.end();
161
162 if (m_harfBuzzRunMap.size() > cHarfBuzzCacheMaxSize) {
163 CachedShapingResultsLRUNode* lru = m_harfBuzzRunLRU.front();
164 CachedShapingResults* foo = lru->entry->second;
165 m_harfBuzzRunMap.erase(lru->entry);
166 m_harfBuzzRunLRU.pop_front();
167 delete foo;
168 delete lru;
169 }
170
171 return true;
172 }
173
174 inline CachedShapingResults* HarfBuzzRunCache::find(const std::wstring& key) con st
175 {
176 CachedShapingResultsMap::const_iterator it = m_harfBuzzRunMap.find(key);
177
178 return it != m_harfBuzzRunMap.end() ? it->second : 0;
179 }
180
181 inline void HarfBuzzRunCache::remove(CachedShapingResults* node)
182 {
183 CachedShapingResultsLRUNode* lruNode = *node->lru;
184
185 m_harfBuzzRunLRU.erase(node->lru);
186 m_harfBuzzRunMap.erase(lruNode->entry);
187 delete lruNode;
188 delete node;
189 }
190
191 inline void HarfBuzzRunCache::moveToBack(CachedShapingResults* node)
192 {
193 CachedShapingResultsLRUNode* lruNode = *node->lru;
194 m_harfBuzzRunLRU.erase(node->lru);
195 m_harfBuzzRunLRU.push_back(lruNode);
196 node->lru = --m_harfBuzzRunLRU.end();
197 }
198
199 HarfBuzzRunCache& harfBuzzRunCache()
200 {
201 DEFINE_STATIC_LOCAL(HarfBuzzRunCache, globalHarfBuzzRunCache, ());
202 return globalHarfBuzzRunCache;
203 }
204
205 static inline float harfBuzzPositionToFloat(hb_position_t value)
206 {
207 return static_cast<float>(value) / (1 << 16);
208 }
209
210 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const SimpleFontData* fontData, unsigned startIndex, unsigned numCharacters, TextDirection direction, hb_script_ t script)
211 : m_fontData(fontData)
212 , m_startIndex(startIndex)
213 , m_numCharacters(numCharacters)
214 , m_numGlyphs(0)
215 , m_direction(direction)
216 , m_script(script)
217 , m_width(0)
218 {
219 }
220
221 inline HarfBuzzShaper::HarfBuzzRun::HarfBuzzRun(const HarfBuzzRun& rhs)
222 : m_fontData(rhs.m_fontData)
223 , m_startIndex(rhs.m_startIndex)
224 , m_numCharacters(rhs.m_numCharacters)
225 , m_numGlyphs(rhs.m_numGlyphs)
226 , m_direction(rhs.m_direction)
227 , m_script(rhs.m_script)
228 , m_glyphs(rhs.m_glyphs)
229 , m_advances(rhs.m_advances)
230 , m_glyphToCharacterIndexes(rhs.m_glyphToCharacterIndexes)
231 , m_offsets(rhs.m_offsets)
232 , m_width(rhs.m_width)
233 {
234 }
235
236 HarfBuzzShaper::HarfBuzzRun::~HarfBuzzRun()
237 {
238 }
239
240 inline void HarfBuzzShaper::HarfBuzzRun::applyShapeResult(hb_buffer_t* harfBuzzB uffer)
241 {
242 m_numGlyphs = hb_buffer_get_length(harfBuzzBuffer);
243 m_glyphs.resize(m_numGlyphs);
244 m_advances.resize(m_numGlyphs);
245 m_glyphToCharacterIndexes.resize(m_numGlyphs);
246 m_offsets.resize(m_numGlyphs);
247 }
248
249 inline void HarfBuzzShaper::HarfBuzzRun::copyShapeResultAndGlyphPositions(const HarfBuzzRun& run)
250 {
251 m_numGlyphs = run.m_numGlyphs;
252 m_glyphs = run.m_glyphs;
253 m_advances = run.m_advances;
254 m_glyphToCharacterIndexes = run.m_glyphToCharacterIndexes;
255 m_offsets = run.m_offsets;
256 m_width = run.m_width;
257 }
258
259 inline void HarfBuzzShaper::HarfBuzzRun::setGlyphAndPositions(unsigned index, ui nt16_t glyphId, float advance, float offsetX, float offsetY)
260 {
261 m_glyphs[index] = glyphId;
262 m_advances[index] = advance;
263 m_offsets[index] = FloatPoint(offsetX, offsetY);
264 }
265
266 int HarfBuzzShaper::HarfBuzzRun::characterIndexForXPosition(float targetX)
267 {
268 ASSERT(targetX <= m_width);
269 float currentX = 0;
270 float currentAdvance = m_advances[0];
271 unsigned glyphIndex = 0;
272
273 // Sum up advances that belong to a character.
274 while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIndex] == m_glyphToCharacterIndexes[glyphIndex + 1])
275 currentAdvance += m_advances[++glyphIndex];
276 currentAdvance = currentAdvance / 2.0;
277 if (targetX <= currentAdvance)
278 return rtl() ? m_numCharacters : 0;
279
280 ++glyphIndex;
281 while (glyphIndex < m_numGlyphs) {
282 unsigned prevCharacterIndex = m_glyphToCharacterIndexes[glyphIndex - 1];
283 float prevAdvance = currentAdvance;
284 currentAdvance = m_advances[glyphIndex];
285 while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIn dex] == m_glyphToCharacterIndexes[glyphIndex + 1])
286 currentAdvance += m_advances[++glyphIndex];
287 currentAdvance = currentAdvance / 2.0;
288 float nextX = currentX + prevAdvance + currentAdvance;
289 if (currentX <= targetX && targetX <= nextX)
290 return rtl() ? prevCharacterIndex : m_glyphToCharacterIndexes[glyphI ndex];
291 currentX = nextX;
292 prevAdvance = currentAdvance;
293 ++glyphIndex;
294 }
295
296 return rtl() ? 0 : m_numCharacters;
297 }
298
299 float HarfBuzzShaper::HarfBuzzRun::xPositionForOffset(unsigned offset)
300 {
301 ASSERT(offset < m_numCharacters);
302 unsigned glyphIndex = 0;
303 float position = 0;
304 if (rtl()) {
305 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] > offset) {
306 position += m_advances[glyphIndex];
307 ++glyphIndex;
308 }
309 // For RTL, we need to return the right side boundary of the character.
310 // Add advance of glyphs which are part of the character.
311 while (glyphIndex < m_numGlyphs - 1 && m_glyphToCharacterIndexes[glyphIn dex] == m_glyphToCharacterIndexes[glyphIndex + 1]) {
312 position += m_advances[glyphIndex];
313 ++glyphIndex;
314 }
315 position += m_advances[glyphIndex];
316 } else {
317 while (glyphIndex < m_numGlyphs && m_glyphToCharacterIndexes[glyphIndex] < offset) {
318 position += m_advances[glyphIndex];
319 ++glyphIndex;
320 }
321 }
322 return position;
323 }
324
325 static void normalizeCharacters(const TextRun& run, unsigned length, UChar* dest ination, unsigned* destinationLength)
326 {
327 unsigned position = 0;
328 bool error = false;
329 const UChar* source;
330 String stringFor8BitRun;
331 if (run.is8Bit()) {
332 stringFor8BitRun = String::make16BitFrom8BitSource(run.characters8(), ru n.length());
333 source = stringFor8BitRun.characters16();
334 } else
335 source = run.characters16();
336
337 *destinationLength = 0;
338 while (position < length) {
339 UChar32 character;
340 U16_NEXT(source, position, length, character);
341 // Don't normalize tabs as they are not treated as spaces for word-end.
342 if (Font::treatAsSpace(character) && character != '\t')
343 character = ' ';
344 else if (Font::treatAsZeroWidthSpaceInComplexScript(character))
345 character = zeroWidthSpace;
346 U16_APPEND(destination, *destinationLength, length, character, error);
347 ASSERT_UNUSED(error, !error);
348 }
349 }
350
351 HarfBuzzShaper::HarfBuzzShaper(const Font* font, const TextRun& run)
352 : m_font(font)
353 , m_normalizedBufferLength(0)
354 , m_run(run)
355 , m_wordSpacingAdjustment(font->wordSpacing())
356 , m_padding(0)
357 , m_padPerWordBreak(0)
358 , m_padError(0)
359 , m_letterSpacing(font->letterSpacing())
360 , m_fromIndex(0)
361 , m_toIndex(m_run.length())
362 {
363 m_normalizedBuffer = adoptArrayPtr(new UChar[m_run.length() + 1]);
364 normalizeCharacters(m_run, m_run.length(), m_normalizedBuffer.get(), &m_norm alizedBufferLength);
365 setPadding(m_run.expansion());
366 setFontFeatures();
367 }
368
369 static void normalizeSpacesAndMirrorChars(const UChar* source, unsigned length, UChar* destination, unsigned* destinationLength, HarfBuzzShaper::NormalizeMode n ormalizeMode)
370 {
371 unsigned position = 0;
372 bool error = false;
373 // Iterate characters in source and mirror character if needed.
374 *destinationLength = 0;
375 while (position < length) {
376 UChar32 character;
377 U16_NEXT(source, position, length, character);
378 // Don't normalize tabs as they are not treated as spaces for word-end
379 if (Font::treatAsSpace(character) && character != '\t')
380 character = ' ';
381 else if (Font::treatAsZeroWidthSpace(character))
382 character = zeroWidthSpace;
383 else if (normalizeMode == HarfBuzzShaper::NormalizeMirrorChars)
384 character = u_charMirror(character);
385 U16_APPEND(destination, *destinationLength, length, character, error);
386 ASSERT_UNUSED(error, !error);
387 }
388 }
389
390 void HarfBuzzShaper::setNormalizedBuffer(NormalizeMode normalizeMode)
391 {
392 // Normalize the text run in three ways:
393 // 1) Convert the |originalRun| to NFC normalized form if combining diacriti cal marks
394 // (U+0300..) are used in the run. This conversion is necessary since most O penType
395 // fonts (e.g., Arial) don't have substitution rules for the diacritical mar ks in
396 // their GSUB tables.
397 //
398 // Note that we don't use the icu::Normalizer::isNormalized(UNORM_NFC) API h ere since
399 // the API returns FALSE (= not normalized) for complex runs that don't requ ire NFC
400 // normalization (e.g., Arabic text). Unless the run contains the diacritica l marks,
401 // HarfBuzz will do the same thing for us using the GSUB table.
402 // 2) Convert spacing characters into plain spaces, as some fonts will provi de glyphs
403 // for characters like '\n' otherwise.
404 // 3) Convert mirrored characters such as parenthesis for rtl text.
405
406 // Convert to NFC form if the text has diacritical marks.
407 icu::UnicodeString normalizedString;
408 UErrorCode error = U_ZERO_ERROR;
409
410 const UChar* runCharacters;
411 String stringFor8BitRun;
412 if (m_run.is8Bit()) {
413 stringFor8BitRun = String::make16BitFrom8BitSource(m_run.characters8(), m_run.length());
414 runCharacters = stringFor8BitRun.characters16();
415 } else
416 runCharacters = m_run.characters16();
417
418 for (int i = 0; i < m_run.length(); ++i) {
419 UChar ch = runCharacters[i];
420 if (::ublock_getCode(ch) == UBLOCK_COMBINING_DIACRITICAL_MARKS) {
421 icu::Normalizer::normalize(icu::UnicodeString(runCharacters,
422 m_run.length()), UNORM_NFC, 0 /* no options */,
423 normalizedString, error);
424 if (U_FAILURE(error))
425 normalizedString.remove();
426 break;
427 }
428 }
429
430 const UChar* sourceText;
431 unsigned sourceLength;
432 if (normalizedString.isEmpty()) {
433 sourceLength = m_run.length();
434 sourceText = runCharacters;
435 } else {
436 sourceLength = normalizedString.length();
437 sourceText = normalizedString.getBuffer();
438 }
439
440 m_normalizedBuffer = adoptArrayPtr(new UChar[sourceLength + 1]);
441 normalizeSpacesAndMirrorChars(sourceText, sourceLength, m_normalizedBuffer.g et(), &m_normalizedBufferLength, normalizeMode);
442 }
443
444 bool HarfBuzzShaper::isWordEnd(unsigned index)
445 {
446 // This could refer a high-surrogate, but should work.
447 return index && isCodepointSpace(m_normalizedBuffer[index]);
448 }
449
450 int HarfBuzzShaper::determineWordBreakSpacing()
451 {
452 int wordBreakSpacing = m_wordSpacingAdjustment;
453
454 if (m_padding > 0) {
455 int toPad = roundf(m_padPerWordBreak + m_padError);
456 m_padError += m_padPerWordBreak - toPad;
457
458 if (m_padding < toPad)
459 toPad = m_padding;
460 m_padding -= toPad;
461 wordBreakSpacing += toPad;
462 }
463 return wordBreakSpacing;
464 }
465
466 // setPadding sets a number of pixels to be distributed across the TextRun.
467 // WebKit uses this to justify text.
468 void HarfBuzzShaper::setPadding(int padding)
469 {
470 m_padding = padding;
471 m_padError = 0;
472 if (!m_padding)
473 return;
474
475 // If we have padding to distribute, then we try to give an equal
476 // amount to each space. The last space gets the smaller amount, if
477 // any.
478 unsigned numWordEnds = 0;
479
480 for (unsigned i = 0; i < m_normalizedBufferLength; i++) {
481 if (isWordEnd(i))
482 numWordEnds++;
483 }
484
485 if (numWordEnds)
486 m_padPerWordBreak = m_padding / numWordEnds;
487 else
488 m_padPerWordBreak = 0;
489 }
490
491
492 void HarfBuzzShaper::setDrawRange(int from, int to)
493 {
494 ASSERT_WITH_SECURITY_IMPLICATION(from >= 0);
495 ASSERT_WITH_SECURITY_IMPLICATION(to <= m_run.length());
496 m_fromIndex = from;
497 m_toIndex = to;
498 }
499
500 void HarfBuzzShaper::setFontFeatures()
501 {
502 const FontDescription& description = m_font->fontDescription();
503 if (description.orientation() == Vertical) {
504 static hb_feature_t vert = { HarfBuzzFace::vertTag, 1, 0, static_cast<un signed>(-1) };
505 static hb_feature_t vrt2 = { HarfBuzzFace::vrt2Tag, 1, 0, static_cast<un signed>(-1) };
506 m_features.append(vert);
507 m_features.append(vrt2);
508 }
509
510 static hb_feature_t noKern = { HB_TAG('k', 'e', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) };
511 static hb_feature_t noVkrn = { HB_TAG('v', 'k', 'r', 'n'), 0, 0, static_cast <unsigned>(-1) };
512 switch (description.kerning()) {
513 case FontDescription::NormalKerning:
514 // kern/vkrn are enabled by default
515 break;
516 case FontDescription::NoneKerning:
517 m_features.append(description.orientation() == Vertical ? noVkrn : noKer n);
518 break;
519 case FontDescription::AutoKerning:
520 break;
521 }
522
523 FontFeatureSettings* settings = description.featureSettings();
524 if (!settings)
525 return;
526
527 unsigned numFeatures = settings->size();
528 for (unsigned i = 0; i < numFeatures; ++i) {
529 hb_feature_t feature;
530 const AtomicString& tag = settings->at(i).tag();
531 feature.tag = HB_TAG(tag[0], tag[1], tag[2], tag[3]);
532 feature.value = settings->at(i).value();
533 feature.start = 0;
534 feature.end = static_cast<unsigned>(-1);
535 m_features.append(feature);
536 }
537 }
538
539 bool HarfBuzzShaper::shape(GlyphBuffer* glyphBuffer)
540 {
541 if (!collectHarfBuzzRuns())
542 return false;
543
544 m_totalWidth = 0;
545 // WebKit doesn't set direction when calulating widths. Leave the direction setting to
546 // HarfBuzz when we are calculating widths (except when directionalOverride( ) is set).
547 if (!shapeHarfBuzzRuns(glyphBuffer || m_run.directionalOverride()))
548 return false;
549
550 if (!RuntimeEnabledFeatures::subpixelFontScalingEnabled())
551 m_totalWidth = roundf(m_totalWidth);
552
553 if (glyphBuffer && !fillGlyphBuffer(glyphBuffer))
554 return false;
555
556 return true;
557 }
558
559 FloatPoint HarfBuzzShaper::adjustStartPoint(const FloatPoint& point)
560 {
561 return point + m_startOffset;
562 }
563
564 bool HarfBuzzShaper::collectHarfBuzzRuns()
565 {
566 const UChar* normalizedBufferEnd = m_normalizedBuffer.get() + m_normalizedBu fferLength;
567 SurrogatePairAwareTextIterator iterator(m_normalizedBuffer.get(), 0, m_norma lizedBufferLength, m_normalizedBufferLength);
568 UChar32 character;
569 unsigned clusterLength = 0;
570 unsigned startIndexOfCurrentRun = 0;
571 if (!iterator.consume(character, clusterLength))
572 return false;
573
574 const SimpleFontData* nextFontData = m_font->glyphDataForCharacter(character , false).fontData;
575 UErrorCode errorCode = U_ZERO_ERROR;
576 UScriptCode nextScript = uscript_getScript(character, &errorCode);
577 if (U_FAILURE(errorCode))
578 return false;
579
580 do {
581 const UChar* currentCharacterPosition = iterator.characters();
582 const SimpleFontData* currentFontData = nextFontData;
583 UScriptCode currentScript = nextScript;
584
585 for (iterator.advance(clusterLength); iterator.consume(character, cluste rLength); iterator.advance(clusterLength)) {
586 if (Font::treatAsZeroWidthSpace(character))
587 continue;
588
589 if (U_GET_GC_MASK(character) & U_GC_M_MASK) {
590 int markLength = clusterLength;
591 const UChar* markCharactersEnd = iterator.characters() + cluster Length;
592 while (markCharactersEnd < normalizedBufferEnd) {
593 UChar32 nextCharacter;
594 int nextCharacterLength = 0;
595 U16_NEXT(markCharactersEnd, nextCharacterLength, normalizedB ufferEnd - markCharactersEnd, nextCharacter);
596 if (!(U_GET_GC_MASK(nextCharacter) & U_GC_M_MASK))
597 break;
598 markLength += nextCharacterLength;
599 markCharactersEnd += nextCharacterLength;
600 }
601
602 if (currentFontData->canRenderCombiningCharacterSequence(current CharacterPosition, markCharactersEnd - currentCharacterPosition)) {
603 clusterLength = markLength;
604 continue;
605 }
606 }
607
608 nextFontData = m_font->glyphDataForCharacter(character, false).fontD ata;
609 nextScript = uscript_getScript(character, &errorCode);
610 if (U_FAILURE(errorCode))
611 return false;
612 if ((nextFontData != currentFontData) || ((currentScript != nextScri pt) && (nextScript != USCRIPT_INHERITED) && (!uscript_hasScript(character, curre ntScript))))
613 break;
614 if (nextScript == USCRIPT_INHERITED)
615 nextScript = currentScript;
616 currentCharacterPosition = iterator.characters();
617 }
618 unsigned numCharactersOfCurrentRun = iterator.currentCharacter() - start IndexOfCurrentRun;
619 hb_script_t script = hb_icu_script_to_script(currentScript);
620 m_harfBuzzRuns.append(HarfBuzzRun::create(currentFontData, startIndexOfC urrentRun, numCharactersOfCurrentRun, m_run.direction(), script));
621 currentFontData = nextFontData;
622 startIndexOfCurrentRun = iterator.currentCharacter();
623 } while (iterator.consume(character, clusterLength));
624
625 return !m_harfBuzzRuns.isEmpty();
626 }
627
628 static const uint16_t* toUint16(const UChar* src)
629 {
630 // FIXME: This relies on undefined behavior however it works on the
631 // current versions of all compilers we care about and avoids making
632 // a copy of the string.
633 COMPILE_ASSERT(sizeof(UChar) == sizeof(uint16_t), UChar_is_the_same_size_as_ uint16_t);
634 return reinterpret_cast<const uint16_t*>(src);
635 }
636
637 bool HarfBuzzShaper::shapeHarfBuzzRuns(bool shouldSetDirection)
638 {
639 HarfBuzzScopedPtr<hb_buffer_t> harfBuzzBuffer(hb_buffer_create(), hb_buffer_ destroy);
640
641 hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_funcs() );
642 HarfBuzzRunCache& runCache = harfBuzzRunCache();
643
644 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
645 unsigned runIndex = m_run.rtl() ? m_harfBuzzRuns.size() - i - 1 : i;
646 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
647 const SimpleFontData* currentFontData = currentRun->fontData();
648 if (currentFontData->isSVGFont())
649 return false;
650
651 FontPlatformData* platformData = const_cast<FontPlatformData*>(&currentF ontData->platformData());
652 HarfBuzzFace* face = platformData->harfBuzzFace();
653 if (!face)
654 return false;
655
656 hb_buffer_set_script(harfBuzzBuffer.get(), currentRun->script());
657 if (shouldSetDirection)
658 hb_buffer_set_direction(harfBuzzBuffer.get(), currentRun->rtl() ? HB _DIRECTION_RTL : HB_DIRECTION_LTR);
659 else
660 // Leaving direction to HarfBuzz to guess is *really* bad, but will do for now.
661 hb_buffer_guess_segment_properties(harfBuzzBuffer.get());
662
663 hb_segment_properties_t props;
664 hb_buffer_get_segment_properties(harfBuzzBuffer.get(), &props);
665
666 const UChar* src = m_normalizedBuffer.get() + currentRun->startIndex();
667 std::wstring key(src, src + currentRun->numCharacters());
668
669 CachedShapingResults* cachedResults = runCache.find(key);
670 if (cachedResults) {
671 if (cachedResults->dir == props.direction && cachedResults->font == *m_font) {
672 currentRun->applyShapeResult(cachedResults->buffer);
673 setGlyphPositionsForHarfBuzzRun(currentRun, cachedResults->buffe r);
674
675 hb_buffer_reset(harfBuzzBuffer.get());
676
677 runCache.moveToBack(cachedResults);
678
679 continue;
680 }
681
682 runCache.remove(cachedResults);
683 }
684
685 // Add a space as pre-context to the buffer. This prevents showing dotte d-circle
686 // for combining marks at the beginning of runs.
687 static const uint16_t preContext = ' ';
688 hb_buffer_add_utf16(harfBuzzBuffer.get(), &preContext, 1, 1, 0);
689
690 if (m_font->isSmallCaps() && u_islower(m_normalizedBuffer[currentRun->st artIndex()])) {
691 String upperText = String(m_normalizedBuffer.get() + currentRun->sta rtIndex(), currentRun->numCharacters()).upper();
692 currentFontData = m_font->glyphDataForCharacter(upperText[0], false, SmallCapsVariant).fontData;
693 ASSERT(!upperText.is8Bit()); // m_normalizedBuffer is 16 bit, theref ore upperText is 16 bit, even after we call makeUpper().
694 hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(upperText.charact ers16()), currentRun->numCharacters(), 0, currentRun->numCharacters());
695 } else {
696 hb_buffer_add_utf16(harfBuzzBuffer.get(), toUint16(m_normalizedBuffe r.get() + currentRun->startIndex()), currentRun->numCharacters(), 0, currentRun- >numCharacters());
697 }
698
699 if (m_font->fontDescription().orientation() == Vertical)
700 face->setScriptForVerticalGlyphSubstitution(harfBuzzBuffer.get());
701
702 HarfBuzzScopedPtr<hb_font_t> harfBuzzFont(face->createFont(), hb_font_de stroy);
703
704 hb_shape(harfBuzzFont.get(), harfBuzzBuffer.get(), m_features.isEmpty() ? 0 : m_features.data(), m_features.size());
705 currentRun->applyShapeResult(harfBuzzBuffer.get());
706 setGlyphPositionsForHarfBuzzRun(currentRun, harfBuzzBuffer.get());
707
708 runCache.insert(key, new CachedShapingResults(harfBuzzBuffer.get(), m_fo nt, props.direction));
709
710 harfBuzzBuffer.set(hb_buffer_create());
711 hb_buffer_set_unicode_funcs(harfBuzzBuffer.get(), hb_icu_get_unicode_fun cs());
712 }
713
714 return true;
715 }
716
717 void HarfBuzzShaper::setGlyphPositionsForHarfBuzzRun(HarfBuzzRun* currentRun, hb _buffer_t* harfBuzzBuffer)
718 {
719 const SimpleFontData* currentFontData = currentRun->fontData();
720 hb_glyph_info_t* glyphInfos = hb_buffer_get_glyph_infos(harfBuzzBuffer, 0);
721 hb_glyph_position_t* glyphPositions = hb_buffer_get_glyph_positions(harfBuzz Buffer, 0);
722
723 unsigned numGlyphs = currentRun->numGlyphs();
724 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
725 float totalAdvance = 0;
726
727 // HarfBuzz returns the shaping result in visual order. We need not to flip for RTL.
728 for (size_t i = 0; i < numGlyphs; ++i) {
729 bool runEnd = i + 1 == numGlyphs;
730 uint16_t glyph = glyphInfos[i].codepoint;
731 float offsetX = harfBuzzPositionToFloat(glyphPositions[i].x_offset);
732 float offsetY = -harfBuzzPositionToFloat(glyphPositions[i].y_offset);
733 float advance = harfBuzzPositionToFloat(glyphPositions[i].x_advance);
734
735 unsigned currentCharacterIndex = currentRun->startIndex() + glyphInfos[i ].cluster;
736 bool isClusterEnd = runEnd || glyphInfos[i].cluster != glyphInfos[i + 1] .cluster;
737 float spacing = 0;
738
739 glyphToCharacterIndexes[i] = glyphInfos[i].cluster;
740
741 if (isClusterEnd && !Font::treatAsZeroWidthSpace(m_normalizedBuffer[curr entCharacterIndex]))
742 spacing += m_letterSpacing;
743
744 if (isClusterEnd && isWordEnd(currentCharacterIndex))
745 spacing += determineWordBreakSpacing();
746
747 if (currentFontData->isZeroWidthSpaceGlyph(glyph)) {
748 currentRun->setGlyphAndPositions(i, glyph, 0, 0, 0);
749 continue;
750 }
751
752 advance += spacing;
753 if (m_run.rtl()) {
754 // In RTL, spacing should be added to left side of glyphs.
755 offsetX += spacing;
756 if (!isClusterEnd)
757 offsetX += m_letterSpacing;
758 }
759
760 currentRun->setGlyphAndPositions(i, glyph, advance, offsetX, offsetY);
761
762 totalAdvance += advance;
763 }
764 currentRun->setWidth(totalAdvance > 0.0 ? totalAdvance : 0.0);
765 m_totalWidth += currentRun->width();
766 }
767
768 void HarfBuzzShaper::fillGlyphBufferFromHarfBuzzRun(GlyphBuffer* glyphBuffer, Ha rfBuzzRun* currentRun, FloatPoint& firstOffsetOfNextRun)
769 {
770 FloatPoint* offsets = currentRun->offsets();
771 uint16_t* glyphs = currentRun->glyphs();
772 float* advances = currentRun->advances();
773 unsigned numGlyphs = currentRun->numGlyphs();
774 uint16_t* glyphToCharacterIndexes = currentRun->glyphToCharacterIndexes();
775
776 for (unsigned i = 0; i < numGlyphs; ++i) {
777 uint16_t currentCharacterIndex = currentRun->startIndex() + glyphToChara cterIndexes[i];
778 FloatPoint& currentOffset = offsets[i];
779 FloatPoint& nextOffset = (i == numGlyphs - 1) ? firstOffsetOfNextRun : o ffsets[i + 1];
780 float glyphAdvanceX = advances[i] + nextOffset.x() - currentOffset.x();
781 float glyphAdvanceY = nextOffset.y() - currentOffset.y();
782 if (m_run.rtl()) {
783 if (currentCharacterIndex >= m_toIndex)
784 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
785 else if (currentCharacterIndex >= m_fromIndex)
786 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphB ufferAdvance(glyphAdvanceX, glyphAdvanceY));
787 } else {
788 if (currentCharacterIndex < m_fromIndex)
789 m_startOffset.move(glyphAdvanceX, glyphAdvanceY);
790 else if (currentCharacterIndex < m_toIndex)
791 glyphBuffer->add(glyphs[i], currentRun->fontData(), createGlyphB ufferAdvance(glyphAdvanceX, glyphAdvanceY));
792 }
793 }
794 }
795
796 bool HarfBuzzShaper::fillGlyphBuffer(GlyphBuffer* glyphBuffer)
797 {
798 unsigned numRuns = m_harfBuzzRuns.size();
799 if (m_run.rtl()) {
800 m_startOffset = m_harfBuzzRuns.last()->offsets()[0];
801 for (int runIndex = numRuns - 1; runIndex >= 0; --runIndex) {
802 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
803 FloatPoint firstOffsetOfNextRun = !runIndex ? FloatPoint() : m_harfB uzzRuns[runIndex - 1]->offsets()[0];
804 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetO fNextRun);
805 }
806 } else {
807 m_startOffset = m_harfBuzzRuns.first()->offsets()[0];
808 for (unsigned runIndex = 0; runIndex < numRuns; ++runIndex) {
809 HarfBuzzRun* currentRun = m_harfBuzzRuns[runIndex].get();
810 FloatPoint firstOffsetOfNextRun = runIndex == numRuns - 1 ? FloatPoi nt() : m_harfBuzzRuns[runIndex + 1]->offsets()[0];
811 fillGlyphBufferFromHarfBuzzRun(glyphBuffer, currentRun, firstOffsetO fNextRun);
812 }
813 }
814 return glyphBuffer->size();
815 }
816
817 int HarfBuzzShaper::offsetForPosition(float targetX)
818 {
819 int charactersSoFar = 0;
820 float currentX = 0;
821
822 if (m_run.rtl()) {
823 charactersSoFar = m_normalizedBufferLength;
824 for (int i = m_harfBuzzRuns.size() - 1; i >= 0; --i) {
825 charactersSoFar -= m_harfBuzzRuns[i]->numCharacters();
826 float nextX = currentX + m_harfBuzzRuns[i]->width();
827 float offsetForRun = targetX - currentX;
828 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
829 // The x value in question is within this script run.
830 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun);
831 return charactersSoFar + index;
832 }
833 currentX = nextX;
834 }
835 } else {
836 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
837 float nextX = currentX + m_harfBuzzRuns[i]->width();
838 float offsetForRun = targetX - currentX;
839 if (offsetForRun >= 0 && offsetForRun <= m_harfBuzzRuns[i]->width()) {
840 const unsigned index = m_harfBuzzRuns[i]->characterIndexForXPosi tion(offsetForRun);
841 return charactersSoFar + index;
842 }
843 charactersSoFar += m_harfBuzzRuns[i]->numCharacters();
844 currentX = nextX;
845 }
846 }
847
848 return charactersSoFar;
849 }
850
851 FloatRect HarfBuzzShaper::selectionRect(const FloatPoint& point, int height, int from, int to)
852 {
853 float currentX = 0;
854 float fromX = 0;
855 float toX = 0;
856 bool foundFromX = false;
857 bool foundToX = false;
858
859 if (m_run.rtl())
860 currentX = m_totalWidth;
861 for (unsigned i = 0; i < m_harfBuzzRuns.size(); ++i) {
862 if (m_run.rtl())
863 currentX -= m_harfBuzzRuns[i]->width();
864 int numCharacters = m_harfBuzzRuns[i]->numCharacters();
865 if (!foundFromX && from >= 0 && from < numCharacters) {
866 fromX = m_harfBuzzRuns[i]->xPositionForOffset(from) + currentX;
867 foundFromX = true;
868 } else
869 from -= numCharacters;
870
871 if (!foundToX && to >= 0 && to < numCharacters) {
872 toX = m_harfBuzzRuns[i]->xPositionForOffset(to) + currentX;
873 foundToX = true;
874 } else
875 to -= numCharacters;
876
877 if (foundFromX && foundToX)
878 break;
879 if (!m_run.rtl())
880 currentX += m_harfBuzzRuns[i]->width();
881 }
882
883 // The position in question might be just after the text.
884 if (!foundFromX)
885 fromX = 0;
886 if (!foundToX)
887 toX = m_run.rtl() ? 0 : m_totalWidth;
888
889 // Using floorf() and roundf() as the same as mac port.
890 if (fromX < toX)
891 return FloatRect(floorf(point.x() + fromX), point.y(), roundf(toX - from X), height);
892 return FloatRect(floorf(point.x() + toX), point.y(), roundf(fromX - toX), he ight);
893 }
894
895 } // namespace WebCore
OLDNEW
« no previous file with comments | « Source/core/platform/graphics/harfbuzz/HarfBuzzShaper.h ('k') | Source/core/platform/graphics/linux/FontCacheLinux.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698