diff options
author | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-10-25 17:49:08 +0000 |
---|---|---|
committer | bungeman@google.com <bungeman@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81> | 2013-10-25 17:49:08 +0000 |
commit | 72b8cb2320dddc6e006a2857746014e607e9e151 (patch) | |
tree | 08f4f5ba330c1e01ad395acf79d40642087771a8 | |
parent | cc17673032df07652a5b5cca5ee1994d6e04aa3d (diff) |
onCharsToGlyphs to handle non-bmp on Mac.
CTFontGetGlyphsForCharacters is a strange API for non-bmp code points.
R=caryclark@google.com
Review URL: https://codereview.chromium.org/43463005
git-svn-id: http://skia.googlecode.com/svn/trunk@11965 2bbb7eff-a529-9590-31e7-b0007b416f81
-rwxr-xr-x | src/ports/SkFontHost_mac.cpp | 93 | ||||
-rw-r--r-- | tests/FontHostTest.cpp | 5 |
2 files changed, 65 insertions, 33 deletions
diff --git a/src/ports/SkFontHost_mac.cpp b/src/ports/SkFontHost_mac.cpp index 0b77aa20f7..fb56119980 100755 --- a/src/ports/SkFontHost_mac.cpp +++ b/src/ports/SkFontHost_mac.cpp @@ -946,19 +946,16 @@ unsigned SkScalerContext_Mac::generateGlyphCount(void) { 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 @@ void SkTypeface_Mac::onGetFontDescriptor(SkFontDescriptor* desc, } 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; } diff --git a/tests/FontHostTest.cpp b/tests/FontHostTest.cpp index 923b309aef..a7ecc5a9dc 100644 --- a/tests/FontHostTest.cpp +++ b/tests/FontHostTest.cpp @@ -72,7 +72,7 @@ static void test_countGlyphs(skiatest::Reporter* reporter, SkTypeface* face) { SkDebugf("--- typeface returned 0 glyphs [%X]\n", face->uniqueID()); } } -#if 0 + // The following three are all the same code points in various encodings. static uint8_t utf8Chars[] = { 0x61, 0xE4, 0xB8, 0xAD, 0xD0, 0xAF, 0xD7, 0x99, 0xD7, 0x95, 0xF0, 0x9D, 0x84, 0x9E, 0x61 }; static uint16_t utf16Chars[] = { 0x0061, 0x4E2D, 0x042F, 0x05D9, 0x05D5, 0xD834, 0xDD1E, 0x0061 }; @@ -115,7 +115,6 @@ static void test_charsToGlyphs(skiatest::Reporter* reporter, SkTypeface* face) { } } } -#endif static void test_fontstream(skiatest::Reporter* reporter, SkStream* stream, int ttcIndex) { @@ -230,7 +229,7 @@ static void test_tables(skiatest::Reporter* reporter) { test_tables(reporter, face); test_unitsPerEm(reporter, face); test_countGlyphs(reporter, face); - //test_charsToGlyphs(reporter, face); + test_charsToGlyphs(reporter, face); } } } |