8220231: Cache HarfBuzz face object for same font's text layout calls
Reviewed-by: prr, avu, serb
This commit is contained in:
parent
a9bfe45ca8
commit
b9f32c8148
src/java.desktop
macosx
share
test/jdk/java/awt/font/TextLayout
@ -77,18 +77,11 @@ public final class CFont extends PhysicalFont implements FontSubstitution {
|
||||
throw new InternalError("Not implemented");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getLayoutTableCache() {
|
||||
return getLayoutTableCacheNative(getNativeFontPtr());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getTableBytes(int tag) {
|
||||
return getTableBytesNative(getNativeFontPtr(), tag);
|
||||
}
|
||||
|
||||
private native synchronized long getLayoutTableCacheNative(long nativeFontPtr);
|
||||
|
||||
private native byte[] getTableBytesNative(long nativeFontPtr, int tag);
|
||||
|
||||
private static native long createNativeFont(final String nativeFontName,
|
||||
|
@ -26,8 +26,6 @@
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
|
||||
|
||||
#import "fontscalerdefs.h"
|
||||
|
||||
#define MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE 256
|
||||
|
||||
@interface AWTFont : NSObject {
|
||||
@ -35,7 +33,6 @@
|
||||
NSFont *fFont;
|
||||
CGFontRef fNativeCGFont;
|
||||
BOOL fIsFakeItalic;
|
||||
TTLayoutTableCache* layoutTableCache;
|
||||
}
|
||||
|
||||
+ (AWTFont *) awtFontForName:(NSString *)name
|
||||
|
@ -42,33 +42,10 @@
|
||||
if (self) {
|
||||
fFont = [font retain];
|
||||
fNativeCGFont = CTFontCopyGraphicsFont((CTFontRef)font, NULL);
|
||||
layoutTableCache = NULL;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
static TTLayoutTableCache* newCFontLayoutTableCache() {
|
||||
TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
ltc->entries[i].len = -1;
|
||||
}
|
||||
}
|
||||
return ltc;
|
||||
}
|
||||
|
||||
static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
|
||||
}
|
||||
if (ltc->kernPairs) free(ltc->kernPairs);
|
||||
free(ltc);
|
||||
}
|
||||
}
|
||||
|
||||
- (void) dealloc {
|
||||
[fFont release];
|
||||
fFont = nil;
|
||||
@ -76,10 +53,6 @@ static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
if (fNativeCGFont) {
|
||||
CGFontRelease(fNativeCGFont);
|
||||
fNativeCGFont = NULL;
|
||||
if (layoutTableCache != NULL) {
|
||||
freeCFontLayoutTableCache(layoutTableCache);
|
||||
layoutTableCache = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
[super dealloc];
|
||||
@ -90,10 +63,6 @@ static void freeCFontLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
CGFontRelease(fNativeCGFont);
|
||||
fNativeCGFont = NULL;
|
||||
}
|
||||
if (layoutTableCache != NULL) {
|
||||
freeCFontLayoutTableCache(layoutTableCache);
|
||||
layoutTableCache = NULL;
|
||||
}
|
||||
[super finalize];
|
||||
}
|
||||
|
||||
@ -431,23 +400,6 @@ Java_sun_font_CFont_getCGFontPtrNative
|
||||
return (jlong)(awtFont->fNativeCGFont);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_CFont
|
||||
* Method: getLayoutTableCacheNative
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_font_CFont_getLayoutTableCacheNative
|
||||
(JNIEnv *env, jclass clazz,
|
||||
jlong awtFontPtr)
|
||||
{
|
||||
AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
|
||||
if (awtFont->layoutTableCache == NULL) {
|
||||
awtFont->layoutTableCache = newCFontLayoutTableCache();
|
||||
}
|
||||
return (jlong)(awtFont->layoutTableCache);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_CFont
|
||||
* Method: getTableBytesNative
|
||||
|
@ -465,13 +465,6 @@ public abstract class Font2D {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* implemented for fonts backed by an sfnt that has
|
||||
* OpenType or AAT layout tables.
|
||||
*/
|
||||
protected long getLayoutTableCache() {
|
||||
return 0L;
|
||||
}
|
||||
|
||||
/* Used only on OS X.
|
||||
*/
|
||||
protected long getPlatformNativeFontPtr() {
|
||||
|
@ -181,25 +181,6 @@ public abstract class FontScaler implements DisposerRecord {
|
||||
abstract int getMissingGlyphCode() throws FontScalerException;
|
||||
abstract int getGlyphCode(char charCode) throws FontScalerException;
|
||||
|
||||
/* This method returns table cache used by native layout engine.
|
||||
* This cache is essentially just small collection of
|
||||
* pointers to various truetype tables. See definition of TTLayoutTableCache
|
||||
* in the fontscalerdefs.h for more details.
|
||||
*
|
||||
* Note that tables themselves have same format as defined in the truetype
|
||||
* specification, i.e. font scaler do not need to perform any preprocessing.
|
||||
*
|
||||
* Probably it is better to have API to request pointers to each table
|
||||
* separately instead of requesting pointer to some native structure.
|
||||
* (then there is not need to share its definition by different
|
||||
* implementations of scaler).
|
||||
* However, this means multiple JNI calls and potential impact on performance.
|
||||
*
|
||||
* Note: return value 0 is legal.
|
||||
* This means tables are not available (e.g. type1 font).
|
||||
*/
|
||||
abstract long getLayoutTableCache() throws FontScalerException;
|
||||
|
||||
/* Used by the OpenType engine for mark positioning. */
|
||||
abstract Point2D.Float getGlyphPoint(long pScalerContext,
|
||||
int glyphCode, int ptNumber)
|
||||
|
@ -163,10 +163,6 @@ class FreetypeFontScaler extends FontScaler {
|
||||
.getNullScaler().getGlyphVectorOutline(0L, glyphs, numGlyphs, x, y);
|
||||
}
|
||||
|
||||
synchronized long getLayoutTableCache() throws FontScalerException {
|
||||
return getLayoutTableCacheNative(nativeScaler);
|
||||
}
|
||||
|
||||
public synchronized void dispose() {
|
||||
if (nativeScaler != 0L) {
|
||||
disposeNativeScaler(font.get(), nativeScaler);
|
||||
@ -243,8 +239,6 @@ class FreetypeFontScaler extends FontScaler {
|
||||
native Point2D.Float getGlyphPointNative(Font2D font,
|
||||
long pScalerContext, long pScaler, int glyphCode, int ptNumber);
|
||||
|
||||
private native long getLayoutTableCacheNative(long pScaler);
|
||||
|
||||
private native void disposeNativeScaler(Font2D font2D, long pScaler);
|
||||
|
||||
private native int getGlyphCodeNative(Font2D font, long pScaler, char charCode);
|
||||
|
@ -64,8 +64,6 @@ class NullFontScaler extends FontScaler {
|
||||
return new GeneralPath();
|
||||
}
|
||||
|
||||
long getLayoutTableCache() {return 0L;}
|
||||
|
||||
long createScalerContext(double[] matrix, int aa,
|
||||
int fm, float boldness, float italic, boolean disableHinting) {
|
||||
return getNullScalerContext();
|
||||
|
@ -31,10 +31,12 @@
|
||||
package sun.font;
|
||||
|
||||
import sun.font.GlyphLayout.*;
|
||||
import sun.java2d.Disposer;
|
||||
import sun.java2d.DisposerRecord;
|
||||
|
||||
import java.awt.geom.Point2D;
|
||||
import java.lang.ref.SoftReference;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/*
|
||||
@ -150,8 +152,10 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory
|
||||
}
|
||||
|
||||
static WeakHashMap<Font2D, Boolean> aatInfo = new WeakHashMap<>();
|
||||
private static final WeakHashMap<Font2D, FaceRef> facePtr =
|
||||
new WeakHashMap<>();
|
||||
|
||||
private boolean isAAT(Font2D font) {
|
||||
private static boolean isAAT(Font2D font) {
|
||||
Boolean aatObj;
|
||||
synchronized (aatInfo) {
|
||||
aatObj = aatInfo.get(font);
|
||||
@ -175,30 +179,67 @@ public final class SunLayoutEngine implements LayoutEngine, LayoutEngineFactory
|
||||
return aat;
|
||||
}
|
||||
|
||||
private long getFacePtr(Font2D font2D) {
|
||||
FaceRef ref;
|
||||
synchronized (facePtr) {
|
||||
ref = facePtr.computeIfAbsent(font2D, FaceRef::new);
|
||||
}
|
||||
return ref.getNativePtr();
|
||||
}
|
||||
|
||||
public void layout(FontStrikeDesc desc, float[] mat, float ptSize, int gmask,
|
||||
int baseIndex, TextRecord tr, int typo_flags,
|
||||
Point2D.Float pt, GVData data) {
|
||||
Font2D font = key.font();
|
||||
FontStrike strike = font.getStrike(desc);
|
||||
long layoutTables = font.getLayoutTableCache();
|
||||
long pNativeFont = font.getPlatformNativeFontPtr(); // used on OSX
|
||||
// pScaler probably not needed long term.
|
||||
long pScaler = 0L;
|
||||
if (font instanceof FileFont) {
|
||||
pScaler = ((FileFont)font).getScaler().nativeScaler;
|
||||
long pFace = getFacePtr(font);
|
||||
if (pFace != 0) {
|
||||
shape(font, strike, ptSize, mat, pNativeFont,
|
||||
pFace, isAAT(font),
|
||||
tr.text, data, key.script(),
|
||||
tr.start, tr.limit, baseIndex, pt,
|
||||
typo_flags, gmask);
|
||||
}
|
||||
shape(font, strike, ptSize, mat, pScaler, pNativeFont,
|
||||
layoutTables, isAAT(font),
|
||||
tr.text, data, key.script(),
|
||||
tr.start, tr.limit, baseIndex, pt,
|
||||
typo_flags, gmask);
|
||||
}
|
||||
|
||||
/* Native method to invoke harfbuzz layout engine */
|
||||
private static native boolean
|
||||
shape(Font2D font, FontStrike strike, float ptSize, float[] mat,
|
||||
long pscaler, long pNativeFont, long layoutTables, boolean aat,
|
||||
long pNativeFont, long pFace, boolean aat,
|
||||
char[] chars, GVData data,
|
||||
int script, int offset, int limit,
|
||||
int baseIndex, Point2D.Float pt, int typo_flags, int slot);
|
||||
|
||||
private static native long createFace(Font2D font,
|
||||
boolean aat,
|
||||
long platformNativeFontPtr);
|
||||
|
||||
private static native void disposeFace(long facePtr);
|
||||
|
||||
private static class FaceRef implements DisposerRecord {
|
||||
private Font2D font;
|
||||
private Long facePtr;
|
||||
|
||||
private FaceRef(Font2D font) {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
private synchronized long getNativePtr() {
|
||||
if (facePtr == null) {
|
||||
facePtr = createFace(font, isAAT(font),
|
||||
font.getPlatformNativeFontPtr());
|
||||
if (facePtr != 0) {
|
||||
Disposer.addObjectRecord(font, this);
|
||||
}
|
||||
font = null;
|
||||
}
|
||||
return facePtr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispose() {
|
||||
disposeFace(facePtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -896,15 +896,6 @@ public class TrueTypeFont extends FileFont {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long getLayoutTableCache() {
|
||||
try {
|
||||
return getScaler().getLayoutTableCache();
|
||||
} catch(FontScalerException fe) {
|
||||
return 0L;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected byte[] getTableBytes(int tag) {
|
||||
ByteBuffer buffer = getTableBuffer(tag);
|
||||
|
@ -88,32 +88,8 @@ typedef struct GlyphInfo {
|
||||
*/
|
||||
#define INVISIBLE_GLYPHS 0xfffe
|
||||
|
||||
#define GSUB_TAG 0x47535542 /* 'GSUB' */
|
||||
#define GPOS_TAG 0x47504F53 /* 'GPOS' */
|
||||
#define GDEF_TAG 0x47444546 /* 'GDEF' */
|
||||
#define HEAD_TAG 0x68656164 /* 'head' */
|
||||
#define MORT_TAG 0x6D6F7274 /* 'mort' */
|
||||
#define MORX_TAG 0x6D6F7278 /* 'morx' */
|
||||
#define KERN_TAG 0x6B65726E /* 'kern' */
|
||||
|
||||
typedef struct TTLayoutTableCacheEntry {
|
||||
const void* ptr;
|
||||
int len;
|
||||
int tag;
|
||||
} TTLayoutTableCacheEntry;
|
||||
|
||||
#define LAYOUTCACHE_ENTRIES 7
|
||||
|
||||
typedef struct TTLayoutTableCache {
|
||||
TTLayoutTableCacheEntry entries[LAYOUTCACHE_ENTRIES];
|
||||
void* kernPairs;
|
||||
} TTLayoutTableCache;
|
||||
|
||||
#include "sunfontids.h"
|
||||
|
||||
JNIEXPORT extern TTLayoutTableCache* newLayoutTableCache();
|
||||
JNIEXPORT extern void freeLayoutTableCache(TTLayoutTableCache* ltc);
|
||||
|
||||
/* If font is malformed then scaler context created by particular scaler
|
||||
* will be replaced by null scaler context.
|
||||
* Note that this context is not compatible with structure of the context
|
||||
|
@ -201,9 +201,7 @@ JDKFontInfo*
|
||||
jobject font2D,
|
||||
jobject fontStrike,
|
||||
jfloat ptSize,
|
||||
jlong pScaler,
|
||||
jlong pNativeFont,
|
||||
jlong layoutTables,
|
||||
jfloatArray matrix,
|
||||
jboolean aat) {
|
||||
|
||||
@ -216,7 +214,6 @@ JDKFontInfo*
|
||||
fi->font2D = font2D;
|
||||
fi->fontStrike = fontStrike;
|
||||
fi->nativeFont = pNativeFont;
|
||||
fi->layoutTables = (TTLayoutTableCache*)layoutTables;
|
||||
fi->aat = aat;
|
||||
(*env)->GetFloatArrayRegion(env, matrix, 0, 4, fi->matrix);
|
||||
fi->ptSize = ptSize;
|
||||
@ -241,9 +238,8 @@ JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
|
||||
jobject fontStrike,
|
||||
jfloat ptSize,
|
||||
jfloatArray matrix,
|
||||
jlong pScaler,
|
||||
jlong pNativeFont,
|
||||
jlong layoutTables,
|
||||
jlong pFace,
|
||||
jboolean aat,
|
||||
jcharArray text,
|
||||
jobject gvdata,
|
||||
@ -256,6 +252,7 @@ JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
|
||||
jint slot) {
|
||||
|
||||
hb_buffer_t *buffer;
|
||||
hb_face_t* hbface;
|
||||
hb_font_t* hbfont;
|
||||
jchar *chars;
|
||||
jsize len;
|
||||
@ -272,7 +269,7 @@ JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
|
||||
|
||||
JDKFontInfo *jdkFontInfo =
|
||||
createJDKFontInfo(env, font2D, fontStrike, ptSize,
|
||||
pScaler, pNativeFont, layoutTables, matrix, aat);
|
||||
pNativeFont, matrix, aat);
|
||||
if (!jdkFontInfo) {
|
||||
return JNI_FALSE;
|
||||
}
|
||||
@ -280,7 +277,8 @@ JNIEXPORT jboolean JNICALL Java_sun_font_SunLayoutEngine_shape
|
||||
jdkFontInfo->font2D = font2D;
|
||||
jdkFontInfo->fontStrike = fontStrike;
|
||||
|
||||
hbfont = hb_jdk_font_create(jdkFontInfo, NULL);
|
||||
hbface = (hb_face_t*) jlong_to_ptr(pFace);
|
||||
hbfont = hb_jdk_font_create(hbface, jdkFontInfo, NULL);
|
||||
|
||||
buffer = hb_buffer_create();
|
||||
hb_buffer_set_script(buffer, getHBScriptCode(script));
|
||||
|
@ -69,7 +69,6 @@ typedef struct {
|
||||
unsigned fontDataOffset;
|
||||
unsigned fontDataLength;
|
||||
unsigned fileSize;
|
||||
TTLayoutTableCache* layoutTables;
|
||||
} FTScalerInfo;
|
||||
|
||||
typedef struct FTScalerContext {
|
||||
@ -251,7 +250,6 @@ Java_sun_font_FreetypeFontScaler_initNativeScaler(
|
||||
if (type == TYPE1_FROM_JAVA) { /* TYPE1 */
|
||||
scalerInfo->fontData = (unsigned char*) malloc(filesize);
|
||||
scalerInfo->directBuffer = NULL;
|
||||
scalerInfo->layoutTables = NULL;
|
||||
scalerInfo->fontDataLength = filesize;
|
||||
|
||||
if (scalerInfo->fontData != NULL) {
|
||||
@ -866,32 +864,6 @@ Java_sun_font_FreetypeFontScaler_getGlyphImageNative(
|
||||
return ptr_to_jlong(glyphInfo);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Class: sun_font_FreetypeFontScaler
|
||||
* Method: getLayoutTableCacheNative
|
||||
* Signature: (J)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL
|
||||
Java_sun_font_FreetypeFontScaler_getLayoutTableCacheNative(
|
||||
JNIEnv *env, jobject scaler, jlong pScaler) {
|
||||
FTScalerInfo *scalerInfo = (FTScalerInfo*) jlong_to_ptr(pScaler);
|
||||
|
||||
if (scalerInfo == NULL) {
|
||||
invalidateJavaScaler(env, scaler, scalerInfo);
|
||||
return 0L;
|
||||
}
|
||||
|
||||
// init layout table cache in font
|
||||
// we're assuming the font is a file font and moreover it is Truetype font
|
||||
// otherwise we shouldn't be able to get here...
|
||||
if (scalerInfo->layoutTables == NULL) {
|
||||
scalerInfo->layoutTables = newLayoutTableCache();
|
||||
}
|
||||
|
||||
return ptr_to_jlong(scalerInfo->layoutTables);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: sun_font_FreetypeFontScaler
|
||||
* Method: disposeNativeScaler
|
||||
|
@ -23,6 +23,9 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
#include "jlong.h"
|
||||
#include "sun_font_SunLayoutEngine.h"
|
||||
|
||||
#include "hb.h"
|
||||
#include "hb-jdk.h"
|
||||
#ifdef MACOSX
|
||||
@ -304,79 +307,113 @@ static void _do_nothing(void) {
|
||||
static void _free_nothing(void*) {
|
||||
}
|
||||
|
||||
struct Font2DPtr {
|
||||
JavaVM* vmPtr;
|
||||
jweak font2DRef;
|
||||
};
|
||||
|
||||
static void cleanupFontInfo(void* data) {
|
||||
Font2DPtr* fontInfo;
|
||||
JNIEnv* env;
|
||||
|
||||
fontInfo = (Font2DPtr*) data;
|
||||
fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1);
|
||||
env->DeleteWeakGlobalRef(fontInfo->font2DRef);
|
||||
free(data);
|
||||
}
|
||||
|
||||
static hb_blob_t *
|
||||
reference_table(hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) {
|
||||
|
||||
JDKFontInfo *jdkFontInfo = (JDKFontInfo*)user_data;
|
||||
JNIEnv* env = jdkFontInfo->env;
|
||||
jobject font2D = jdkFontInfo->font2D;
|
||||
jsize length = 0;
|
||||
void* buffer = NULL;
|
||||
int cacheIdx = 0;
|
||||
Font2DPtr *fontInfo;
|
||||
JNIEnv* env;
|
||||
jobject font2D;
|
||||
jsize length;
|
||||
void* buffer;
|
||||
|
||||
// HB_TAG_NONE is 0 and is used to get the whole font file.
|
||||
// It is not expected to be needed for JDK.
|
||||
if (tag == 0 || jdkFontInfo->layoutTables == NULL) {
|
||||
if (tag == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (cacheIdx=0; cacheIdx<LAYOUTCACHE_ENTRIES; cacheIdx++) {
|
||||
if (tag == jdkFontInfo->layoutTables->entries[cacheIdx].tag) break;
|
||||
fontInfo = (Font2DPtr*)user_data;
|
||||
fontInfo->vmPtr->GetEnv((void**)&env, JNI_VERSION_1_1);
|
||||
if (env == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
font2D = fontInfo->font2DRef;
|
||||
|
||||
if (cacheIdx < LAYOUTCACHE_ENTRIES) { // if found
|
||||
if (jdkFontInfo->layoutTables->entries[cacheIdx].len != -1) {
|
||||
length = jdkFontInfo->layoutTables->entries[cacheIdx].len;
|
||||
buffer = (void*)jdkFontInfo->layoutTables->entries[cacheIdx].ptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (buffer == NULL) {
|
||||
jbyteArray tableBytes = (jbyteArray)
|
||||
env->CallObjectMethod(font2D, sunFontIDs.getTableBytesMID, tag);
|
||||
if (tableBytes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
length = env->GetArrayLength(tableBytes);
|
||||
buffer = calloc(length, sizeof(jbyte));
|
||||
env->GetByteArrayRegion(tableBytes, 0, length, (jbyte*)buffer);
|
||||
|
||||
if (cacheIdx >= LAYOUTCACHE_ENTRIES) { // not a cacheable table
|
||||
return hb_blob_create((const char *)buffer, length,
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
buffer, free);
|
||||
} else {
|
||||
jdkFontInfo->layoutTables->entries[cacheIdx].len = length;
|
||||
jdkFontInfo->layoutTables->entries[cacheIdx].ptr = buffer;
|
||||
}
|
||||
jbyteArray tableBytes = (jbyteArray)
|
||||
env->CallObjectMethod(font2D, sunFontIDs.getTableBytesMID, tag);
|
||||
if (tableBytes == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
length = env->GetArrayLength(tableBytes);
|
||||
buffer = calloc(length, sizeof(jbyte));
|
||||
env->GetByteArrayRegion(tableBytes, 0, length, (jbyte*)buffer);
|
||||
|
||||
return hb_blob_create((const char *)buffer, length,
|
||||
HB_MEMORY_MODE_READONLY,
|
||||
NULL, _free_nothing);
|
||||
HB_MEMORY_MODE_WRITABLE,
|
||||
buffer, free);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
||||
hb_face_t*
|
||||
hb_jdk_face_create(JDKFontInfo *jdkFontInfo,
|
||||
hb_destroy_func_t destroy) {
|
||||
|
||||
hb_face_t *face =
|
||||
hb_face_create_for_tables(reference_table, jdkFontInfo, destroy);
|
||||
|
||||
return face;
|
||||
/*
|
||||
* Class: sun_font_SunLayoutEngine
|
||||
* Method: createFace
|
||||
* Signature: (Lsun/font/Font2D;ZJJ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_sun_font_SunLayoutEngine_createFace(JNIEnv *env,
|
||||
jclass cls,
|
||||
jobject font2D,
|
||||
jboolean aat,
|
||||
jlong platformFontPtr) {
|
||||
#ifdef MACOSX
|
||||
if (aat && platformFontPtr) {
|
||||
hb_face_t *face = hb_coretext_face_create((CGFontRef)platformFontPtr);
|
||||
return ptr_to_jlong(face);
|
||||
}
|
||||
#endif
|
||||
Font2DPtr *fi = (Font2DPtr*)malloc(sizeof(Font2DPtr));
|
||||
if (!fi) {
|
||||
return 0;
|
||||
}
|
||||
JavaVM* vmPtr;
|
||||
env->GetJavaVM(&vmPtr);
|
||||
fi->vmPtr = vmPtr;
|
||||
fi->font2DRef = env->NewWeakGlobalRef(font2D);
|
||||
if (!fi->font2DRef) {
|
||||
free(fi);
|
||||
return 0;
|
||||
}
|
||||
hb_face_t *face = hb_face_create_for_tables(reference_table, fi,
|
||||
cleanupFontInfo);
|
||||
return ptr_to_jlong(face);
|
||||
}
|
||||
|
||||
static hb_font_t* _hb_jdk_font_create(JDKFontInfo *jdkFontInfo,
|
||||
/*
|
||||
* Class: sun_font_SunLayoutEngine
|
||||
* Method: disposeFace
|
||||
* Signature: (J)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_sun_font_SunLayoutEngine_disposeFace(JNIEnv *env,
|
||||
jclass cls,
|
||||
jlong ptr) {
|
||||
hb_face_t* face = (hb_face_t*) jlong_to_ptr(ptr);
|
||||
hb_face_destroy(face);
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
static hb_font_t* _hb_jdk_font_create(hb_face_t* face,
|
||||
JDKFontInfo *jdkFontInfo,
|
||||
hb_destroy_func_t destroy) {
|
||||
|
||||
hb_font_t *font;
|
||||
hb_face_t *face;
|
||||
|
||||
face = hb_jdk_face_create(jdkFontInfo, destroy);
|
||||
font = hb_font_create(face);
|
||||
hb_face_destroy (face);
|
||||
hb_font_set_funcs (font,
|
||||
_hb_jdk_get_font_funcs (),
|
||||
jdkFontInfo, (hb_destroy_func_t) _do_nothing);
|
||||
@ -387,17 +424,11 @@ static hb_font_t* _hb_jdk_font_create(JDKFontInfo *jdkFontInfo,
|
||||
}
|
||||
|
||||
#ifdef MACOSX
|
||||
static hb_font_t* _hb_jdk_ct_font_create(JDKFontInfo *jdkFontInfo) {
|
||||
static hb_font_t* _hb_jdk_ct_font_create(hb_face_t* face,
|
||||
JDKFontInfo *jdkFontInfo) {
|
||||
|
||||
hb_font_t *font = NULL;
|
||||
hb_face_t *face = NULL;
|
||||
if (jdkFontInfo->nativeFont == 0) {
|
||||
return NULL;
|
||||
}
|
||||
face = hb_coretext_face_create((CGFontRef)(jdkFontInfo->nativeFont));
|
||||
font = hb_font_create(face);
|
||||
hb_face_destroy(face);
|
||||
|
||||
hb_font_set_scale(font,
|
||||
HBFloatToFixed(jdkFontInfo->ptSize),
|
||||
HBFloatToFixed(jdkFontInfo->ptSize));
|
||||
@ -405,18 +436,13 @@ static hb_font_t* _hb_jdk_ct_font_create(JDKFontInfo *jdkFontInfo) {
|
||||
}
|
||||
#endif
|
||||
|
||||
hb_font_t* hb_jdk_font_create(JDKFontInfo *jdkFontInfo,
|
||||
hb_font_t* hb_jdk_font_create(hb_face_t* hbFace,
|
||||
JDKFontInfo *jdkFontInfo,
|
||||
hb_destroy_func_t destroy) {
|
||||
|
||||
hb_font_t* font = NULL;
|
||||
|
||||
#ifdef MACOSX
|
||||
if (jdkFontInfo->aat) {
|
||||
font = _hb_jdk_ct_font_create(jdkFontInfo);
|
||||
if (jdkFontInfo->aat && jdkFontInfo->nativeFont) {
|
||||
return _hb_jdk_ct_font_create(hbFace, jdkFontInfo);
|
||||
}
|
||||
#endif
|
||||
if (font == NULL) {
|
||||
font = _hb_jdk_font_create(jdkFontInfo, destroy);
|
||||
}
|
||||
return font;
|
||||
return _hb_jdk_font_create(hbFace, jdkFontInfo, destroy);
|
||||
}
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include "hb.h"
|
||||
#include <jni.h>
|
||||
#include <sunfontids.h>
|
||||
#include <fontscalerdefs.h>
|
||||
|
||||
# ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -40,7 +39,6 @@ typedef struct JDKFontInfo_Struct {
|
||||
jobject font2D;
|
||||
jobject fontStrike;
|
||||
long nativeFont;
|
||||
TTLayoutTableCache *layoutTables;
|
||||
float matrix[4];
|
||||
float ptSize;
|
||||
float xPtSize;
|
||||
@ -65,7 +63,8 @@ hb_face_t *
|
||||
hb_jdk_face_create(JDKFontInfo* jdkFontInfo,
|
||||
hb_destroy_func_t destroy);
|
||||
hb_font_t *
|
||||
hb_jdk_font_create(JDKFontInfo* jdkFontInfo,
|
||||
hb_jdk_font_create(hb_face_t* hbFace,
|
||||
JDKFontInfo* jdkFontInfo,
|
||||
hb_destroy_func_t destroy);
|
||||
|
||||
|
||||
|
@ -344,32 +344,3 @@ Java_sun_font_StrikeCache_getGlyphCacheDescription
|
||||
|
||||
(*env)->ReleasePrimitiveArrayCritical(env, results, nresults, 0);
|
||||
}
|
||||
|
||||
JNIEXPORT TTLayoutTableCache* newLayoutTableCache() {
|
||||
TTLayoutTableCache* ltc = calloc(1, sizeof(TTLayoutTableCache));
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
ltc->entries[i].len = -1;
|
||||
}
|
||||
ltc->entries[0].tag = GDEF_TAG;
|
||||
ltc->entries[1].tag = GPOS_TAG;
|
||||
ltc->entries[2].tag = GSUB_TAG;
|
||||
ltc->entries[3].tag = HEAD_TAG;
|
||||
ltc->entries[4].tag = KERN_TAG;
|
||||
ltc->entries[5].tag = MORT_TAG;
|
||||
ltc->entries[6].tag = MORX_TAG;
|
||||
}
|
||||
return ltc;
|
||||
}
|
||||
|
||||
JNIEXPORT void freeLayoutTableCache(TTLayoutTableCache* ltc) {
|
||||
if (ltc) {
|
||||
int i;
|
||||
for(i=0;i<LAYOUTCACHE_ENTRIES;i++) {
|
||||
if(ltc->entries[i].ptr) free (ltc->entries[i].ptr);
|
||||
}
|
||||
if (ltc->kernPairs) free(ltc->kernPairs);
|
||||
free(ltc);
|
||||
}
|
||||
}
|
||||
|
88
test/jdk/java/awt/font/TextLayout/FontLayoutStressTest.java
Normal file
88
test/jdk/java/awt/font/TextLayout/FontLayoutStressTest.java
Normal file
@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2019 JetBrains s.r.o.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 8220231
|
||||
* @summary Cache HarfBuzz face object for same font's text layout calls
|
||||
* @comment Test layout operations for the same font performed simultaneously
|
||||
* from multiple threads
|
||||
*/
|
||||
|
||||
import java.awt.Font;
|
||||
import java.awt.font.FontRenderContext;
|
||||
import java.awt.font.GlyphVector;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CyclicBarrier;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public class FontLayoutStressTest {
|
||||
private static final int NUMBER_OF_THREADS =
|
||||
Runtime.getRuntime().availableProcessors() * 2;
|
||||
private static final long TIME_TO_RUN_NS = 1_000_000_000; // 1 second
|
||||
private static final Font FONT = new Font(Font.SERIF, Font.PLAIN, 12);
|
||||
private static final FontRenderContext FRC = new FontRenderContext(null,
|
||||
false, false);
|
||||
private static final char[] TEXT = "Lorem ipsum dolor sit amet, ..."
|
||||
.toCharArray();
|
||||
|
||||
private static double doLayout() {
|
||||
GlyphVector gv = FONT.layoutGlyphVector(FRC, TEXT, 0, TEXT.length,
|
||||
Font.LAYOUT_LEFT_TO_RIGHT);
|
||||
return gv.getGlyphPosition(gv.getNumGlyphs()).getX();
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws Throwable {
|
||||
double expectedWidth = doLayout();
|
||||
AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
CyclicBarrier barrier = new CyclicBarrier(NUMBER_OF_THREADS);
|
||||
List<Thread> threads = new ArrayList<>();
|
||||
for (int i = 0; i < NUMBER_OF_THREADS; i++) {
|
||||
Thread thread = new Thread(() -> {
|
||||
try {
|
||||
barrier.await();
|
||||
long timeToStop = System.nanoTime() + TIME_TO_RUN_NS;
|
||||
while (System.nanoTime() < timeToStop) {
|
||||
double width = doLayout();
|
||||
if (width != expectedWidth) {
|
||||
throw new RuntimeException(
|
||||
"Unexpected layout result");
|
||||
}
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
throwableRef.set(e);
|
||||
}
|
||||
});
|
||||
threads.add(thread);
|
||||
thread.start();
|
||||
}
|
||||
for (Thread thread : threads) {
|
||||
thread.join();
|
||||
}
|
||||
Throwable throwable = throwableRef.get();
|
||||
if (throwable != null) {
|
||||
throw throwable;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user