Home | History | Annotate | Download | only in fonts
      1 /*
      2  * Copyright 2010, The Android Open Source Project
      3  * Copyright 2010, Google Inc. All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *  * Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  *  * Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 
     29 #include "FontPlatformData.h"
     30 
     31 #include <SkFontHost.h>
     32 #include <SkPaint.h>
     33 #include <SkPath.h>
     34 #include <SkPoint.h>
     35 #include <SkRect.h>
     36 #include <wtf/OwnArrayPtr.h>
     37 #include <wtf/PassOwnArrayPtr.h>
     38 
     39 extern "C" {
     40 #include "harfbuzz-shaper.h"
     41 }
     42 
     43 // This file implements the callbacks which Harfbuzz requires by using Skia
     44 // calls. See the Harfbuzz source for references about what these callbacks do.
     45 
     46 namespace WebCore {
     47 
     48 static HB_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
     49 {
     50     // HB_Fixed is a 26.6 fixed point format.
     51     return value * 64;
     52 }
     53 
     54 static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
     55 {
     56     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
     57     SkPaint paint;
     58 
     59     font->setupPaint(&paint);
     60     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
     61     int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), reinterpret_cast<uint16_t*>(glyphs));
     62 
     63     // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our
     64     // |glyphs| array needs to be converted.
     65     for (int i = numGlyphs - 1; i >= 0; --i) {
     66         uint16_t value;
     67         // We use a memcpy to avoid breaking strict aliasing rules.
     68         memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value));
     69         glyphs[i] = value;
     70     }
     71 
     72     *glyphsSize = numGlyphs;
     73     return 1;
     74 }
     75 
     76 static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags)
     77 {
     78     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
     79     SkPaint paint;
     80 
     81     font->setupPaint(&paint);
     82     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
     83 
     84     OwnArrayPtr<uint16_t> glyphs16 = adoptArrayPtr(new uint16_t[numGlyphs]);
     85     if (!glyphs16.get())
     86         return;
     87     for (unsigned i = 0; i < numGlyphs; ++i)
     88         glyphs16[i] = glyphs[i];
     89     paint.getTextWidths(glyphs16.get(), numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
     90 
     91     // The |advances| values which Skia outputs are SkScalars, which are floats
     92     // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format.
     93     // These two formats are both 32-bits long.
     94     for (unsigned i = 0; i < numGlyphs; ++i) {
     95         float value;
     96         // We use a memcpy to avoid breaking strict aliasing rules.
     97         memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value));
     98         advances[i] = SkiaScalarToHarfbuzzFixed(value);
     99     }
    100 }
    101 
    102 static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
    103 {
    104     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
    105     SkPaint paint;
    106 
    107     font->setupPaint(&paint);
    108     paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
    109 
    110     OwnArrayPtr<uint16_t> glyphs16 = adoptArrayPtr(new uint16_t[length]);
    111     glyphs16.get();
    112     int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t), glyphs16.get());
    113 
    114     for (int i = 0; i < numGlyphs; ++i) {
    115         if (!glyphs16[i])
    116             return false;
    117     }
    118 
    119     return true;
    120 }
    121 
    122 static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints)
    123 {
    124     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
    125     SkPaint paint;
    126 
    127     if (flags & HB_ShaperFlag_UseDesignMetrics)
    128         return HB_Err_Invalid_Argument;  // This is requesting pre-hinted positions. We can't support this.
    129 
    130     font->setupPaint(&paint);
    131     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    132     uint16_t glyph16 = glyph;
    133     SkPath path;
    134     paint.getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path);
    135     uint32_t numPoints = path.getPoints(0, 0);
    136     if (point >= numPoints)
    137         return HB_Err_Invalid_SubTable;
    138     SkPoint* points = reinterpret_cast<SkPoint*>(fastMalloc(sizeof(SkPoint) * (point + 1)));
    139     if (!points)
    140         return HB_Err_Invalid_SubTable;
    141     // Skia does let us get a single point from the path.
    142     path.getPoints(points, point + 1);
    143     *xPos = SkiaScalarToHarfbuzzFixed(points[point].fX);
    144     *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
    145     *resultingNumPoints = numPoints;
    146     fastFree(points);
    147 
    148     return HB_Err_Ok;
    149 }
    150 
    151 static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
    152 {
    153     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
    154     SkPaint paint;
    155 
    156     font->setupPaint(&paint);
    157     paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
    158     uint16_t glyph16 = glyph;
    159     SkScalar width;
    160     SkRect bounds;
    161     paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
    162 
    163     metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
    164     metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
    165     metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
    166     metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
    167 
    168     metrics->xOffset = SkiaScalarToHarfbuzzFixed(width);
    169     // We can't actually get the |y| correct because Skia doesn't export
    170     // the vertical advance. However, nor we do ever render vertical text at
    171     // the moment so it's unimportant.
    172     metrics->yOffset = 0;
    173 }
    174 
    175 static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric)
    176 {
    177     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(hbFont->userData);
    178     SkPaint paint;
    179 
    180     font->setupPaint(&paint);
    181     SkPaint::FontMetrics skiaMetrics;
    182     paint.getFontMetrics(&skiaMetrics);
    183 
    184     switch (metric) {
    185     case HB_FontAscent:
    186         return SkiaScalarToHarfbuzzFixed(-skiaMetrics.fAscent);
    187     // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them.
    188     default:
    189         return 0;
    190     }
    191 }
    192 
    193 HB_FontClass harfbuzzSkiaClass = {
    194     stringToGlyphs,
    195     glyphsToAdvances,
    196     canRender,
    197     getOutlinePoint,
    198     getGlyphMetrics,
    199     getFontMetric,
    200 };
    201 
    202 HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
    203 {
    204     FontPlatformData* font = reinterpret_cast<FontPlatformData*>(voidface);
    205 
    206     const size_t tableSize = SkFontHost::GetTableSize(font->uniqueID(), tag);
    207     if (!tableSize)
    208         return HB_Err_Invalid_Argument;
    209     // If Harfbuzz specified a NULL buffer then it's asking for the size of the table.
    210     if (!buffer) {
    211         *len = tableSize;
    212         return HB_Err_Ok;
    213     }
    214 
    215     if (*len < tableSize)
    216         return HB_Err_Invalid_Argument;
    217     SkFontHost::GetTableData(font->uniqueID(), tag, 0, tableSize, buffer);
    218     return HB_Err_Ok;
    219 }
    220 
    221 }  // namespace WebCore
    222