Index: src/ports/SkFontHost_mac.cpp |
=================================================================== |
--- src/ports/SkFontHost_mac.cpp (revision 11960) |
+++ src/ports/SkFontHost_mac.cpp (working copy) |
@@ -946,19 +946,16 @@ |
uint16_t SkScalerContext_Mac::generateCharToGlyph(SkUnichar uni) { |
CGGlyph cgGlyph[2]; |
- UniChar theChar[2]; |
+ UniChar theChar[2]; // UniChar is a UTF-16 16-bit code unit. |
// Get the glyph |
size_t numUniChar = SkUTF16_FromUnichar(uni, theChar); |
SkASSERT(sizeof(CGGlyph) <= sizeof(uint16_t)); |
- // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points. |
- // When a surragate pair is detected, the glyph index used is the index of the first |
- // UniChar of the pair (the lower location). |
- if (!CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar)) { |
- cgGlyph[0] = 0; |
- } |
- |
+ // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: |
+ // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. |
+ // It is documented that if a mapping is unavailable, the glyph will be set to 0. |
+ CTFontGetGlyphsForCharacters(fCTFont, theChar, cgGlyph, numUniChar); |
return cgGlyph[0]; |
} |
@@ -1920,53 +1917,89 @@ |
} |
int SkTypeface_Mac::onCharsToGlyphs(const void* chars, Encoding encoding, |
- uint16_t glyphs[], int glyphCount) const { |
- // UniChar is utf16 |
+ uint16_t glyphs[], int glyphCount) const |
+{ |
+ // Undocumented behavior of CTFontGetGlyphsForCharacters with non-bmp code points: |
+ // When a surrogate pair is detected, the glyph index used is the index of the high surrogate. |
+ // It is documented that if a mapping is unavailable, the glyph will be set to 0. |
+ |
SkAutoSTMalloc<1024, UniChar> charStorage; |
- const UniChar* src; |
+ const UniChar* src; // UniChar is a UTF-16 16-bit code unit. |
+ int srcCount; |
switch (encoding) { |
case kUTF8_Encoding: { |
- const char* u8 = (const char*)chars; |
- const UniChar* u16 = src = charStorage.reset(2 * glyphCount); |
+ const char* utf8 = reinterpret_cast<const char*>(chars); |
+ UniChar* utf16 = charStorage.reset(2 * glyphCount); |
+ src = utf16; |
for (int i = 0; i < glyphCount; ++i) { |
- SkUnichar uni = SkUTF8_NextUnichar(&u8); |
- int n = SkUTF16_FromUnichar(uni, (uint16_t*)u16); |
- u16 += n; |
+ SkUnichar uni = SkUTF8_NextUnichar(&utf8); |
+ utf16 += SkUTF16_FromUnichar(uni, utf16); |
} |
+ srcCount = utf16 - src; |
break; |
} |
- case kUTF16_Encoding: |
- src = (const UniChar*)chars; |
+ case kUTF16_Encoding: { |
+ src = reinterpret_cast<const UniChar*>(chars); |
+ int extra = 0; |
+ for (int i = 0; i < glyphCount; ++i) { |
+ if (SkUTF16_IsHighSurrogate(src[i + extra])) { |
+ ++extra; |
+ } |
+ } |
+ srcCount = glyphCount + extra; |
break; |
+ } |
case kUTF32_Encoding: { |
- const SkUnichar* u32 = (const SkUnichar*)chars; |
- const UniChar* u16 = src = charStorage.reset(2 * glyphCount); |
+ const SkUnichar* utf32 = reinterpret_cast<const SkUnichar*>(chars); |
+ UniChar* utf16 = charStorage.reset(2 * glyphCount); |
+ src = utf16; |
for (int i = 0; i < glyphCount; ++i) { |
- int n = SkUTF16_FromUnichar(u32[i], (uint16_t*)u16); |
- u16 += n; |
+ utf16 += SkUTF16_FromUnichar(utf32[i], utf16); |
} |
+ srcCount = utf16 - src; |
break; |
} |
} |
- // Our caller may not want glyphs for output, but we need to give that |
- // storage to CT, so we can walk it looking for the first non-zero. |
+ // If glyphs is NULL, CT still needs glyph storage for finding the first failure. |
+ // Also, if there are any non-bmp code points, the provided 'glyphs' storage will be inadequate. |
SkAutoSTMalloc<1024, uint16_t> glyphStorage; |
uint16_t* macGlyphs = glyphs; |
- if (NULL == macGlyphs) { |
- macGlyphs = glyphStorage.reset(glyphCount); |
+ if (NULL == macGlyphs || srcCount > glyphCount) { |
+ macGlyphs = glyphStorage.reset(srcCount); |
} |
- if (CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, glyphCount)) { |
+ bool allEncoded = CTFontGetGlyphsForCharacters(fFontRef, src, macGlyphs, srcCount); |
+ |
+ // If there were any non-bmp, then copy and compact. |
+ // If 'glyphs' is NULL, then compact glyphStorage in-place. |
+ // If all are bmp and 'glyphs' is non-NULL, 'glyphs' already contains the compact glyphs. |
+ // If some are non-bmp and 'glyphs' is non-NULL, copy and compact into 'glyphs'. |
+ uint16_t* compactedGlyphs = glyphs; |
+ if (NULL == compactedGlyphs) { |
+ compactedGlyphs = macGlyphs; |
+ } |
+ if (srcCount > glyphCount) { |
+ int extra = 0; |
+ for (int i = 0; i < glyphCount; ++i) { |
+ if (SkUTF16_IsHighSurrogate(src[i + extra])) { |
+ ++extra; |
+ } |
+ compactedGlyphs[i] = macGlyphs[i + extra]; |
+ } |
+ } |
+ |
+ if (allEncoded) { |
return glyphCount; |
} |
- // If we got false, then we need to manually look for first failure |
+ |
+ // If we got false, then we need to manually look for first failure. |
for (int i = 0; i < glyphCount; ++i) { |
- if (0 == macGlyphs[i]) { |
+ if (0 == compactedGlyphs[i]) { |
return i; |
} |
} |
- // odd to get here, as we expected CT to have returned true up front. |
+ // Odd to get here, as we expected CT to have returned true up front. |
return glyphCount; |
} |