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