Loading core/jni/Android.mk +3 −4 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ LOCAL_SRC_FILES:= \ android/graphics/DrawFilter.cpp \ android/graphics/CreateJavaOutputStreamAdaptor.cpp \ android/graphics/Graphics.cpp \ android/graphics/HarfbuzzSkia.cpp \ android/graphics/HarfBuzzNGFaceSkia.cpp \ android/graphics/Interpolator.cpp \ android/graphics/LayerRasterizer.cpp \ android/graphics/MaskFilter.cpp \ Loading Loading @@ -170,8 +170,7 @@ LOCAL_C_INCLUDES += \ external/icu4c/i18n \ external/icu4c/common \ external/jpeg \ external/harfbuzz/contrib \ external/harfbuzz/src \ external/harfbuzz_ng/src \ external/zlib \ frameworks/opt/emoji \ libcore/include Loading Loading @@ -206,7 +205,7 @@ LOCAL_SHARED_LIBRARIES := \ libwpa_client \ libjpeg \ libusbhost \ libharfbuzz \ libharfbuzz_ng \ libz ifeq ($(USE_OPENGL_RENDERER),true) Loading core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp 0 → 100644 +177 −0 Original line number Diff line number Diff line /* * Copyright (c) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "TextLayoutCache" #include "HarfBuzzNGFaceSkia.h" #include <cutils/log.h> #include <SkFontHost.h> #include <SkPaint.h> #include <SkPath.h> #include <SkPoint.h> #include <SkRect.h> #include <SkUtils.h> #include <hb.h> namespace android { // Our implementation of the callbacks which Harfbuzz requires by using Skia // calls. See the Harfbuzz source for references about what these callbacks do. struct HarfBuzzFontData { HarfBuzzFontData(SkPaint* paint) : m_paint(paint) { } SkPaint* m_paint; }; static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents) { ALOG_ASSERT(codepoint <= 0xFFFF); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar skWidth; SkRect skBounds; uint16_t glyph = codepoint; paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); ALOGD("returned glyph for %i: width = %f", codepoint, skWidth); if (width) *width = SkScalarToHBFixed(skWidth); if (extents) { // Invert y-axis because Skia is y-grows-down but we set up harfbuzz to be y-grows-up. extents->x_bearing = SkScalarToHBFixed(skBounds.fLeft); extents->y_bearing = SkScalarToHBFixed(-skBounds.fTop); extents->width = SkScalarToHBFixed(skBounds.width()); extents->height = SkScalarToHBFixed(-skBounds.height()); } } 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) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); if (unicode > 0x10ffff) { unicode = 0xfffd; } SkPaint* paint = hbFontData->m_paint; // It would be better to use kUTF32_TextEncoding directly paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); uint16_t glyph16; uint16_t unichar[2]; size_t size = SkUTF16_FromUnichar(unicode, unichar); paint->textToGlyphs(unichar, size * sizeof(*unichar), &glyph16); *glyph = glyph16; return !!*glyph; } static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); hb_position_t advance = 0; SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, &advance, 0); return advance; } 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) { // Just return true, following the way that Harfbuzz-FreeType // implementation does. return true; } static hb_bool_t harfbuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, 0, extents); return true; } static hb_font_funcs_t* harfbuzzSkiaGetFontFuncs() { static hb_font_funcs_t* harfbuzzSkiaFontFuncs = 0; // We don't set callback functions which we can't support. // Harfbuzz will use the fallback implementation if they aren't set. if (!harfbuzzSkiaFontFuncs) { harfbuzzSkiaFontFuncs = hb_font_funcs_create(); hb_font_funcs_set_glyph_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyph, 0, 0); hb_font_funcs_set_glyph_h_advance_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0); hb_font_funcs_set_glyph_h_origin_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0); hb_font_funcs_set_glyph_extents_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphExtents, 0, 0); hb_font_funcs_make_immutable(harfbuzzSkiaFontFuncs); } return harfbuzzSkiaFontFuncs; } hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData) { SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); SkFontID uniqueID = typeface->uniqueID(); const size_t tableSize = SkFontHost::GetTableSize(uniqueID, tag); if (!tableSize) return 0; char* buffer = reinterpret_cast<char*>(malloc(tableSize)); if (!buffer) return 0; size_t actualSize = SkFontHost::GetTableData(uniqueID, tag, 0, tableSize, buffer); if (tableSize != actualSize) { free(buffer); return 0; } return hb_blob_create(const_cast<char*>(buffer), tableSize, HB_MEMORY_MODE_WRITABLE, buffer, free); } static void destroyHarfBuzzFontData(void* data) { delete (HarfBuzzFontData*)data; } hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY) { hb_font_t* font = hb_font_create(face); // Note: this needs to be reworked when we do subpixels int x_ppem = floor(sizeX + 0.5); int y_ppem = floor(sizeY + 0.5); hb_font_set_ppem(font, x_ppem, y_ppem); hb_font_set_scale(font, HBFloatToFixed(sizeX), HBFloatToFixed(sizeY)); HarfBuzzFontData* data = new HarfBuzzFontData(paint); hb_font_set_funcs(font, harfbuzzSkiaGetFontFuncs(), data, destroyHarfBuzzFontData); return font; } } // namespace android core/jni/android/graphics/HarfbuzzSkia.h→core/jni/android/graphics/HarfBuzzNGFaceSkia.h +20 −16 Original line number Diff line number Diff line Loading @@ -24,31 +24,35 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HarfbuzzSkia_h #define HarfbuzzSkia_h #ifndef HarfBuzzNGFaceSkia_h #define HarfBuzzNGFaceSkia_h #include "SkScalar.h" #include "SkTypeface.h" #include "SkPaint.h" #include <SkScalar.h> #include <SkPaint.h> extern "C" { #include "harfbuzz-shaper.h" } #include <hb.h> namespace android { static inline float HBFixedToFloat(HB_Fixed v) { // Harfbuzz uses 26.6 fixed point values for pixel offsets return v * (1.0f / 64); static inline float HBFixedToFloat (hb_position_t v) { return scalblnf (v, -8); } static inline hb_position_t HBFloatToFixed (float v) { return scalblnf (v, +8); } static inline HB_Fixed SkScalarToHBFixed(SkScalar value) { // HB_Fixed is a 26.6 fixed point format. return SkScalarToFloat(value) * 64.0f; static inline hb_position_t SkScalarToHBFixed(SkScalar value) { return HBFloatToFixed(SkScalarToFloat(value)); } HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len); extern const HB_FontClass harfbuzzSkiaClass; hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData); hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY); } // namespace android Loading core/jni/android/graphics/HarfbuzzSkia.cppdeleted 100644 → 0 +0 −214 Original line number Diff line number Diff line /* * Copyright 2011, The Android Open Source Project * Copyright 2011, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "HarfbuzzSkia" #include "HarfbuzzSkia.h" #include "SkFontHost.h" #include "SkPaint.h" #include "SkPath.h" #include "SkPoint.h" #include "SkRect.h" #include "SkTypeface.h" #include <utils/Log.h> extern "C" { #include "harfbuzz-shaper.h" } // This file implements the callbacks which Harfbuzz requires by using Skia // calls. See the Harfbuzz source for references about what these callbacks do. namespace android { static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs); int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs); // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our // |glyphs| array needs to be converted. for (int i = numGlyphs - 1; i >= 0; --i) { glyphs[i] = skiaGlyphs[i]; } *glyphsSize = numGlyphs; return 1; } static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t* glyphs16 = new uint16_t[numGlyphs]; if (!glyphs16) return; for (unsigned i = 0; i < numGlyphs; ++i) glyphs16[i] = glyphs[i]; SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances); paint->getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances); // The |advances| values which Skia outputs are SkScalars, which are floats // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format. // These two formats are both 32-bits long. for (unsigned i = 0; i < numGlyphs; ++i) { advances[i] = SkScalarToHBFixed(scalarAdvances[i]); #if DEBUG_ADVANCES ALOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]); #endif } delete glyphs16; } static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); uint16_t* glyphs16 = new uint16_t[length]; int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), glyphs16); bool result = true; for (int i = 0; i < numGlyphs; ++i) { if (!glyphs16[i]) { result = false; break; } } delete glyphs16; return result; } static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) { if (flags & HB_ShaperFlag_UseDesignMetrics) // This is requesting pre-hinted positions. We can't support this. return HB_Err_Invalid_Argument; SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkPath path; paint->getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); uint32_t numPoints = path.getPoints(0, 0); if (point >= numPoints) return HB_Err_Invalid_SubTable; SkPoint* points = static_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1))); if (!points) return HB_Err_Invalid_SubTable; // Skia does let us get a single point from the path. path.getPoints(points, point + 1); *xPos = SkScalarToHBFixed(points[point].fX); *yPos = SkScalarToHBFixed(points[point].fY); *resultingNumPoints = numPoints; delete points; return HB_Err_Ok; } static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkScalar width; SkRect bounds; paint->getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds); metrics->x = SkScalarToHBFixed(bounds.fLeft); metrics->y = SkScalarToHBFixed(bounds.fTop); metrics->width = SkScalarToHBFixed(bounds.width()); metrics->height = SkScalarToHBFixed(bounds.height()); metrics->xOffset = SkScalarToHBFixed(width); // We can't actually get the |y| correct because Skia doesn't export // the vertical advance. However, nor we do ever render vertical text at // the moment so it's unimportant. metrics->yOffset = 0; } static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); SkPaint::FontMetrics skiaMetrics; paint->getFontMetrics(&skiaMetrics); switch (metric) { case HB_FontAscent: return SkScalarToHBFixed(-skiaMetrics.fAscent); // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them. default: return 0; } return 0; } const HB_FontClass harfbuzzSkiaClass = { stringToGlyphs, glyphsToAdvances, canRender, getOutlinePoint, getGlyphMetrics, getFontMetric, }; HB_Error harfbuzzSkiaGetTable(void* font, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len) { SkTypeface* typeface = static_cast<SkTypeface*>(font); if (!typeface) { ALOGD("Typeface cannot be null"); return HB_Err_Invalid_Argument; } const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag); if (!tableSize) return HB_Err_Invalid_Argument; // If Harfbuzz specified a NULL buffer then it's asking for the size of the table. if (!buffer) { *len = tableSize; return HB_Err_Ok; } if (*len < tableSize) return HB_Err_Invalid_Argument; SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer); return HB_Err_Ok; } } // namespace android Loading
core/jni/Android.mk +3 −4 Original line number Diff line number Diff line Loading @@ -91,7 +91,7 @@ LOCAL_SRC_FILES:= \ android/graphics/DrawFilter.cpp \ android/graphics/CreateJavaOutputStreamAdaptor.cpp \ android/graphics/Graphics.cpp \ android/graphics/HarfbuzzSkia.cpp \ android/graphics/HarfBuzzNGFaceSkia.cpp \ android/graphics/Interpolator.cpp \ android/graphics/LayerRasterizer.cpp \ android/graphics/MaskFilter.cpp \ Loading Loading @@ -170,8 +170,7 @@ LOCAL_C_INCLUDES += \ external/icu4c/i18n \ external/icu4c/common \ external/jpeg \ external/harfbuzz/contrib \ external/harfbuzz/src \ external/harfbuzz_ng/src \ external/zlib \ frameworks/opt/emoji \ libcore/include Loading Loading @@ -206,7 +205,7 @@ LOCAL_SHARED_LIBRARIES := \ libwpa_client \ libjpeg \ libusbhost \ libharfbuzz \ libharfbuzz_ng \ libz ifeq ($(USE_OPENGL_RENDERER),true) Loading
core/jni/android/graphics/HarfBuzzNGFaceSkia.cpp 0 → 100644 +177 −0 Original line number Diff line number Diff line /* * Copyright (c) 2012 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "TextLayoutCache" #include "HarfBuzzNGFaceSkia.h" #include <cutils/log.h> #include <SkFontHost.h> #include <SkPaint.h> #include <SkPath.h> #include <SkPoint.h> #include <SkRect.h> #include <SkUtils.h> #include <hb.h> namespace android { // Our implementation of the callbacks which Harfbuzz requires by using Skia // calls. See the Harfbuzz source for references about what these callbacks do. struct HarfBuzzFontData { HarfBuzzFontData(SkPaint* paint) : m_paint(paint) { } SkPaint* m_paint; }; static void SkiaGetGlyphWidthAndExtents(SkPaint* paint, hb_codepoint_t codepoint, hb_position_t* width, hb_glyph_extents_t* extents) { ALOG_ASSERT(codepoint <= 0xFFFF); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); SkScalar skWidth; SkRect skBounds; uint16_t glyph = codepoint; paint->getTextWidths(&glyph, sizeof(glyph), &skWidth, &skBounds); ALOGD("returned glyph for %i: width = %f", codepoint, skWidth); if (width) *width = SkScalarToHBFixed(skWidth); if (extents) { // Invert y-axis because Skia is y-grows-down but we set up harfbuzz to be y-grows-up. extents->x_bearing = SkScalarToHBFixed(skBounds.fLeft); extents->y_bearing = SkScalarToHBFixed(-skBounds.fTop); extents->width = SkScalarToHBFixed(skBounds.width()); extents->height = SkScalarToHBFixed(-skBounds.height()); } } 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) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); if (unicode > 0x10ffff) { unicode = 0xfffd; } SkPaint* paint = hbFontData->m_paint; // It would be better to use kUTF32_TextEncoding directly paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); uint16_t glyph16; uint16_t unichar[2]; size_t size = SkUTF16_FromUnichar(unicode, unichar); paint->textToGlyphs(unichar, size * sizeof(*unichar), &glyph16); *glyph = glyph16; return !!*glyph; } static hb_position_t harfbuzzGetGlyphHorizontalAdvance(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, void* userData) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); hb_position_t advance = 0; SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, &advance, 0); return advance; } 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) { // Just return true, following the way that Harfbuzz-FreeType // implementation does. return true; } static hb_bool_t harfbuzzGetGlyphExtents(hb_font_t* hbFont, void* fontData, hb_codepoint_t glyph, hb_glyph_extents_t* extents, void* userData) { HarfBuzzFontData* hbFontData = reinterpret_cast<HarfBuzzFontData*>(fontData); SkiaGetGlyphWidthAndExtents(hbFontData->m_paint, glyph, 0, extents); return true; } static hb_font_funcs_t* harfbuzzSkiaGetFontFuncs() { static hb_font_funcs_t* harfbuzzSkiaFontFuncs = 0; // We don't set callback functions which we can't support. // Harfbuzz will use the fallback implementation if they aren't set. if (!harfbuzzSkiaFontFuncs) { harfbuzzSkiaFontFuncs = hb_font_funcs_create(); hb_font_funcs_set_glyph_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyph, 0, 0); hb_font_funcs_set_glyph_h_advance_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalAdvance, 0, 0); hb_font_funcs_set_glyph_h_origin_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphHorizontalOrigin, 0, 0); hb_font_funcs_set_glyph_extents_func(harfbuzzSkiaFontFuncs, harfbuzzGetGlyphExtents, 0, 0); hb_font_funcs_make_immutable(harfbuzzSkiaFontFuncs); } return harfbuzzSkiaFontFuncs; } hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData) { SkTypeface* typeface = reinterpret_cast<SkTypeface*>(userData); SkFontID uniqueID = typeface->uniqueID(); const size_t tableSize = SkFontHost::GetTableSize(uniqueID, tag); if (!tableSize) return 0; char* buffer = reinterpret_cast<char*>(malloc(tableSize)); if (!buffer) return 0; size_t actualSize = SkFontHost::GetTableData(uniqueID, tag, 0, tableSize, buffer); if (tableSize != actualSize) { free(buffer); return 0; } return hb_blob_create(const_cast<char*>(buffer), tableSize, HB_MEMORY_MODE_WRITABLE, buffer, free); } static void destroyHarfBuzzFontData(void* data) { delete (HarfBuzzFontData*)data; } hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY) { hb_font_t* font = hb_font_create(face); // Note: this needs to be reworked when we do subpixels int x_ppem = floor(sizeX + 0.5); int y_ppem = floor(sizeY + 0.5); hb_font_set_ppem(font, x_ppem, y_ppem); hb_font_set_scale(font, HBFloatToFixed(sizeX), HBFloatToFixed(sizeY)); HarfBuzzFontData* data = new HarfBuzzFontData(paint); hb_font_set_funcs(font, harfbuzzSkiaGetFontFuncs(), data, destroyHarfBuzzFontData); return font; } } // namespace android
core/jni/android/graphics/HarfbuzzSkia.h→core/jni/android/graphics/HarfBuzzNGFaceSkia.h +20 −16 Original line number Diff line number Diff line Loading @@ -24,31 +24,35 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef HarfbuzzSkia_h #define HarfbuzzSkia_h #ifndef HarfBuzzNGFaceSkia_h #define HarfBuzzNGFaceSkia_h #include "SkScalar.h" #include "SkTypeface.h" #include "SkPaint.h" #include <SkScalar.h> #include <SkPaint.h> extern "C" { #include "harfbuzz-shaper.h" } #include <hb.h> namespace android { static inline float HBFixedToFloat(HB_Fixed v) { // Harfbuzz uses 26.6 fixed point values for pixel offsets return v * (1.0f / 64); static inline float HBFixedToFloat (hb_position_t v) { return scalblnf (v, -8); } static inline hb_position_t HBFloatToFixed (float v) { return scalblnf (v, +8); } static inline HB_Fixed SkScalarToHBFixed(SkScalar value) { // HB_Fixed is a 26.6 fixed point format. return SkScalarToFloat(value) * 64.0f; static inline hb_position_t SkScalarToHBFixed(SkScalar value) { return HBFloatToFixed(SkScalarToFloat(value)); } HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len); extern const HB_FontClass harfbuzzSkiaClass; hb_blob_t* harfbuzzSkiaReferenceTable(hb_face_t* face, hb_tag_t tag, void* userData); hb_font_t* createFont(hb_face_t* face, SkPaint* paint, float sizeX, float sizeY); } // namespace android Loading
core/jni/android/graphics/HarfbuzzSkia.cppdeleted 100644 → 0 +0 −214 Original line number Diff line number Diff line /* * Copyright 2011, The Android Open Source Project * Copyright 2011, Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #define LOG_TAG "HarfbuzzSkia" #include "HarfbuzzSkia.h" #include "SkFontHost.h" #include "SkPaint.h" #include "SkPath.h" #include "SkPoint.h" #include "SkRect.h" #include "SkTypeface.h" #include <utils/Log.h> extern "C" { #include "harfbuzz-shaper.h" } // This file implements the callbacks which Harfbuzz requires by using Skia // calls. See the Harfbuzz source for references about what these callbacks do. namespace android { static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length, HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); uint16_t* skiaGlyphs = reinterpret_cast<uint16_t*>(glyphs); int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), skiaGlyphs); // HB_Glyph is 32-bit, but Skia outputs only 16-bit numbers. So our // |glyphs| array needs to be converted. for (int i = numGlyphs - 1; i >= 0; --i) { glyphs[i] = skiaGlyphs[i]; } *glyphsSize = numGlyphs; return 1; } static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs, HB_Fixed* advances, int flags) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t* glyphs16 = new uint16_t[numGlyphs]; if (!glyphs16) return; for (unsigned i = 0; i < numGlyphs; ++i) glyphs16[i] = glyphs[i]; SkScalar* scalarAdvances = reinterpret_cast<SkScalar*>(advances); paint->getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), scalarAdvances); // The |advances| values which Skia outputs are SkScalars, which are floats // in Chromium. However, Harfbuzz wants them in 26.6 fixed point format. // These two formats are both 32-bits long. for (unsigned i = 0; i < numGlyphs; ++i) { advances[i] = SkScalarToHBFixed(scalarAdvances[i]); #if DEBUG_ADVANCES ALOGD("glyphsToAdvances -- advances[%d]=%d", i, advances[i]); #endif } delete glyphs16; } static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kUTF16_TextEncoding); uint16_t* glyphs16 = new uint16_t[length]; int numGlyphs = paint->textToGlyphs(characters, length * sizeof(uint16_t), glyphs16); bool result = true; for (int i = 0; i < numGlyphs; ++i) { if (!glyphs16[i]) { result = false; break; } } delete glyphs16; return result; } static HB_Error getOutlinePoint(HB_Font hbFont, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed* xPos, HB_Fixed* yPos, hb_uint32* resultingNumPoints) { if (flags & HB_ShaperFlag_UseDesignMetrics) // This is requesting pre-hinted positions. We can't support this. return HB_Err_Invalid_Argument; SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkPath path; paint->getTextPath(&glyph16, sizeof(glyph16), 0, 0, &path); uint32_t numPoints = path.getPoints(0, 0); if (point >= numPoints) return HB_Err_Invalid_SubTable; SkPoint* points = static_cast<SkPoint*>(malloc(sizeof(SkPoint) * (point + 1))); if (!points) return HB_Err_Invalid_SubTable; // Skia does let us get a single point from the path. path.getPoints(points, point + 1); *xPos = SkScalarToHBFixed(points[point].fX); *yPos = SkScalarToHBFixed(points[point].fY); *resultingNumPoints = numPoints; delete points; return HB_Err_Ok; } static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding); uint16_t glyph16 = glyph; SkScalar width; SkRect bounds; paint->getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds); metrics->x = SkScalarToHBFixed(bounds.fLeft); metrics->y = SkScalarToHBFixed(bounds.fTop); metrics->width = SkScalarToHBFixed(bounds.width()); metrics->height = SkScalarToHBFixed(bounds.height()); metrics->xOffset = SkScalarToHBFixed(width); // We can't actually get the |y| correct because Skia doesn't export // the vertical advance. However, nor we do ever render vertical text at // the moment so it's unimportant. metrics->yOffset = 0; } static HB_Fixed getFontMetric(HB_Font hbFont, HB_FontMetric metric) { SkPaint* paint = static_cast<SkPaint*>(hbFont->userData); SkPaint::FontMetrics skiaMetrics; paint->getFontMetrics(&skiaMetrics); switch (metric) { case HB_FontAscent: return SkScalarToHBFixed(-skiaMetrics.fAscent); // We don't support getting the rest of the metrics and Harfbuzz doesn't seem to need them. default: return 0; } return 0; } const HB_FontClass harfbuzzSkiaClass = { stringToGlyphs, glyphsToAdvances, canRender, getOutlinePoint, getGlyphMetrics, getFontMetric, }; HB_Error harfbuzzSkiaGetTable(void* font, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len) { SkTypeface* typeface = static_cast<SkTypeface*>(font); if (!typeface) { ALOGD("Typeface cannot be null"); return HB_Err_Invalid_Argument; } const size_t tableSize = SkFontHost::GetTableSize(typeface->uniqueID(), tag); if (!tableSize) return HB_Err_Invalid_Argument; // If Harfbuzz specified a NULL buffer then it's asking for the size of the table. if (!buffer) { *len = tableSize; return HB_Err_Ok; } if (*len < tableSize) return HB_Err_Invalid_Argument; SkFontHost::GetTableData(typeface->uniqueID(), tag, 0, tableSize, buffer); return HB_Err_Ok; } } // namespace android