Home | History | Annotate | Download | only in ports
      1 
      2 /*
      3  * Copyright 2009 The Android Open Source Project
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  */
      8 
      9 
     10 #include "SkHarfBuzzFont.h"
     11 #include "SkFontHost.h"
     12 #include "SkPaint.h"
     13 #include "SkPath.h"
     14 
     15 // HB_Fixed is a 26.6 fixed point format.
     16 static inline HB_Fixed SkScalarToHarfbuzzFixed(SkScalar value) {
     17 #ifdef SK_SCALAR_IS_FLOAT
     18     return static_cast<HB_Fixed>(value * 64);
     19 #else
     20     // convert .16 to .6
     21     return value >> (16 - 6);
     22 #endif
     23 }
     24 
     25 static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters,
     26                               hb_uint32 length, HB_Glyph* glyphs,
     27                               hb_uint32* glyphsSize, HB_Bool isRTL) {
     28     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData);
     29     SkPaint paint;
     30 
     31     paint.setTypeface(font->getTypeface());
     32     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
     33     int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t),
     34                                        reinterpret_cast<uint16_t*>(glyphs));
     35 
     36     // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
     37     // |glyphs| array needs to be converted.
     38     for (int i = numGlyphs - 1; i >= 0; --i) {
     39         uint16_t value;
     40         // We use a memcpy to avoid breaking strict aliasing rules.
     41         memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(uint16_t));
     42         glyphs[i] = value;
     43     }
     44 
     45     *glyphsSize = numGlyphs;
     46     return 1;
     47 }
     48 
     49 static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs,
     50                          hb_uint32 numGlyphs, HB_Fixed* advances, int flags) {
     51     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData);
     52     SkPaint paint;
     53 
     54     font->setupPaint(&paint);
     55     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     56 
     57     SkAutoMalloc storage(numGlyphs * (sizeof(SkScalar) + sizeof(uint16_t)));
     58     SkScalar* scalarWidths = reinterpret_cast<SkScalar*>(storage.get());
     59     uint16_t* glyphs16 = reinterpret_cast<uint16_t*>(scalarWidths + numGlyphs);
     60 
     61     // convert HB 32bit glyphs to skia's 16bit
     62     for (hb_uint32 i = 0; i < numGlyphs; ++i) {
     63         glyphs16[i] = SkToU16(glyphs[i]);
     64     }
     65     paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarWidths);
     66 
     67     for (hb_uint32 i = 0; i < numGlyphs; ++i) {
     68         advances[i] = SkScalarToHarfbuzzFixed(scalarWidths[i]);
     69     }
     70 }
     71 
     72 static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters,
     73                          hb_uint32 length) {
     74     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData);
     75     SkPaint paint;
     76 
     77     paint.setTypeface(font->getTypeface());
     78     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
     79     return paint.containsText(characters, length * sizeof(uint16_t));
     80 }
     81 
     82 static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags,
     83                                 hb_uint32 index, HB_Fixed* xPos, HB_Fixed* yPos,
     84                                 hb_uint32* resultingNumPoints) {
     85     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData);
     86     SkPaint paint;
     87 
     88     font->setupPaint(&paint);
     89     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     90     if (flags & HB_ShaperFlag_UseDesignMetrics) {
     91         paint.setHinting(SkPaint::kNo_Hinting);
     92     }
     93 
     94     SkPath path;
     95     uint16_t glyph16 = SkToU16(glyph);
     96     paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
     97     int numPoints = path.countPoints();
     98     if (index >= numPoints) {
     99         return HB_Err_Invalid_SubTable;
    100     }
    101 
    102     SkPoint pt = path.getPoint(index);
    103     *xPos = SkScalarToHarfbuzzFixed(pt.fX);
    104     *yPos = SkScalarToHarfbuzzFixed(pt.fY);
    105     *resultingNumPoints = numPoints;
    106 
    107     return HB_Err_Ok;
    108 }
    109 
    110 static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph,
    111                             HB_GlyphMetrics* metrics) {
    112     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData);
    113     SkPaint paint;
    114 
    115     font->setupPaint(&paint);
    116     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    117 
    118     SkScalar width;
    119     SkRect bounds;
    120     uint16_t glyph16 = SkToU16(glyph);
    121     paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
    122 
    123     metrics->x = SkScalarToHarfbuzzFixed(bounds.fLeft);
    124     metrics->y = SkScalarToHarfbuzzFixed(bounds.fTop);
    125     metrics->width = SkScalarToHarfbuzzFixed(bounds.width());
    126     metrics->height = SkScalarToHarfbuzzFixed(bounds.height());
    127 
    128     metrics->xOffset = SkScalarToHarfbuzzFixed(width);
    129     // We can't actually get the |y| correct because Skia doesn't export
    130     // the vertical advance. However, nor we do ever render vertical text at
    131     // the moment so it's unimportant.
    132     metrics->yOffset = 0;
    133 }
    134 
    135 static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
    136 {
    137     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(hbFont->userData);
    138     SkPaint paint;
    139     SkPaint::FontMetrics skiaMetrics;
    140 
    141     font->setupPaint(&paint);
    142     paint.getFontMetrics(&skiaMetrics);
    143 
    144     switch (metric) {
    145     case HB_FontAscent:
    146         return SkScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
    147     default:
    148         SkDebugf("--- unknown harfbuzz metric enum %d\n", metric);
    149         return 0;
    150     }
    151 }
    152 
    153 static HB_FontClass gSkHarfBuzzFontClass = {
    154     stringToGlyphs,
    155     glyphsToAdvances,
    156     canRender,
    157     getOutlinePoint,
    158     getGlyphMetrics,
    159     getFontMetric,
    160 };
    161 
    162 const HB_FontClass& SkHarfBuzzFont::GetFontClass() {
    163     return gSkHarfBuzzFontClass;
    164 }
    165 
    166 HB_Error SkHarfBuzzFont::GetFontTableFunc(void* voidface, const HB_Tag tag,
    167                                           HB_Byte* buffer, HB_UInt* len) {
    168     SkHarfBuzzFont* font = reinterpret_cast<SkHarfBuzzFont*>(voidface);
    169     uint32_t uniqueID = SkTypeface::UniqueID(font->getTypeface());
    170 
    171     const size_t tableSize = SkFontHost::GetTableSize(uniqueID, tag);
    172     if (!tableSize) {
    173         return HB_Err_Invalid_Argument;
    174     }
    175     // If Harfbuzz specified a NULL buffer then it's asking for the size.
    176     if (!buffer) {
    177         *len = tableSize;
    178         return HB_Err_Ok;
    179     }
    180 
    181     if (*len < tableSize) {
    182         // is this right, or should we just copy less than the full table?
    183         return HB_Err_Invalid_Argument;
    184     }
    185     SkFontHost::GetTableData(uniqueID, tag, 0, tableSize, buffer);
    186     return HB_Err_Ok;
    187 }
    188 
    189