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 SkFontID uniqueID = typeface->uniqueID(); 142 143 const size_t tableSize = SkFontHost::GetTableSize(uniqueID, 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 = SkFontHost::GetTableData(uniqueID, 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 160 static void destroyHarfBuzzFontData(void* data) { 161 delete (HarfBuzzFontData*)data; 162 } 163 164 hb_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