HarfBuzzNGFaceSkia.cpp revision aaedde51b76901ff05f2a2348eb41f0f5323d954
1/* 2 * Copyright (c) 2012 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 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 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#define LOG_TAG "TextLayoutCache" 32 33#include "HarfBuzzNGFaceSkia.h" 34 35#include <cutils/log.h> 36#include <SkFontHost.h> 37#include <SkPaint.h> 38#include <SkPath.h> 39#include <SkPoint.h> 40#include <SkRect.h> 41#include <SkUtils.h> 42 43#include <hb.h> 44 45namespace android { 46 47// Our implementation of the callbacks which Harfbuzz requires by using Skia 48// calls. See the Harfbuzz source for references about what these callbacks do. 49 50struct HarfBuzzFontData { 51 HarfBuzzFontData(SkPaint* paint) : m_paint(paint) { } 52 SkPaint* m_paint; 53}; 54 55static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents) 56{ 57 ALOG_ASSERT(codepoint <= 0xFFFF); 58 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 59 60 SkScalar skWidth; 61 SkRect skBounds; 62 uint16_t glyph = codepoint; 63 64 paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); 65 ALOGD("returned glyph for %i: width = %f", codepoint, skWidth); 66 if (width) 67 *width = SkScalarToHBFixed(skWidth); 68 if (extents) { 69 // Invert y-axis because Skia is y-grows-down but we set up harfbuzz to be y-grows-up. 70 extents->x_bearing = SkScalarToHBFixed(skBounds.fLeft); 71 extents->y_bearing = SkScalarToHBFixed(-skBounds.fTop); 72 extents->width = SkScalarToHBFixed(skBounds.width()); 73 extents->height = SkScalarToHBFixed(-skBounds.height()); 74 } 75} 76 77static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData) 78{ 79 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 80 81 if (unicode > 0x10ffff) { 82 unicode = 0xfffd; 83 } 84 SkPaint* paint = hbFontData->m_paint; 85 // It would be better to use kUTF32_TextEncoding directly 86 paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); 87 uint16_t glyph16; 88 uint16_t unichar[2]; 89 size_t size = SkUTF16_FromUnichar(unicode, unichar); 90 paint->textToGlyphs(unichar, size * sizeof(*unichar), &glyph16); 91 *glyph = glyph16; 92 return !!*glyph; 93} 94 95static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData) 96{ 97 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 98 hb_position_t advance = 0; 99 100 SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, &advance, 0); 101 return advance; 102} 103 104static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData) 105{ 106 // Just return true, following the way that Harfbuzz-FreeType 107 // implementation does. 108 return true; 109} 110 111static hb_bool_t harfbuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) 112{ 113 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 114 115 SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, 0, extents); 116 return true; 117} 118 119static hb_font_funcs_t* harfbuzzSkiaGetFontFuncs() 120{ 121 static hb_font_funcs_t* harfbuzzSkiaFontFuncs = 0; 122 123 // We don't set callback functions which we can't support. 124 // Harfbuzz will use the fallback implementation if they aren't set. 125 if (!harfbuzzSkiaFontFuncs) { 126 harfbuzzSkiaFontFuncs = hb_font_funcs_create(); 127 hb_font_funcs_set_glyph_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyph, 0, 0); 128 hb_font_funcs_set_glyph_h_advance_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0); 129 hb_font_funcs_set_glyph_h_origin_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0); 130 hb_font_funcs_set_glyph_extents_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphExtents, 0, 0); 131 hb_font_funcs_make_immutable(harfbuzzSkiaFontFuncs); 132 } 133 return harfbuzzSkiaFontFuncs; 134} 135 136hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData) 137{ 138 SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); 139 SkFontID uniqueID = typeface->uniqueID(); 140 141 const size_t tableSize = SkFontHost::GetTableSize(uniqueID, tag); 142 if (!tableSize) 143 return 0; 144 145 char* buffer = reinterpret_cast<char*>(malloc(tableSize)); 146 if (!buffer) 147 return 0; 148 size_t actualSize = SkFontHost::GetTableData(uniqueID, tag, 0, tableSize, buffer); 149 if (tableSize != actualSize) { 150 free(buffer); 151 return 0; 152 } 153 154 return hb_blob_create(const_cast<char*>(buffer), tableSize, 155 HB_MEMORY_MODE_WRITABLE, buffer, free); 156} 157 158static void destroyHarfBuzzFontData(void* data) { 159 delete (HarfBuzzFontData*)data; 160} 161 162hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY) { 163 hb_font_t* font = hb_font_create(face); 164 165 // Note: this needs to be reworked when we do subpixels 166 int x_ppem = floor(sizeX + 0.5); 167 int y_ppem = floor(sizeY + 0.5); 168 hb_font_set_ppem(font, x_ppem, y_ppem); 169 hb_font_set_scale(font, HBFloatToFixed(sizeX), HBFloatToFixed(sizeY)); 170 171 HarfBuzzFontData* data = new HarfBuzzFontData(paint); 172 hb_font_set_funcs(font, harfbuzzSkiaGetFontFuncs(), data, destroyHarfBuzzFontData); 173 174 return font; 175} 176 177} // namespace android 178