1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/skia/trunk/src/ports/SkHarfBuzzFont.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,182 @@ 1.4 + 1.5 +/* 1.6 + * Copyright 2009 The Android Open Source Project 1.7 + * 1.8 + * Use of this source code is governed by a BSD-style license that can be 1.9 + * found in the LICENSE file. 1.10 + */ 1.11 + 1.12 + 1.13 +#include "SkHarfBuzzFont.h" 1.14 +#include "SkFontHost.h" 1.15 +#include "SkPaint.h" 1.16 +#include "SkPath.h" 1.17 + 1.18 +// HB_Fixed is a 26.6 fixed point format. 1.19 +static inline HB_Fixed SkScalarToHarfbuzzFixed(SkScalar value) { 1.20 + return static_cast<HB_Fixed>(value * 64); 1.21 +} 1.22 + 1.23 +static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, 1.24 + hb_uint32 length, HB_Glyph* glyphs, 1.25 + hb_uint32* glyphsSize, HB_Bool isRTL) { 1.26 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); 1.27 + SkPaint paint; 1.28 + 1.29 + paint.setTypeface(font->getTypeface()); 1.30 + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 1.31 + int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), 1.32 + reinterpret_cast<uint16_t*>(glyphs)); 1.33 + 1.34 + // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our 1.35 + // |glyphs| array needs to be converted. 1.36 + for (int i = numGlyphs - 1; i >= 0; --i) { 1.37 + uint16_t value; 1.38 + // We use a memcpy to avoid breaking strict aliasing rules. 1.39 + memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t)); 1.40 + glyphs[i] = value; 1.41 + } 1.42 + 1.43 + *glyphsSize = numGlyphs; 1.44 + return 1; 1.45 +} 1.46 + 1.47 +static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, 1.48 + hb_uint32 numGlyphs, HB_Fixed* advances, int flags) { 1.49 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); 1.50 + SkPaint paint; 1.51 + 1.52 + font->setupPaint(&paint); 1.53 + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1.54 + 1.55 + SkAutoMalloc storage(numGlyphs * (sizeof(SkScalar) + sizeof(uint16_t))); 1.56 + SkScalar* scalarWidths = reinterpret_cast<SkScalar*>(storage.get()); 1.57 + uint16_t* glyphs16 = reinterpret_cast<uint16_t*>(scalarWidths + numGlyphs); 1.58 + 1.59 + // convert HB 32bit glyphs to skia's 16bit 1.60 + for (hb_uint32 i = 0; i < numGlyphs; ++i) { 1.61 + glyphs16[i] = SkToU16(glyphs[i]); 1.62 + } 1.63 + paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarWidths); 1.64 + 1.65 + for (hb_uint32 i = 0; i < numGlyphs; ++i) { 1.66 + advances[i] = SkScalarToHarfbuzzFixed(scalarWidths[i]); 1.67 + } 1.68 +} 1.69 + 1.70 +static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, 1.71 + hb_uint32 length) { 1.72 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); 1.73 + SkPaint paint; 1.74 + 1.75 + paint.setTypeface(font->getTypeface()); 1.76 + paint.setTextEncoding(SkPaint::kUTF16_TextEncoding); 1.77 + return paint.containsText(characters, length * sizeof(uint16_t)); 1.78 +} 1.79 + 1.80 +static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, 1.81 + hb_uint32 index, HB_Fixed* xPos, HB_Fixed* yPos, 1.82 + hb_uint32* resultingNumPoints) { 1.83 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); 1.84 + SkPaint paint; 1.85 + 1.86 + font->setupPaint(&paint); 1.87 + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1.88 + if (flags & HB_ShaperFlag_UseDesignMetrics) { 1.89 + paint.setHinting(SkPaint::kNo_Hinting); 1.90 + } 1.91 + 1.92 + SkPath path; 1.93 + uint16_t glyph16 = SkToU16(glyph); 1.94 + paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); 1.95 + int numPoints = path.countPoints(); 1.96 + if (index >= numPoints) { 1.97 + return HB_Err_Invalid_SubTable; 1.98 + } 1.99 + 1.100 + SkPoint pt = path.getPoint(index); 1.101 + *xPos = SkScalarToHarfbuzzFixed(pt.fX); 1.102 + *yPos = SkScalarToHarfbuzzFixed(pt.fY); 1.103 + *resultingNumPoints = numPoints; 1.104 + 1.105 + return HB_Err_Ok; 1.106 +} 1.107 + 1.108 +static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, 1.109 + HB_GlyphMetrics* metrics) { 1.110 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); 1.111 + SkPaint paint; 1.112 + 1.113 + font->setupPaint(&paint); 1.114 + paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding); 1.115 + 1.116 + SkScalar width; 1.117 + SkRect bounds; 1.118 + uint16_t glyph16 = SkToU16(glyph); 1.119 + paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds); 1.120 + 1.121 + metrics->x = SkScalarToHarfbuzzFixed(bounds.fLeft); 1.122 + metrics->y = SkScalarToHarfbuzzFixed(bounds.fTop); 1.123 + metrics->width = SkScalarToHarfbuzzFixed(bounds.width()); 1.124 + metrics->height = SkScalarToHarfbuzzFixed(bounds.height()); 1.125 + 1.126 + metrics->xOffset = SkScalarToHarfbuzzFixed(width); 1.127 + // We can't actually get the |y| correct because Skia doesn't export 1.128 + // the vertical advance. However, nor we do ever render vertical text at 1.129 + // the moment so it's unimportant. 1.130 + metrics->yOffset = 0; 1.131 +} 1.132 + 1.133 +static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric) 1.134 +{ 1.135 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData); 1.136 + SkPaint paint; 1.137 + SkPaint::FontMetrics skiaMetrics; 1.138 + 1.139 + font->setupPaint(&paint); 1.140 + paint.getFontMetrics(&skiaMetrics); 1.141 + 1.142 + switch (metric) { 1.143 + case HB_FontAscent: 1.144 + return SkScalarToHarfbuzzFixed(-skiaMetrics.fAscent); 1.145 + default: 1.146 + SkDebugf("--- unknown harfbuzz metric enum %d\n", metric); 1.147 + return 0; 1.148 + } 1.149 +} 1.150 + 1.151 +static HB_FontClass gSkHarfBuzzFontClass = { 1.152 + stringToGlyphs, 1.153 + glyphsToAdvances, 1.154 + canRender, 1.155 + getOutlinePoint, 1.156 + getGlyphMetrics, 1.157 + getFontMetric, 1.158 +}; 1.159 + 1.160 +const HB_FontClass& SkHarfBuzzFont::GetFontClass() { 1.161 + return gSkHarfBuzzFontClass; 1.162 +} 1.163 + 1.164 +HB_Error SkHarfBuzzFont::GetFontTableFunc(void* voidface, const HB_Tag tag, 1.165 + HB_Byte* buffer, HB_UInt* len) { 1.166 + SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(voidface); 1.167 + SkTypeface* typeface = font->getTypeface(); 1.168 + 1.169 + const size_t tableSize = typeface->getTableSize(tag); 1.170 + if (!tableSize) { 1.171 + return HB_Err_Invalid_Argument; 1.172 + } 1.173 + // If Harfbuzz specified a NULL buffer then it's asking for the size. 1.174 + if (!buffer) { 1.175 + *len = tableSize; 1.176 + return HB_Err_Ok; 1.177 + } 1.178 + 1.179 + if (*len < tableSize) { 1.180 + // is this right, or should we just copy less than the full table? 1.181 + return HB_Err_Invalid_Argument; 1.182 + } 1.183 + typeface->getTableData(tag, 0, tableSize, buffer); 1.184 + return HB_Err_Ok; 1.185 +}