static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL) { FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData); SkPaint paint; font->setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); unsigned codepoints = 0; for (hb_uint32 i = 0; i < length; i++) { if (!SkUTF16_IsHighSurrogate(characters[i])) codepoints++; if (codepoints > *glyphsSize) return 0; } int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs)); // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our // |glyphs| array needs to be converted. for (int i = numGlyphs - 1; i >= 0; --i) { uint16_t value; // We use a memcpy to avoid breaking strict aliasing rules. memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t)); glyphs[i] = value; } *glyphsSize = numGlyphs; return 1; }
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; } SkPaint paint; fontData->platformData().setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); #if OS(WINDOWS) // FIXME: For some reason SkAutoSTMalloc fails to link on Windows. // SkAutoSTArray works fine though... SkAutoSTArray<GlyphPage::size, uint16_t> glyphStorage(length); #else SkAutoSTMalloc<GlyphPage::size, uint16_t> glyphStorage(length); #endif uint16_t* glyphs = glyphStorage.get(); // textToGlyphs takes a byte count, not a glyph count so we multiply by two. unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs); if (count != length) { SkDebugf("%s count != length\n", __FUNCTION__); return false; } unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero for (unsigned i = 0; i < length; i++) { setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL); allGlyphs |= glyphs[i]; } return allGlyphs != 0; }
static SkUnichar SkUTF16BE_NextUnichar(const uint16_t** srcPtr) { SkASSERT(srcPtr && *srcPtr); const uint16_t* src = *srcPtr; SkUnichar c = SkEndian_SwapBE16(*src++); SkASSERT(!SkUTF16_IsLowSurrogate(c)); if (SkUTF16_IsHighSurrogate(c)) { unsigned c2 = SkEndian_SwapBE16(*src++); SkASSERT(SkUTF16_IsLowSurrogate(c2)); c = (c << 10) + c2 + (0x10000 - (0xD800 << 10) - 0xDC00); } *srcPtr = src; return c; }
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; } SkPaint paint; fontData->platformData().setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length); uint16_t* glyphs = glyphStorage.get(); unsigned count = paint.textToGlyphs(buffer, bufferLength << 1, glyphs); if (count != length) { SkDebugf("%s count != length\n", __FUNCTION__); return false; } unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero // search for emoji. If we knew for sure that buffer was a contiguous range // of chars, we could quick-reject the range to avoid this loop (usually) if (EmojiFont::IsAvailable()) { const UChar* curr = buffer; for (unsigned i = 0; i < length; i++) { SkUnichar uni = SkUTF16_NextUnichar(&curr); uint16_t glyphID = glyphs[i]; // only sniff if the normal font failed to recognize it if (!glyphID) glyphID = EmojiFont::UnicharToGlyph(uni); setGlyphDataForIndex(offset + i, glyphID, fontData); allGlyphs |= glyphID; } } else { for (unsigned i = 0; i < length; i++) { uint16_t glyphID = glyphs[i]; setGlyphDataForIndex(offset + i, glyphID, fontData); allGlyphs |= glyphID; } } return allGlyphs != 0; }
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; } SkPaint paint; fontData->platformData().setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length); uint16_t* glyphs = glyphStorage.get(); // textToGlyphs takes a byte count, not a glyph count so we multiply by two. unsigned count = paint.textToGlyphs(buffer, bufferLength * 2, glyphs); if (count != length) { SkDebugf("%s count != length\n", __FUNCTION__); return false; } if (fontData->hasVerticalGlyphs()) { bool lookVariants = false; for (unsigned i = 0; i < bufferLength; ++i) { if (!Font::isCJKIdeograph(buffer[i])) { lookVariants = true; continue; } } if (lookVariants) substituteWithVerticalGlyphs(fontData, glyphs, bufferLength); } unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero for (unsigned i = 0; i < length; i++) { setGlyphDataForIndex(offset + i, glyphs[i], glyphs[i] ? fontData : NULL); allGlyphs |= glyphs[i]; } return allGlyphs != 0; }
bool SimpleFontData::fillGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength) const { if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; } SkAutoSTMalloc<GlyphPage::size, uint16_t> glyphStorage(length); uint16_t* glyphs = glyphStorage.get(); SkTypeface* typeface = platformData().typeface(); typeface->charsToGlyphs(buffer, SkTypeface::kUTF16_Encoding, glyphs, length); bool haveGlyphs = false; for (unsigned i = 0; i < length; i++) { if (glyphs[i]) { pageToFill->setGlyphDataForIndex(offset + i, glyphs[i], this); haveGlyphs = true; } } return haveGlyphs; }
bool GlyphPage::fill(unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) { if (SkUTF16_IsHighSurrogate(buffer[bufferLength-1])) { SkDebugf("%s last char is high-surrogate", __FUNCTION__); return false; } SkPaint paint; fontData->platformData().setupPaint(&paint); paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); SkAutoSTMalloc <GlyphPage::size, uint16_t> glyphStorage(length); uint16_t* glyphs = glyphStorage.get(); UChar *textBuffer = buffer; UChar vTextBuffer[bufferLength]; if (fontData->platformData().orientation() == Vertical && !fontData->hasVerticalGlyphs()) { // Convert to vertical form if there is no vertical glyphs. for (unsigned i = 0; i < bufferLength; ++i) { vTextBuffer[i] = VerticalTextMap::getVerticalForm(buffer[i]); if (!vTextBuffer[i]) vTextBuffer[i] = buffer[i]; } textBuffer = vTextBuffer; } unsigned count = paint.textToGlyphs(textBuffer, bufferLength << 1, glyphs); if (count != length) { SkDebugf("%s count != length\n", __FUNCTION__); return false; } if (fontData->hasVerticalGlyphs()) { bool lookVariants = false; for (unsigned i = 0; i < bufferLength; ++i) { if (!Font::isCJKIdeograph(textBuffer[i])) { lookVariants = true; continue; } } if (lookVariants) substituteWithVerticalGlyphs(fontData->platformData(), glyphs, bufferLength); } unsigned allGlyphs = 0; // track if any of the glyphIDs are non-zero // search for emoji. If we knew for sure that buffer was a contiguous range // of chars, we could quick-reject the range to avoid this loop (usually) if (EmojiFont::IsAvailable()) { const UChar* curr = textBuffer; for (unsigned i = 0; i < length; i++) { SkUnichar uni = SkUTF16_NextUnichar(&curr); uint16_t glyphID = glyphs[i]; // only sniff if the normal font failed to recognize it if (!glyphID) glyphID = EmojiFont::UnicharToGlyph(uni); setGlyphDataForIndex(offset + i, glyphID, fontData); allGlyphs |= glyphID; } } else { for (unsigned i = 0; i < length; i++) { uint16_t glyphID = glyphs[i]; setGlyphDataForIndex(offset + i, glyphID, fontData); allGlyphs |= glyphID; } } return allGlyphs != 0; }