Merge "Avoid copying of font table data, provide raw font bytes" into nyc-dev

am: c147dbb

* commit 'c147dbbca4ea1870bcf88c5889e6a83865ceed54':
  Avoid copying of font table data, provide raw font bytes

Change-Id: Icf7e1aa1bc8ae759aaff94a3eeea7261a5456b47
This commit is contained in:
Raph Levien
2016-04-08 16:48:25 +00:00
committed by android-build-merger
5 changed files with 113 additions and 47 deletions

View File

@@ -53,36 +53,14 @@ static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
fontFamily->Unref(); fontFamily->Unref();
} }
static jboolean addSkTypeface(FontFamily* family, SkTypeface* face) { static jboolean addSkTypeface(FontFamily* family, SkTypeface* face, const void* fontData,
MinikinFont* minikinFont = new MinikinFontSkia(face); size_t fontSize, int ttcIndex) {
MinikinFont* minikinFont = new MinikinFontSkia(face, fontData, fontSize, ttcIndex);
bool result = family->addFont(minikinFont); bool result = family->addFont(minikinFont);
minikinFont->Unref(); minikinFont->Unref();
return result; return result;
} }
static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jstring path,
jint ttcIndex) {
NPE_CHECK_RETURN_ZERO(env, path);
ScopedUtfChars str(env, path);
SkTypeface* face = SkTypeface::CreateFromFile(str.c_str(), ttcIndex);
if (face == NULL) {
ALOGE("addFont failed to create font %s", str.c_str());
return false;
}
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
return addSkTypeface(fontFamily, face);
}
static struct {
jmethodID mGet;
jmethodID mSize;
} gListClassInfo;
static struct {
jfieldID mTag;
jfieldID mStyleValue;
} gAxisClassInfo;
static void release_global_ref(const void* /*data*/, void* context) { static void release_global_ref(const void* /*data*/, void* context) {
JNIEnv* env = AndroidRuntime::getJNIEnv(); JNIEnv* env = AndroidRuntime::getJNIEnv();
bool needToAttach = (env == NULL); bool needToAttach = (env == NULL);
@@ -106,6 +84,47 @@ static void release_global_ref(const void* /*data*/, void* context) {
} }
} }
static jboolean FontFamily_addFont(JNIEnv* env, jobject clazz, jlong familyPtr, jobject bytebuf,
jint ttcIndex) {
NPE_CHECK_RETURN_ZERO(env, bytebuf);
const void* fontPtr = env->GetDirectBufferAddress(bytebuf);
if (fontPtr == NULL) {
ALOGE("addFont failed to create font, buffer invalid");
return false;
}
jlong fontSize = env->GetDirectBufferCapacity(bytebuf);
if (fontSize < 0) {
ALOGE("addFont failed to create font, buffer size invalid");
return false;
}
jobject fontRef = MakeGlobalRefOrDie(env, bytebuf);
SkAutoTUnref<SkData> data(SkData::NewWithProc(fontPtr, fontSize,
release_global_ref, reinterpret_cast<void*>(fontRef)));
std::unique_ptr<SkStreamAsset> fontData(new SkMemoryStream(data));
SkFontMgr::FontParameters params;
params.setCollectionIndex(ttcIndex);
SkAutoTUnref<SkFontMgr> fm(SkFontMgr::RefDefault());
SkTypeface* face = fm->createFromStream(fontData.release(), params);
if (face == NULL) {
ALOGE("addFont failed to create font");
return false;
}
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
return addSkTypeface(fontFamily, face, fontPtr, (size_t)fontSize, ttcIndex);
}
static struct {
jmethodID mGet;
jmethodID mSize;
} gListClassInfo;
static struct {
jfieldID mTag;
jfieldID mStyleValue;
} gAxisClassInfo;
static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr, static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong familyPtr,
jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) { jobject font, jint ttcIndex, jobject listOfAxis, jint weight, jboolean isItalic) {
NPE_CHECK_RETURN_ZERO(env, font); NPE_CHECK_RETURN_ZERO(env, font);
@@ -133,7 +152,7 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong
} }
} }
void* fontPtr = env->GetDirectBufferAddress(font); const void* fontPtr = env->GetDirectBufferAddress(font);
if (fontPtr == NULL) { if (fontPtr == NULL) {
ALOGE("addFont failed to create font, buffer invalid"); ALOGE("addFont failed to create font, buffer invalid");
return false; return false;
@@ -159,7 +178,7 @@ static jboolean FontFamily_addFontWeightStyle(JNIEnv* env, jobject clazz, jlong
return false; return false;
} }
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
MinikinFont* minikinFont = new MinikinFontSkia(face); MinikinFont* minikinFont = new MinikinFontSkia(face, fontPtr, (size_t)fontSize, ttcIndex);
fontFamily->addFont(minikinFont, FontStyle(weight / 100, isItalic)); fontFamily->addFont(minikinFont, FontStyle(weight / 100, isItalic));
minikinFont->Unref(); minikinFont->Unref();
return true; return true;
@@ -191,6 +210,7 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt
return false; return false;
} }
size_t bufSize = asset->getLength();
SkAutoTUnref<SkData> data(SkData::NewWithProc(buf, asset->getLength(), releaseAsset, asset)); SkAutoTUnref<SkData> data(SkData::NewWithProc(buf, asset->getLength(), releaseAsset, asset));
SkMemoryStream* stream = new SkMemoryStream(data); SkMemoryStream* stream = new SkMemoryStream(data);
// CreateFromStream takes ownership of stream. // CreateFromStream takes ownership of stream.
@@ -200,7 +220,7 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt
return false; return false;
} }
FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr); FontFamily* fontFamily = reinterpret_cast<FontFamily*>(familyPtr);
return addSkTypeface(fontFamily, face); return addSkTypeface(fontFamily, face, buf, bufSize, /* ttcIndex */ 0);
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@@ -208,7 +228,7 @@ static jboolean FontFamily_addFontFromAsset(JNIEnv* env, jobject, jlong familyPt
static const JNINativeMethod gFontFamilyMethods[] = { static const JNINativeMethod gFontFamilyMethods[] = {
{ "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create }, { "nCreateFamily", "(Ljava/lang/String;I)J", (void*)FontFamily_create },
{ "nUnrefFamily", "(J)V", (void*)FontFamily_unref }, { "nUnrefFamily", "(J)V", (void*)FontFamily_unref },
{ "nAddFont", "(JLjava/lang/String;I)Z", (void*)FontFamily_addFont }, { "nAddFont", "(JLjava/nio/ByteBuffer;I)Z", (void*)FontFamily_addFont },
{ "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z", { "nAddFontWeightStyle", "(JLjava/nio/ByteBuffer;ILjava/util/List;IZ)Z",
(void*)FontFamily_addFontWeightStyle }, (void*)FontFamily_addFontWeightStyle },
{ "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z", { "nAddFontFromAsset", "(JLandroid/content/res/AssetManager;Ljava/lang/String;)Z",

View File

@@ -17,8 +17,12 @@
package android.graphics; package android.graphics;
import android.content.res.AssetManager; import android.content.res.AssetManager;
import android.util.Log;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.List; import java.util.List;
/** /**
@@ -27,6 +31,9 @@ import java.util.List;
* @hide * @hide
*/ */
public class FontFamily { public class FontFamily {
private static String TAG = "FontFamily";
/** /**
* @hide * @hide
*/ */
@@ -62,7 +69,15 @@ public class FontFamily {
} }
public boolean addFont(String path, int ttcIndex) { public boolean addFont(String path, int ttcIndex) {
return nAddFont(mNativePtr, path, ttcIndex); try (FileInputStream file = new FileInputStream(path)) {
FileChannel fileChannel = file.getChannel();
long fontSize = fileChannel.size();
ByteBuffer fontBuffer = fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fontSize);
return nAddFont(mNativePtr, fontBuffer, ttcIndex);
} catch (IOException e) {
Log.e(TAG, "Error mapping font file " + path);
return false;
}
} }
public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes, public boolean addFontWeightStyle(ByteBuffer font, int ttcIndex, List<FontListParser.Axis> axes,
@@ -76,7 +91,7 @@ public class FontFamily {
private static native long nCreateFamily(String lang, int variant); private static native long nCreateFamily(String lang, int variant);
private static native void nUnrefFamily(long nativePtr); private static native void nUnrefFamily(long nativePtr);
private static native boolean nAddFont(long nativeFamily, String path, int ttcIndex); private static native boolean nAddFont(long nativeFamily, ByteBuffer font, int ttcIndex);
private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font, private static native boolean nAddFontWeightStyle(long nativeFamily, ByteBuffer font,
int ttcIndex, List<FontListParser.Axis> listOfAxis, int ttcIndex, List<FontListParser.Axis> listOfAxis,
int weight, boolean isItalic); int weight, boolean isItalic);

View File

@@ -22,8 +22,9 @@
namespace android { namespace android {
MinikinFontSkia::MinikinFontSkia(SkTypeface *typeface) : MinikinFontSkia::MinikinFontSkia(SkTypeface* typeface, const void* fontData, size_t fontSize,
mTypeface(typeface) { int ttcIndex) :
mTypeface(typeface), mFontData(fontData), mFontSize(fontSize), mTtcIndex(ttcIndex) {
} }
MinikinFontSkia::~MinikinFontSkia() { MinikinFontSkia::~MinikinFontSkia() {
@@ -66,22 +67,38 @@ void MinikinFontSkia::GetBounds(MinikinRect* bounds, uint32_t glyph_id,
bounds->mBottom = skBounds.fBottom; bounds->mBottom = skBounds.fBottom;
} }
bool MinikinFontSkia::GetTable(uint32_t tag, uint8_t *buf, size_t *size) { const void* MinikinFontSkia::GetTable(uint32_t tag, size_t* size, MinikinDestroyFunc* destroy) {
if (buf == NULL) { // we don't have a buffer to the font data, copy to own buffer
const size_t tableSize = mTypeface->getTableSize(tag); const size_t tableSize = mTypeface->getTableSize(tag);
*size = tableSize; *size = tableSize;
return tableSize != 0; if (tableSize == 0) {
} else { return nullptr;
const size_t actualSize = mTypeface->getTableData(tag, 0, *size, buf);
*size = actualSize;
return actualSize != 0;
} }
void* buf = malloc(tableSize);
if (buf == nullptr) {
return nullptr;
}
mTypeface->getTableData(tag, 0, tableSize, buf);
*destroy = free;
return buf;
} }
SkTypeface *MinikinFontSkia::GetSkTypeface() const { SkTypeface *MinikinFontSkia::GetSkTypeface() const {
return mTypeface; return mTypeface;
} }
const void* MinikinFontSkia::GetFontData() const {
return mFontData;
}
size_t MinikinFontSkia::GetFontSize() const {
return mFontSize;
}
int MinikinFontSkia::GetFontIndex() const {
return mTtcIndex;
}
int32_t MinikinFontSkia::GetUniqueId() const { int32_t MinikinFontSkia::GetUniqueId() const {
return mTypeface->uniqueID(); return mTypeface->uniqueID();
} }

View File

@@ -28,7 +28,8 @@ namespace android {
class ANDROID_API MinikinFontSkia : public MinikinFont { class ANDROID_API MinikinFontSkia : public MinikinFont {
public: public:
// Note: this takes ownership of the reference (will unref on dtor) // Note: this takes ownership of the reference (will unref on dtor)
explicit MinikinFontSkia(SkTypeface *typeface); explicit MinikinFontSkia(SkTypeface *typeface, const void* fontData, size_t fontSize,
int ttcIndex);
~MinikinFontSkia(); ~MinikinFontSkia();
@@ -38,20 +39,30 @@ public:
void GetBounds(MinikinRect* bounds, uint32_t glyph_id, void GetBounds(MinikinRect* bounds, uint32_t glyph_id,
const MinikinPaint &paint) const; const MinikinPaint &paint) const;
// If buf is NULL, just update size const void* GetTable(uint32_t tag, size_t* size, MinikinDestroyFunc* destroy);
bool GetTable(uint32_t tag, uint8_t *buf, size_t *size);
int32_t GetUniqueId() const; int32_t GetUniqueId() const;
SkTypeface* GetSkTypeface() const; SkTypeface* GetSkTypeface() const;
// Access to underlying raw font bytes
const void* GetFontData() const;
size_t GetFontSize() const;
int GetFontIndex() const;
static uint32_t packPaintFlags(const SkPaint* paint); static uint32_t packPaintFlags(const SkPaint* paint);
static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags); static void unpackPaintFlags(SkPaint* paint, uint32_t paintFlags);
// set typeface and fake bold/italic parameters // set typeface and fake bold/italic parameters
static void populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery); static void populateSkPaint(SkPaint* paint, const MinikinFont* font, FontFakery fakery);
private: private:
SkTypeface *mTypeface; SkTypeface* mTypeface;
// A raw pointer to the font data - it should be owned by some other object with
// lifetime at least as long as this object.
const void* mFontData;
size_t mFontSize;
int mTtcIndex;
}; };
} // namespace android } // namespace android

View File

@@ -66,7 +66,10 @@ static FontCollection *makeFontCollection() {
ALOGD("makeFontCollection adding %s", fn); ALOGD("makeFontCollection adding %s", fn);
SkTypeface *skFace = SkTypeface::CreateFromFile(fn); SkTypeface *skFace = SkTypeface::CreateFromFile(fn);
if (skFace != NULL) { if (skFace != NULL) {
MinikinFont *font = new MinikinFontSkia(skFace); // TODO: might be a nice optimization to get access to the underlying font
// data, but would require us opening the file ourselves and passing that
// to the appropriate Create method of SkTypeface.
MinikinFont *font = new MinikinFontSkia(skFace, NULL, 0, 0);
family->addFont(font); family->addFont(font);
font->Unref(); font->Unref();
} else { } else {