Merge "Avoid copying of font table data, provide raw font bytes" into nyc-dev
This commit is contained in:
@@ -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",
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user