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