8220231: Cache HarfBuzz face object for same font's text layout calls
Reviewed-by: prr, avu, serb
--- a/src/java.desktop/macosx/classes/sun/font/CFont.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/macosx/classes/sun/font/CFont.java Thu Apr 11 10:49:36 2019 -0700
@@ -78,17 +78,10 @@
}
@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,
--- a/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h Thu Apr 11 10:49:36 2019 -0700
@@ -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
--- a/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Thu Apr 11 10:49:36 2019 -0700
@@ -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 @@
if (fNativeCGFont) {
CGFontRelease(fNativeCGFont);
fNativeCGFont = NULL;
- if (layoutTableCache != NULL) {
- freeCFontLayoutTableCache(layoutTableCache);
- layoutTableCache = NULL;
- }
}
[super dealloc];
@@ -90,10 +63,6 @@
CGFontRelease(fNativeCGFont);
fNativeCGFont = NULL;
}
- if (layoutTableCache != NULL) {
- freeCFontLayoutTableCache(layoutTableCache);
- layoutTableCache = NULL;
- }
[super finalize];
}
@@ -433,23 +402,6 @@
/*
* 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
* Signature: (JI)[B
*/
--- a/src/java.desktop/share/classes/sun/font/Font2D.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/classes/sun/font/Font2D.java Thu Apr 11 10:49:36 2019 -0700
@@ -465,13 +465,6 @@
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() {
--- a/src/java.desktop/share/classes/sun/font/FontScaler.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/classes/sun/font/FontScaler.java Thu Apr 11 10:49:36 2019 -0700
@@ -181,25 +181,6 @@
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)
--- a/src/java.desktop/share/classes/sun/font/FreetypeFontScaler.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/classes/sun/font/FreetypeFontScaler.java Thu Apr 11 10:49:36 2019 -0700
@@ -163,10 +163,6 @@
.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 @@
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);
--- a/src/java.desktop/share/classes/sun/font/NullFontScaler.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/classes/sun/font/NullFontScaler.java Thu Apr 11 10:49:36 2019 -0700
@@ -64,8 +64,6 @@
return new GeneralPath();
}
- long getLayoutTableCache() {return 0L;}
-
long createScalerContext(double[] matrix, int aa,
int fm, float boldness, float italic, boolean disableHinting) {
return getNullScalerContext();
--- a/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java Thu Apr 11 10:49:36 2019 -0700
@@ -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 @@
}
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 @@
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);
+ }
+ }
}
--- a/src/java.desktop/share/classes/sun/font/TrueTypeFont.java Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/classes/sun/font/TrueTypeFont.java Thu Apr 11 10:49:36 2019 -0700
@@ -897,15 +897,6 @@
}
@Override
- protected long getLayoutTableCache() {
- try {
- return getScaler().getLayoutTableCache();
- } catch(FontScalerException fe) {
- return 0L;
- }
- }
-
- @Override
protected byte[] getTableBytes(int tag) {
ByteBuffer buffer = getTableBuffer(tag);
if (buffer == null) {
--- a/src/java.desktop/share/native/common/font/fontscalerdefs.h Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/native/common/font/fontscalerdefs.h Thu Apr 11 10:49:36 2019 -0700
@@ -88,32 +88,8 @@
*/
#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
--- a/src/java.desktop/share/native/libfontmanager/HBShaper.c Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/native/libfontmanager/HBShaper.c Thu Apr 11 10:49:36 2019 -0700
@@ -201,9 +201,7 @@
jobject font2D,
jobject fontStrike,
jfloat ptSize,
- jlong pScaler,
jlong pNativeFont,
- jlong layoutTables,
jfloatArray matrix,
jboolean aat) {
@@ -216,7 +214,6 @@
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 @@
jobject fontStrike,
jfloat ptSize,
jfloatArray matrix,
- jlong pScaler,
jlong pNativeFont,
- jlong layoutTables,
+ jlong pFace,
jboolean aat,
jcharArray text,
jobject gvdata,
@@ -256,6 +252,7 @@
jint slot) {
hb_buffer_t *buffer;
+ hb_face_t* hbface;
hb_font_t* hbfont;
jchar *chars;
jsize len;
@@ -272,7 +269,7 @@
JDKFontInfo *jdkFontInfo =
createJDKFontInfo(env, font2D, fontStrike, ptSize,
- pScaler, pNativeFont, layoutTables, matrix, aat);
+ pNativeFont, matrix, aat);
if (!jdkFontInfo) {
return JNI_FALSE;
}
@@ -280,7 +277,8 @@
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));
--- a/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/native/libfontmanager/freetypeScaler.c Thu Apr 11 10:49:36 2019 -0700
@@ -69,7 +69,6 @@
unsigned fontDataOffset;
unsigned fontDataLength;
unsigned fileSize;
- TTLayoutTableCache* layoutTables;
} FTScalerInfo;
typedef struct FTScalerContext {
@@ -251,7 +250,6 @@
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 @@
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
--- a/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/native/libfontmanager/hb-jdk-font.cc Thu Apr 11 10:49:36 2019 -0700
@@ -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 _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;
}
-
- 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;
- }
- }
+ font2D = fontInfo->font2DRef;
- 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 @@
}
#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 @@
}
#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);
}
--- a/src/java.desktop/share/native/libfontmanager/hb-jdk.h Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/native/libfontmanager/hb-jdk.h Thu Apr 11 10:49:36 2019 -0700
@@ -29,7 +29,6 @@
#include "hb.h"
#include <jni.h>
#include <sunfontids.h>
-#include <fontscalerdefs.h>
# ifdef __cplusplus
extern "C" {
@@ -40,7 +39,6 @@
jobject font2D;
jobject fontStrike;
long nativeFont;
- TTLayoutTableCache *layoutTables;
float matrix[4];
float ptSize;
float xPtSize;
@@ -65,7 +63,8 @@
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);
--- a/src/java.desktop/share/native/libfontmanager/sunFont.c Thu Apr 11 14:20:16 2019 +0530
+++ b/src/java.desktop/share/native/libfontmanager/sunFont.c Thu Apr 11 10:49:36 2019 -0700
@@ -344,32 +344,3 @@
(*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);
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/java/awt/font/TextLayout/FontLayoutStressTest.java Thu Apr 11 10:49:36 2019 -0700
@@ -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;
+ }
+ }
+}