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 <stdlib.h> 36#include <cutils/log.h> 37#include <SkPaint.h> 38#include <SkPath.h> 39#include <SkPoint.h> 40#include <SkRect.h> 41#include <SkTypeface.h> 42 43#include <hb.h> 44 45namespace android { 46 47static const bool kDebugGlyphs = false; 48 49// Our implementation of the callbacks which Harfbuzz requires by using Skia 50// calls. See the Harfbuzz source for references about what these callbacks do. 51 52struct HarfBuzzFontData { 53 HarfBuzzFontData(SkPaint* paint) : m_paint(paint) { } 54 SkPaint* m_paint; 55}; 56 57static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents) 58{ 59 ALOG_ASSERT(codepoint <= 0xFFFF); 60 paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); 61 62 SkScalar skWidth; 63 SkRect skBounds; 64 uint16_t glyph = codepoint; 65 66 paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); 67 if (kDebugGlyphs) { 68 ALOGD("returned glyph for %i: width = %f", codepoint, skWidth); 69 } 70 if (width) 71 *width = SkScalarToHBFixed(skWidth); 72 if (extents) { 73 // Invert y-axis because Skia is y-grows-down but we set up harfbuzz to be y-grows-up. 74 extents->x_bearing = SkScalarToHBFixed(skBounds.fLeft); 75 extents->y_bearing = SkScalarToHBFixed(-skBounds.fTop); 76 extents->width = SkScalarToHBFixed(skBounds.width()); 77 extents->height = SkScalarToHBFixed(-skBounds.height()); 78 } 79} 80 81static hb_bool_t harfbuzzGetGlyph(hb_font_t* hbFont, void* fontData, hb_codepoint_t unicode, hb_codepoint_t variationSelector, hb_codepoint_t* glyph, void* userData) 82{ 83 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 84 SkPaint* paint = hbFontData->m_paint; 85 paint->setTextEncoding(SkPaint::kUTF32_TextEncoding); 86 87 if (unicode > 0x10ffff) { 88 unicode = 0xfffd; 89 } 90 SkUnichar unichar = unicode; 91 92 uint16_t glyph16; 93 paint->textToGlyphs(&unichar, sizeof(unichar), &glyph16); 94 *glyph = glyph16; 95 return !!*glyph; 96} 97 98static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData) 99{ 100 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 101 hb_position_t advance = 0; 102 103 SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, &advance, 0); 104 return advance; 105} 106 107static hb_bool_t harfbuzzGetGlyphHorizontalOrigin(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_position_t* x, hb_position_t* y, void* userData) 108{ 109 // Just return true, following the way that Harfbuzz-FreeType 110 // implementation does. 111 return true; 112} 113 114static hb_bool_t harfbuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) 115{ 116 HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); 117 118 SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, 0, extents); 119 return true; 120} 121 122static hb_font_funcs_t* harfbuzzSkiaGetFontFuncs() 123{ 124 static hb_font_funcs_t* harfbuzzSkiaFontFuncs = 0; 125 126 // We don't set callback functions which we can't support. 127 // Harfbuzz will use the fallback implementation if they aren't set. 128 if (!harfbuzzSkiaFontFuncs) { 129 harfbuzzSkiaFontFuncs = hb_font_funcs_create(); 130 hb_font_funcs_set_glyph_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyph, 0, 0); 131 hb_font_funcs_set_glyph_h_advance_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0); 132 hb_font_funcs_set_glyph_h_origin_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0); 133 hb_font_funcs_set_glyph_extents_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphExtents, 0, 0); 134 hb_font_funcs_make_immutable(harfbuzzSkiaFontFuncs); 135 } 136 return harfbuzzSkiaFontFuncs; 137} 138 139hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData) 140{ 141 SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); 142 143 const size_t tableSize = typeface->getTableSize(tag); 144 if (!tableSize) 145 return 0; 146 147 char* buffer = reinterpret_cast<char*>(malloc(tableSize)); 148 if (!buffer) 149 return 0; 150 size_t actualSize = typeface->getTableData(tag, 0, tableSize, buffer); 151 if (tableSize != actualSize) { 152 free(buffer); 153 return 0; 154 } 155 156 return hb_blob_create(const_cast<char*>(buffer), tableSize, 157 HB_MEMORY_MODE_WRITABLE, buffer, free); 158} 159 160static void destroyHarfBuzzFontData(void* data) { 161 delete (HarfBuzzFontData*)data; 162} 163 164hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY) { 165 hb_font_t* font = hb_font_create(face); 166 167 // Note: this needs to be reworked when we do subpixels 168 int x_ppem = floor(sizeX + 0.5); 169 int y_ppem = floor(sizeY + 0.5); 170 hb_font_set_ppem(font, x_ppem, y_ppem); 171 hb_font_set_scale(font, HBFloatToFixed(sizeX), HBFloatToFixed(sizeY)); 172 173 HarfBuzzFontData* data = new HarfBuzzFontData(paint); 174 hb_font_set_funcs(font, harfbuzzSkiaGetFontFuncs(), data, destroyHarfBuzzFontData); 175 176 return font; 177} 178 179} // namespace android 180