summaryrefslogtreecommitdiffstats
path: root/core/jni/android
diff options
context:
space:
mode:
authorFabrice Di Meglio <fdimeglio@google.com>2011-03-08 12:02:59 -0800
committerFabrice Di Meglio <fdimeglio@google.com>2011-03-22 19:36:30 -0700
commit9f82b580d744ce4baf057b061994394dcf239eed (patch)
treed4ca8d62a680a24b710ed7f44adbf783839b5702 /core/jni/android
parentd54952b451b2778629662cab100ac0a414c84583 (diff)
downloadframeworks_base-9f82b580d744ce4baf057b061994394dcf239eed.zip
frameworks_base-9f82b580d744ce4baf057b061994394dcf239eed.tar.gz
frameworks_base-9f82b580d744ce4baf057b061994394dcf239eed.tar.bz2
Use Harfbuzz instead of ICU4C for computing advances
- use Harfbuzz shaper for shaping and getting glyphs - add test app for showing result of drawText() and drawGlyphs() - add private API in Canvas and Paint for test app Change-Id: Ia15be216f8636d2d864066e9b7de2f53008c30f6
Diffstat (limited to 'core/jni/android')
-rw-r--r--core/jni/android/graphics/Canvas.cpp23
-rw-r--r--core/jni/android/graphics/HarfbuzzSkia.cpp239
-rw-r--r--core/jni/android/graphics/HarfbuzzSkia.h48
-rw-r--r--core/jni/android/graphics/Paint.cpp31
-rw-r--r--core/jni/android/graphics/RtlProperties.h2
-rw-r--r--core/jni/android/graphics/TextLayoutCache.cpp10
-rw-r--r--core/jni/android/graphics/TextLayoutCache.h162
7 files changed, 510 insertions, 5 deletions
diff --git a/core/jni/android/graphics/Canvas.cpp b/core/jni/android/graphics/Canvas.cpp
index 0cdb357..b4ad9e9 100644
--- a/core/jni/android/graphics/Canvas.cpp
+++ b/core/jni/android/graphics/Canvas.cpp
@@ -755,6 +755,27 @@ public:
env->ReleaseStringChars(text, textArray);
}
+ static void drawGlyphs___CIIFFIPaint(JNIEnv* env, jobject, SkCanvas* canvas,
+ jcharArray glyphs, int index, int count,
+ jfloat x, jfloat y, int flags, SkPaint* paint) {
+ jchar* glyphArray = env->GetCharArrayElements(glyphs, NULL);
+
+ // TODO: need to suppress this code after the GL renderer is modified for not
+ // copying the paint
+
+ // Save old text encoding
+ SkPaint::TextEncoding oldEncoding = paint->getTextEncoding();
+ // Define Glyph encoding
+ paint->setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+
+ TextLayout::drawText(paint, glyphArray + index, count, flags, x, y, canvas);
+
+ // Get back old encoding
+ paint->setTextEncoding(oldEncoding);
+
+ env->ReleaseCharArrayElements(glyphs, glyphArray, JNI_ABORT);
+ }
+
static void drawTextRun___CIIIIFFIPaint(
JNIEnv* env, jobject, SkCanvas* canvas, jcharArray text, int index,
int count, int contextIndex, int contextCount,
@@ -946,6 +967,8 @@ static JNINativeMethod gCanvasMethods[] = {
(void*) SkCanvasGlue::drawText___CIIFFIPaint},
{"native_drawText","(ILjava/lang/String;IIFFII)V",
(void*) SkCanvasGlue::drawText__StringIIFFIPaint},
+ {"native_drawGlyphs","(I[CIIFFII)V",
+ (void*) SkCanvasGlue::drawGlyphs___CIIFFIPaint},
{"native_drawTextRun","(I[CIIIIFFII)V",
(void*) SkCanvasGlue::drawTextRun___CIIIIFFIPaint},
{"native_drawTextRun","(ILjava/lang/String;IIIIFFII)V",
diff --git a/core/jni/android/graphics/HarfbuzzSkia.cpp b/core/jni/android/graphics/HarfbuzzSkia.cpp
new file mode 100644
index 0000000..58fb32b
--- /dev/null
+++ b/core/jni/android/graphics/HarfbuzzSkia.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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.
+ */
+
+#include "HarfbuzzSkia.h"
+
+#include "SkFontHost.h"
+
+#include "SkPaint.h"
+#include "SkPath.h"
+#include "SkPoint.h"
+#include "SkRect.h"
+#include "SkTypeface.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_Fixed SkiaScalarToHarfbuzzFixed(SkScalar value)
+{
+ // HB_Fixed is a 26.6 fixed point format.
+ return value * 64;
+}
+
+static void setupPaintWithFontData(SkPaint* paint, FontData* data) {
+ paint->setAntiAlias(true);
+ paint->setSubpixelText(true);
+ paint->setHinting(SkPaint::kSlight_Hinting);
+ paint->setTextSize(SkFloatToScalar(data->textSize));
+ paint->setTypeface(data->typeFace);
+ paint->setFakeBoldText(data->fakeBold);
+ paint->setTextSkewX(data->fakeItalic ? -SK_Scalar1/4 : 0);
+}
+
+static HB_Bool stringToGlyphs(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length,
+ HB_Glyph* glyphs, hb_uint32* glyphsSize, HB_Bool isRTL)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ paint.setTextEncoding(SkPaint::kUTF16_TextEncoding);
+ int numGlyphs = paint.textToGlyphs(characters, length * sizeof(uint16_t),
+ reinterpret_cast<uint16_t*>(glyphs));
+
+ // 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) {
+ uint16_t value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(glyphs) + sizeof(uint16_t) * i, sizeof(value));
+ glyphs[i] = value;
+ }
+
+ *glyphsSize = numGlyphs;
+ return 1;
+}
+
+static void glyphsToAdvances(HB_Font hbFont, const HB_Glyph* glyphs, hb_uint32 numGlyphs,
+ HB_Fixed* advances, int flags)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ 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];
+ paint.getTextWidths(glyphs16, numGlyphs * sizeof(uint16_t), reinterpret_cast<SkScalar*>(advances));
+
+ // 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) {
+ float value;
+ // We use a memcpy to avoid breaking strict aliasing rules.
+ memcpy(&value, reinterpret_cast<char*>(advances) + sizeof(float) * i, sizeof(value));
+ advances[i] = SkiaScalarToHarfbuzzFixed(value);
+ }
+ delete glyphs16;
+}
+
+static HB_Bool canRender(HB_Font hbFont, const HB_UChar16* characters, hb_uint32 length)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ 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)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ if (flags & HB_ShaperFlag_UseDesignMetrics)
+ // This is requesting pre-hinted positions. We can't support this.
+ return HB_Err_Invalid_Argument;
+
+ 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 = reinterpret_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 = SkiaScalarToHarfbuzzFixed(points[point].fX);
+ *yPos = SkiaScalarToHarfbuzzFixed(points[point].fY);
+ *resultingNumPoints = numPoints;
+ delete points;
+
+ return HB_Err_Ok;
+}
+
+static void getGlyphMetrics(HB_Font hbFont, HB_Glyph glyph, HB_GlyphMetrics* metrics)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+ uint16_t glyph16 = glyph;
+ SkScalar width;
+ SkRect bounds;
+ paint.getTextWidths(&glyph16, sizeof(glyph16), &width, &bounds);
+
+ metrics->x = SkiaScalarToHarfbuzzFixed(bounds.fLeft);
+ metrics->y = SkiaScalarToHarfbuzzFixed(bounds.fTop);
+ metrics->width = SkiaScalarToHarfbuzzFixed(bounds.width());
+ metrics->height = SkiaScalarToHarfbuzzFixed(bounds.height());
+
+ metrics->xOffset = SkiaScalarToHarfbuzzFixed(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)
+{
+ FontData* data = reinterpret_cast<FontData*>(hbFont->userData);
+ SkPaint paint;
+ setupPaintWithFontData(&paint, data);
+
+ SkPaint::FontMetrics skiaMetrics;
+ paint.getFontMetrics(&skiaMetrics);
+
+ switch (metric) {
+ case HB_FontAscent:
+ return SkiaScalarToHarfbuzzFixed(-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* voidface, const HB_Tag tag, HB_Byte* buffer, HB_UInt* len)
+{
+ FontData* data = reinterpret_cast<FontData*>(voidface);
+ SkTypeface* typeface = data->typeFace;
+
+ 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
diff --git a/core/jni/android/graphics/HarfbuzzSkia.h b/core/jni/android/graphics/HarfbuzzSkia.h
new file mode 100644
index 0000000..d057d76
--- /dev/null
+++ b/core/jni/android/graphics/HarfbuzzSkia.h
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+
+#ifndef HarfbuzzSkia_h
+#define HarfbuzzSkia_h
+
+#include "SkTypeface.h"
+
+extern "C" {
+#include "harfbuzz-shaper.h"
+}
+
+namespace android {
+ typedef struct {
+ SkTypeface* typeFace;
+ float textSize;
+ bool fakeBold;
+ bool fakeItalic;
+ } FontData;
+
+ HB_Error harfbuzzSkiaGetTable(void* voidface, const HB_Tag, HB_Byte* buffer, HB_UInt* len);
+ extern const HB_FontClass harfbuzzSkiaClass;
+} // namespace android
+
+#endif
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e62b034..5c3497f 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -393,13 +393,40 @@ public:
return count;
}
- static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text, int start, int end, jfloatArray widths) {
+ static int getTextWidths__StringII_F(JNIEnv* env, jobject clazz, SkPaint* paint, jstring text,
+ int start, int end, jfloatArray widths) {
const jchar* textArray = env->GetStringChars(text, NULL);
int count = dotextwidths(env, paint, textArray + start, end - start, widths);
env->ReleaseStringChars(text, textArray);
return count;
}
+ static int doTextGlyphs(JNIEnv* env, SkPaint* paint, const jchar* text, jint start, jint count,
+ jint contextCount, jint flags, jcharArray glyphs) {
+ jchar* glyphsArray = env->GetCharArrayElements(glyphs, NULL);
+ HB_ShaperItem shaperItem;
+ HB_FontRec font;
+ FontData fontData;
+ RunAdvanceDescription::shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, text,
+ start, count, contextCount, flags);
+
+ int glyphCount = shaperItem.num_glyphs;
+ for (int i = 0; i < glyphCount; i++) {
+ glyphsArray[i] = (jchar) shaperItem.glyphs[i];
+ }
+ return glyphCount;
+ }
+
+ static int getTextGlyphs__StringIIIII_C(JNIEnv* env, jobject clazz, SkPaint* paint,
+ jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
+ jcharArray glyphs) {
+ const jchar* textArray = env->GetStringChars(text, NULL);
+ int count = doTextGlyphs(env, paint, textArray + contextStart, start - contextStart,
+ end - start, contextEnd - contextStart, flags, glyphs);
+ env->ReleaseStringChars(text, textArray);
+ return count;
+ }
+
static jfloat doTextRunAdvances(JNIEnv *env, SkPaint *paint, const jchar *text,
jint start, jint count, jint contextCount, jint flags,
jfloatArray advances, jint advancesIndex) {
@@ -725,6 +752,8 @@ static JNINativeMethod methods[] = {
SkPaintGlue::getTextRunAdvances___CIIIII_FI},
{"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
(void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
+ {"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
+ (void*) SkPaintGlue::getTextGlyphs__StringIIIII_C},
{"native_getTextRunCursor", "(I[CIIIII)I", (void*) SkPaintGlue::getTextRunCursor___C},
{"native_getTextRunCursor", "(ILjava/lang/String;IIIII)I",
(void*) SkPaintGlue::getTextRunCursor__String},
diff --git a/core/jni/android/graphics/RtlProperties.h b/core/jni/android/graphics/RtlProperties.h
index 6d8ba91..2c68fa3 100644
--- a/core/jni/android/graphics/RtlProperties.h
+++ b/core/jni/android/graphics/RtlProperties.h
@@ -45,5 +45,7 @@ static RtlDebugLevel readRtlDebugLevel() {
return kRtlDebugDisabled;
}
+#define RTL_USE_HARFBUZZ 1
+
} // namespace android
#endif // ANDROID_RTL_PROPERTIES_H
diff --git a/core/jni/android/graphics/TextLayoutCache.cpp b/core/jni/android/graphics/TextLayoutCache.cpp
index 7888769..a7265be 100644
--- a/core/jni/android/graphics/TextLayoutCache.cpp
+++ b/core/jni/android/graphics/TextLayoutCache.cpp
@@ -47,8 +47,16 @@ void TextLayoutCache::init() {
if (mDebugEnabled) {
LOGD("TextLayoutCache start time: %lld", mCacheStartTime);
}
-
mInitialized = true;
+
+ if (mDebugEnabled) {
+#if RTL_USE_HARFBUZZ
+ LOGD("TextLayoutCache is using HARFBUZZ");
+#else
+ LOGD("TextLayoutCache is using ICU");
+#endif
+ }
+
if (mDebugEnabled) {
LOGD("TextLayoutCache initialization is done");
}
diff --git a/core/jni/android/graphics/TextLayoutCache.h b/core/jni/android/graphics/TextLayoutCache.h
index 9d55918..e962a86 100644
--- a/core/jni/android/graphics/TextLayoutCache.h
+++ b/core/jni/android/graphics/TextLayoutCache.h
@@ -30,6 +30,8 @@
#include "unicode/ubidi.h"
#include "unicode/ushape.h"
+#include "HarfbuzzSkia.h"
+#include "harfbuzz-shaper.h"
#include <android_runtime/AndroidRuntime.h>
@@ -52,8 +54,14 @@
// Define the interval in number of cache hits between two statistics dump
#define DEFAULT_DUMP_STATS_CACHE_HIT_INTERVAL 100
+// Define if we want to have Advances debug values
+#define DEBUG_ADVANCES 0
+
namespace android {
+// Harfbuzz uses 26.6 fixed point values for pixel offsets
+#define HB_FIXED_TO_FLOAT(v) (((float) v) * (1.0 / 64))
+
/**
* TextLayoutCacheKey is the Cache key
*/
@@ -149,8 +157,18 @@ public:
advances = new float[count];
this->count = count;
- computeAdvances(paint, chars, start, count, contextCount, dirFlags,
+#if RTL_USE_HARFBUZZ
+ computeAdvancesWithHarfbuzz(paint, chars, start, count, contextCount, dirFlags,
advances, &totalAdvance);
+#else
+ computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
+ advances, &totalAdvance);
+#endif
+#if DEBUG_ADVANCES
+ LOGD("Advances - count=%d - countextCount=%d - totalAdvance=%f - "
+ "adv[0]=%f adv[1]=%f adv[2]=%f adv[3]=%f", count, contextCount, totalAdvance,
+ advances[0], advances[1], advances[2], advances[3]);
+#endif
}
void copyResult(jfloat* outAdvances, jfloat* outTotalAdvance) {
@@ -165,8 +183,108 @@ public:
return sizeof(RunAdvanceDescription) + sizeof(jfloat) * count;
}
- static void computeAdvances(SkPaint* paint, const UChar* chars, size_t start, size_t count,
- size_t contextCount, int dirFlags, jfloat* outAdvances, jfloat* outTotalAdvance) {
+ static void setupShaperItem(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
+ SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
+ int dirFlags) {
+ bool isRTL = dirFlags & 0x1;
+
+ font->klass = &harfbuzzSkiaClass;
+ font->userData = 0;
+ // The values which harfbuzzSkiaClass returns are already scaled to
+ // pixel units, so we just set all these to one to disable further
+ // scaling.
+ font->x_ppem = 1;
+ font->y_ppem = 1;
+ font->x_scale = 1;
+ font->y_scale = 1;
+
+ memset(shaperItem, 0, sizeof(*shaperItem));
+ shaperItem->font = font;
+ shaperItem->face = HB_NewFace(shaperItem->font, harfbuzzSkiaGetTable);
+
+ // We cannot know, ahead of time, how many glyphs a given script run
+ // will produce. We take a guess that script runs will not produce more
+ // than twice as many glyphs as there are code points plus a bit of
+ // padding and fallback if we find that we are wrong.
+ createGlyphArrays(shaperItem, (contextCount + 2) * 2);
+
+ // Free memory for clusters if needed and recreate the clusters array
+ if (shaperItem->log_clusters) {
+ delete shaperItem->log_clusters;
+ }
+ shaperItem->log_clusters = new unsigned short[contextCount];
+
+ shaperItem->item.pos = start;
+ shaperItem->item.length = count;
+ shaperItem->item.bidiLevel = isRTL;
+ shaperItem->item.script = isRTL ? HB_Script_Arabic : HB_Script_Common;
+
+ shaperItem->string = chars;
+ shaperItem->stringLength = contextCount;
+
+ fontData->textSize = paint->getTextSize();
+ fontData->fakeBold = paint->isFakeBoldText();
+ fontData->fakeItalic = (paint->getTextSkewX() > 0);
+ fontData->typeFace = paint->getTypeface();
+
+ shaperItem->font->userData = fontData;
+ }
+
+ static void shapeWithHarfbuzz(HB_ShaperItem* shaperItem, HB_FontRec* font, FontData* fontData,
+ SkPaint* paint, const UChar* chars, size_t start, size_t count, size_t contextCount,
+ int dirFlags) {
+ // Setup Harfbuzz Shaper
+ setupShaperItem(shaperItem, font, fontData, paint, chars, start, count,
+ contextCount, dirFlags);
+
+ // Shape
+ resetGlyphArrays(shaperItem);
+ while (!HB_ShapeItem(shaperItem)) {
+ // We overflowed our arrays. Resize and retry.
+ // HB_ShapeItem fills in shaperItem.num_glyphs with the needed size.
+ deleteGlyphArrays(shaperItem);
+ createGlyphArrays(shaperItem, shaperItem->num_glyphs << 1);
+ resetGlyphArrays(shaperItem);
+ }
+ }
+
+ static void computeAdvancesWithHarfbuzz(SkPaint* paint, const UChar* chars, size_t start,
+ size_t count, size_t contextCount, int dirFlags,
+ jfloat* outAdvances, jfloat* outTotalAdvance) {
+
+ bool isRTL = dirFlags & 0x1;
+
+ HB_ShaperItem shaperItem;
+ HB_FontRec font;
+ FontData fontData;
+ shapeWithHarfbuzz(&shaperItem, &font, &fontData, paint, chars, start, count,
+ contextCount, dirFlags);
+
+#if DEBUG_ADVANCES
+ LOGD("HARFBUZZ -- num_glypth=%d", shaperItem.num_glyphs);
+#endif
+
+ jfloat totalAdvance = 0;
+ for (size_t i = 0; i < count; i++) {
+ // Be careful: we need to use roundf() for doing the same way as Skia is doing
+ totalAdvance += outAdvances[i] = roundf(HB_FIXED_TO_FLOAT(shaperItem.advances[i]));
+
+#if DEBUG_ADVANCES
+ LOGD("hb-adv = %d - rebased = %f - total = %f", shaperItem.advances[i], outAdvances[i],
+ totalAdvance);
+#endif
+ }
+
+ deleteGlyphArrays(&shaperItem);
+ HB_FreeFace(shaperItem.face);
+
+ *outTotalAdvance = totalAdvance;
+ }
+
+ static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars, size_t start,
+ size_t count, size_t contextCount, int dirFlags,
+ jfloat* outAdvances, jfloat* outTotalAdvance) {
+
SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
jchar* buffer = tempBuffer.get();
@@ -199,6 +317,9 @@ public:
jfloat totalAdvance = 0;
if (widths < count) {
+#if DEBUG_ADVANCES
+ LOGD("ICU -- count=%d", widths);
+#endif
// Skia operates on code points, not code units, so surrogate pairs return only
// one value. Expand the result so we have one value per UTF-16 code unit.
@@ -213,10 +334,19 @@ public:
text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
outAdvances[p++] = 0;
}
+#if DEBUG_ADVANCES
+ LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
}
} else {
+#if DEBUG_ADVANCES
+ LOGD("ICU -- count=%d", count);
+#endif
for (size_t i = 0; i < count; i++) {
totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
+#if DEBUG_ADVANCES
+ LOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
+#endif
}
}
*outTotalAdvance = totalAdvance;
@@ -228,6 +358,32 @@ private:
size_t count;
uint32_t elapsedTime;
+
+ static void deleteGlyphArrays(HB_ShaperItem* shaperItem) {
+ delete[] shaperItem->glyphs;
+ delete[] shaperItem->attributes;
+ delete[] shaperItem->advances;
+ delete[] shaperItem->offsets;
+ }
+
+ static void createGlyphArrays(HB_ShaperItem* shaperItem, int size) {
+ shaperItem->glyphs = new HB_Glyph[size];
+ shaperItem->attributes = new HB_GlyphAttributes[size];
+ shaperItem->advances = new HB_Fixed[size];
+ shaperItem->offsets = new HB_FixedPoint[size];
+ shaperItem->num_glyphs = size;
+ }
+
+ static void resetGlyphArrays(HB_ShaperItem* shaperItem) {
+ int size = shaperItem->num_glyphs;
+ // All the types here don't have pointers. It is safe to reset to
+ // zero unless Harfbuzz breaks the compatibility in the future.
+ memset(shaperItem->glyphs, 0, size * sizeof(shaperItem->glyphs[0]));
+ memset(shaperItem->attributes, 0, size * sizeof(shaperItem->attributes[0]));
+ memset(shaperItem->advances, 0, size * sizeof(shaperItem->advances[0]));
+ memset(shaperItem->offsets, 0, size * sizeof(shaperItem->offsets[0]));
+ }
+
}; // RunAdvanceDescription