7162125: [macosx] A font has different behaviour for ligatures depending on its creation mod
Reviewed-by: srl, jgodinez
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CCompositeGlyphMapper.java Mon Nov 16 16:07:46 2015 -0800
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package sun.font;
+
+public final class CCompositeGlyphMapper extends CompositeGlyphMapper {
+
+ private CompositeFont font;
+ private CharToGlyphMapper slotMappers[];
+
+ public CCompositeGlyphMapper(CompositeFont compFont) {
+ super(compFont);
+ font = compFont;
+ slotMappers = new CharToGlyphMapper[font.numSlots];
+ missingGlyph = 0;
+ }
+
+ private CharToGlyphMapper getSlotMapper(int slot) {
+ CharToGlyphMapper mapper = slotMappers[slot];
+ if (mapper == null) {
+ mapper = font.getSlotFont(slot).getMapper();
+ slotMappers[slot] = mapper;
+ }
+ return mapper;
+ }
+
+ public boolean canDisplay(char ch) {
+ int glyph = charToGlyph(ch);
+ return glyph != missingGlyph;
+ }
+
+ private int convertToGlyph(int unicode) {
+ for (int slot = 0; slot < font.numSlots; slot++) {
+ CharToGlyphMapper mapper = getSlotMapper(slot);
+ int glyphCode = mapper.charToGlyph(unicode);
+ // The CFont Mappers will return a negative code
+ // for fonts that will fill the glyph from fallbacks
+ // - cascading font in OSX-speak. But we need to be
+ // know here that only the codes > 0 are really present.
+ if (glyphCode > 0) {
+ glyphCode = compositeGlyphCode(slot, glyphCode);
+ return glyphCode;
+ }
+ }
+ return missingGlyph;
+ }
+
+ public int getNumGlyphs() {
+ int numGlyphs = 0;
+ for (int slot=0; slot<1 /*font.numSlots*/; slot++) {
+ CharToGlyphMapper mapper = slotMappers[slot];
+ if (mapper == null) {
+ mapper = font.getSlotFont(slot).getMapper();
+ slotMappers[slot] = mapper;
+ }
+ numGlyphs += mapper.getNumGlyphs();
+ }
+ return numGlyphs;
+ }
+
+ public int charToGlyph(int unicode) {
+ return convertToGlyph(unicode);
+ }
+
+ public int charToGlyph(char unicode) {
+ return convertToGlyph(unicode);
+ }
+
+ public boolean charsToGlyphsNS(int count, char[] unicodes, int[] glyphs) {
+
+ for (int i=0; i<count; i++) {
+ int code = unicodes[i]; // char is unsigned.
+
+ if (code >= HI_SURROGATE_START &&
+ code <= HI_SURROGATE_END && i < count - 1) {
+ char low = unicodes[i + 1];
+
+ if (low >= LO_SURROGATE_START &&
+ low <= LO_SURROGATE_END) {
+ code = (code - HI_SURROGATE_START) *
+ 0x400 + low - LO_SURROGATE_START + 0x10000;
+ glyphs[i + 1] = INVISIBLE_GLYPH_ID;
+ }
+ }
+
+ glyphs[i] = convertToGlyph(code);
+
+ if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
+ continue;
+ }
+ else if (FontUtilities.isComplexCharCode(code)) {
+ return true;
+ }
+ else if (code >= 0x10000) {
+ i += 1; // Empty glyph slot after surrogate
+ continue;
+ }
+ }
+
+ return false;
+ }
+
+ public void charsToGlyphs(int count, char[] unicodes, int[] glyphs) {
+ for (int i=0; i<count; i++) {
+ int code = unicodes[i]; // char is unsigned.
+
+ if (code >= HI_SURROGATE_START &&
+ code <= HI_SURROGATE_END && i < count - 1) {
+ char low = unicodes[i + 1];
+
+ if (low >= LO_SURROGATE_START &&
+ low <= LO_SURROGATE_END) {
+ code = (code - HI_SURROGATE_START) *
+ 0x400 + low - LO_SURROGATE_START + 0x10000;
+
+ glyphs[i] = convertToGlyph(code);
+ i += 1; // Empty glyph slot after surrogate
+ glyphs[i] = INVISIBLE_GLYPH_ID;
+ continue;
+ }
+ }
+
+ glyphs[i] = convertToGlyph(code);
+ }
+ }
+
+ public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
+ for (int i=0; i<count; i++) {
+ glyphs[i] = convertToGlyph(unicodes[i]);
+ }
+ }
+
+}
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CFont.java Mon Nov 16 16:07:46 2015 -0800
@@ -31,12 +31,13 @@
import java.awt.geom.GeneralPath;;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
// Right now this class is final to avoid a problem with native code.
// For some reason the JNI IsInstanceOf was not working correctly
// so we are checking the class specifically. If we subclass this
// we need to modify the native code in CFontWrapper.m
-public final class CFont extends PhysicalFont {
+public final class CFont extends PhysicalFont implements FontSubstitution {
/* CFontStrike doesn't call these methods so they are unimplemented.
* They are here to meet the requirements of PhysicalFont, needed
@@ -76,6 +77,20 @@
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,
final int style);
private static native void disposeNativeFont(final long nativeFontPtr);
@@ -179,10 +194,51 @@
protected synchronized long getNativeFontPtr() {
if (nativeFontPtr == 0L) {
nativeFontPtr = createNativeFont(nativeFontName, style);
-}
+ }
return nativeFontPtr;
}
+ static native void getCascadeList(long nativeFontPtr, ArrayList<String> listOfString);
+
+ private CompositeFont createCompositeFont() {
+ ArrayList<String> listOfString = new ArrayList<String>();
+ getCascadeList(nativeFontPtr, listOfString);
+
+ FontManager fm = FontManagerFactory.getInstance();
+ int numFonts = 1 + listOfString.size();
+ PhysicalFont[] fonts = new PhysicalFont[numFonts];
+ fonts[0] = this;
+ int idx = 1;
+ for (String s : listOfString) {
+ if (s.equals(".AppleSymbolsFB")) {
+ // Don't know why we get the weird name above .. replace.
+ s = "AppleSymbols";
+ }
+ Font2D f2d = fm.findFont2D(s, Font.PLAIN, FontManager.NO_FALLBACK);
+ if (f2d == null || f2d == this) {
+ continue;
+ }
+ fonts[idx++] = (PhysicalFont)f2d;
+ }
+ if (idx < fonts.length) {
+ PhysicalFont[] orig = fonts;
+ fonts = new PhysicalFont[idx];
+ System.arraycopy(orig, 0, fonts, 0, idx);
+ }
+ CompositeFont compFont = new CompositeFont(fonts);
+ compFont.mapper = new CCompositeGlyphMapper(compFont);
+ return compFont;
+ }
+
+ private CompositeFont compFont;
+
+ public CompositeFont getCompositeFont2D() {
+ if (compFont == null) {
+ compFont = createCompositeFont();
+ }
+ return compFont;
+ }
+
protected synchronized void finalize() {
if (nativeFontPtr != 0) {
disposeNativeFont(nativeFontPtr);
--- a/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/macosx/classes/sun/font/CStrike.java Mon Nov 16 16:07:46 2015 -0800
@@ -31,7 +31,7 @@
import sun.awt.SunHints;
-public final class CStrike extends FontStrike {
+public final class CStrike extends PhysicalStrike {
// Creates the native strike
private static native long createNativeStrikePtr(long nativeFontPtr,
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.h Mon Nov 16 16:07:46 2015 -0800
@@ -26,6 +26,8 @@
#import <Cocoa/Cocoa.h>
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
+#import "fontscalerdefs.h"
+
#define MAX_STACK_ALLOC_GLYPH_BUFFER_SIZE 256
@interface AWTFont : NSObject {
@@ -33,6 +35,7 @@
NSFont *fFont;
CGFontRef fNativeCGFont;
BOOL fIsFakeItalic;
+ TTLayoutTableCache* layoutTableCache;
}
+ (AWTFont *) awtFontForName:(NSString *)name
--- a/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/macosx/native/libawt_lwawt/font/AWTFont.m Mon Nov 16 16:07:46 2015 -0800
@@ -42,10 +42,33 @@
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;
@@ -53,6 +76,10 @@
if (fNativeCGFont) {
CGFontRelease(fNativeCGFont);
fNativeCGFont = NULL;
+ if (layoutTableCache != NULL) {
+ freeCFontLayoutTableCache(layoutTableCache);
+ layoutTableCache = NULL;
+ }
}
[super dealloc];
@@ -63,6 +90,10 @@
CGFontRelease(fNativeCGFont);
fNativeCGFont = NULL;
}
+ if (layoutTableCache != NULL) {
+ freeCFontLayoutTableCache(layoutTableCache);
+ layoutTableCache = NULL;
+ }
[super finalize];
}
@@ -345,6 +376,95 @@
/*
* Class: sun_font_CFont
+ * Method: getPlatformFontPtrNative
+ * Signature: (JI)[B
+ */
+JNIEXPORT jlong JNICALL
+Java_sun_font_CFont_getCGFontPtrNative
+ (JNIEnv *env, jclass clazz,
+ jlong awtFontPtr)
+{
+ AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+ 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
+ * Signature: (JI)[B
+ */
+JNIEXPORT jbyteArray JNICALL
+Java_sun_font_CFont_getTableBytesNative
+ (JNIEnv *env, jclass clazz,
+ jlong awtFontPtr, jint jtag)
+{
+ jbyteArray jbytes = NULL;
+JNF_COCOA_ENTER(env);
+
+ CTFontTableTag tag = (CTFontTableTag)jtag;
+ int i, found = 0;
+ AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+ NSFont* nsFont = awtFont->fFont;
+ CTFontRef ctfont = (CTFontRef)nsFont;
+ CFArrayRef tagsArray =
+ CTFontCopyAvailableTables(ctfont, kCTFontTableOptionNoOptions);
+ CFIndex numTags = CFArrayGetCount(tagsArray);
+ for (i=0; i<numTags; i++) {
+ if (tag ==
+ (CTFontTableTag)(uintptr_t)CFArrayGetValueAtIndex(tagsArray, i)) {
+ found = 1;
+ break;
+ }
+ }
+ CFRelease(tagsArray);
+ if (!found) {
+ return NULL;
+ }
+ CFDataRef table = CTFontCopyTable(ctfont, tag, kCTFontTableOptionNoOptions);
+ if (table == NULL) {
+ return NULL;
+ }
+
+ char *tableBytes = (char*)(CFDataGetBytePtr(table));
+ size_t tableLength = CFDataGetLength(table);
+ if (tableBytes == NULL || tableLength == 0) {
+ CFRelease(table);
+ return NULL;
+ }
+
+ jbytes = (*env)->NewByteArray(env, (jsize)tableLength);
+ if (jbytes == NULL) {
+ return NULL;
+ }
+ (*env)->SetByteArrayRegion(env, jbytes, 0,
+ (jsize)tableLength,
+ (jbyte*)tableBytes);
+ CFRelease(table);
+
+JNF_COCOA_EXIT(env);
+
+ return jbytes;
+}
+
+/*
+ * Class: sun_font_CFont
* Method: initNativeFont
* Signature: (Ljava/lang/String;I)J
*/
@@ -460,3 +580,42 @@
{
}
#endif
+
+/*
+ * Class: sun_awt_FontDescriptor
+ * Method: initIDs
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL
+Java_sun_font_CFont_getCascadeList
+ (JNIEnv *env, jclass cls, jlong awtFontPtr, jobject arrayListOfString)
+{
+ jclass alc = (*env)->FindClass(env, "java/util/ArrayList");
+ if (alc == NULL) return;
+ jmethodID addMID = (*env)->GetMethodID(env, alc, "add", "(Ljava/lang/Object;)Z");
+ if (addMID == NULL) return;
+
+ CFIndex i;
+ AWTFont *awtFont = (AWTFont *)jlong_to_ptr(awtFontPtr);
+ NSFont* nsFont = awtFont->fFont;
+ CTFontRef font = (CTFontRef)nsFont;
+ CFStringRef base = CTFontCopyFullName(font);
+ CFArrayRef codes = CFLocaleCopyISOLanguageCodes();
+
+#ifdef DEBUG
+ NSLog(@"BaseFont is : %@", (NSString*)base);
+#endif
+ CFArrayRef fds = CTFontCopyDefaultCascadeListForLanguages(font, codes);
+ CFIndex cnt = CFArrayGetCount(fds);
+ for (i=0; i<cnt; i++) {
+ CTFontDescriptorRef ref = CFArrayGetValueAtIndex(fds, i);
+ CFStringRef fontname =
+ CTFontDescriptorCopyAttribute(ref, kCTFontNameAttribute);
+#ifdef DEBUG
+ NSLog(@"Font is : %@", (NSString*)fontname);
+#endif
+ jstring jFontName = (jstring)JNFNSToJavaString(env, fontname);
+ (*env)->CallBooleanMethod(env, arrayListOfString, addMID, jFontName);
+ (*env)->DeleteLocalRef(env, jFontName);
+ }
+}
--- a/jdk/src/java.desktop/share/classes/sun/font/CompositeFont.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/CompositeFont.java Mon Nov 16 16:07:46 2015 -0800
@@ -149,6 +149,25 @@
}
}
+ /*
+ * Build a composite from a set of individual slot fonts.
+ */
+ CompositeFont(PhysicalFont[] slotFonts) {
+
+ isStdComposite = false;
+ handle = new Font2DHandle(this);
+ fullName = slotFonts[0].fullName;
+ familyName = slotFonts[0].familyName;
+ style = slotFonts[0].style;
+
+ numMetricsSlots = 1; /* Only the physical Font */
+ numSlots = slotFonts.length;
+
+ components = new PhysicalFont[numSlots];
+ System.arraycopy(slotFonts, 0, components, 0, numSlots);
+ deferredInitialisation = new boolean[numSlots]; // all false.
+ }
+
/* This method is currently intended to be called only from
* FontManager.getCompositeFontUIResource(Font)
* It creates a new CompositeFont with the contents of the Physical
--- a/jdk/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/CompositeGlyphMapper.java Mon Nov 16 16:07:46 2015 -0800
@@ -42,7 +42,7 @@
* this appears to cause problems.
*/
-public final class CompositeGlyphMapper extends CharToGlyphMapper {
+public class CompositeGlyphMapper extends CharToGlyphMapper {
public static final int SLOTMASK = 0xff000000;
public static final int GLYPHMASK = 0x00ffffff;
--- a/jdk/src/java.desktop/share/classes/sun/font/Font2D.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/Font2D.java Mon Nov 16 16:07:46 2015 -0800
@@ -461,10 +461,17 @@
* to check the font class before attempting to run, rather than needing
* to promote this method up from TrueTypeFont
*/
- byte[] getTableBytes(int tag) {
+ protected byte[] getTableBytes(int tag) {
return null;
}
+ /* implemented for fonts backed by an sfnt that has
+ * OpenType or AAT layout tables.
+ */
+ protected long getLayoutTableCache() {
+ return 0L;
+ }
+
/* for layout code */
protected long getUnitsPerEm() {
return 2048;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/java.desktop/share/classes/sun/font/FontSubstitution.java Mon Nov 16 16:07:46 2015 -0800
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+package sun.font;
+
+
+
+/**
+ * Interface that indicates a Font2D that is not a Composite but has the
+ * property that it internally behaves like one, substituting glyphs
+ * from another font at render time.
+ * In this case the Font must provide a way to behave like a regular
+ * composite when that behaviour is not wanted.
+ */
+public interface FontSubstitution {
+ public CompositeFont getCompositeFont2D();
+}
--- a/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/GlyphLayout.java Mon Nov 16 16:07:46 2015 -0800
@@ -408,6 +408,9 @@
int lang = -1; // default for now
Font2D font2D = FontUtilities.getFont2D(font);
+ if (font2D instanceof FontSubstitution) {
+ font2D = ((FontSubstitution)font2D).getCompositeFont2D();
+ }
_textRecord.init(text, offset, lim, min, max);
int start = offset;
--- a/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/StandardGlyphVector.java Mon Nov 16 16:07:46 2015 -0800
@@ -1124,6 +1124,9 @@
private void initFontData() {
font2D = FontUtilities.getFont2D(font);
+ if (font2D instanceof FontSubstitution) {
+ font2D = ((FontSubstitution)font2D).getCompositeFont2D();
+ }
float s = font.getSize2D();
if (font.isTransformed()) {
ftx = font.getTransform();
@@ -1742,7 +1745,12 @@
aa, fm);
// Get the strike via the handle. Shouldn't matter
// if we've invalidated the font but its an extra precaution.
- FontStrike strike = sgv.font2D.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
+ // do we want the CompFont from CFont here ?
+ Font2D f2d = sgv.font2D;
+ if (f2d instanceof FontSubstitution) {
+ f2d = ((FontSubstitution)f2d).getCompositeFont2D();
+ }
+ FontStrike strike = f2d.handle.font2D.getStrike(desc); // !!! getStrike(desc, false)
return new GlyphStrike(sgv, strike, dx, dy);
}
--- a/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/SunLayoutEngine.java Mon Nov 16 16:07:46 2015 -0800
@@ -155,10 +155,7 @@
Point2D.Float pt, GVData data) {
Font2D font = key.font();
FontStrike strike = font.getStrike(desc);
- long layoutTables = 0;
- if (font instanceof TrueTypeFont) {
- layoutTables = ((TrueTypeFont) font).getLayoutTableCache();
- }
+ long layoutTables = font.getLayoutTableCache();
nativeLayout(font, strike, mat, gmask, baseIndex,
tr.text, tr.start, tr.limit, tr.min, tr.max,
key.script(), key.lang(), typo_flags, pt, data,
--- a/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java Mon Nov 16 15:03:17 2015 +0400
+++ b/jdk/src/java.desktop/share/classes/sun/font/TrueTypeFont.java Mon Nov 16 16:07:46 2015 -0800
@@ -874,8 +874,8 @@
}
}
- /* NB: is it better to move declaration to Font2D? */
- long getLayoutTableCache() {
+ @Override
+ protected long getLayoutTableCache() {
try {
return getScaler().getLayoutTableCache();
} catch(FontScalerException fe) {
@@ -884,7 +884,7 @@
}
@Override
- byte[] getTableBytes(int tag) {
+ protected byte[] getTableBytes(int tag) {
ByteBuffer buffer = getTableBuffer(tag);
if (buffer == null) {
return null;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/java/awt/font/TextLayout/OSXLigatureTest.java Mon Nov 16 16:07:46 2015 -0800
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
+ * 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 7162125
+ * @summary Test ligatures form on OS X.
+ */
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.awt.font.TextAttribute;
+import java.util.HashMap;
+import java.util.Map;
+
+public class OSXLigatureTest {
+
+ public static void main(String[] args) {
+ if (!System.getProperty("os.name").startsWith("Mac")) {
+ return;
+ }
+ String ligStr = "ffi";
+ int w = 50, h = 50;
+
+ BufferedImage bi1 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ Graphics2D bi1Graphics = bi1.createGraphics();
+ bi1Graphics.setColor(Color.white);
+ bi1Graphics.fillRect(0, 0, w, h);
+ bi1Graphics.setColor(Color.black);
+ Font noLigFont = new Font("Gill Sans", Font.PLAIN, 30);
+ bi1Graphics.setFont(noLigFont);
+ bi1Graphics.drawString(ligStr, 10, 40);
+
+ BufferedImage bi2 = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+ Graphics2D bi2Graphics = bi2.createGraphics();
+ bi2Graphics.setColor(Color.white);
+ bi2Graphics.fillRect(0, 0, w, h);
+ bi2Graphics.setColor(Color.black);
+ Map<TextAttribute, Object> attributes = new HashMap<>();
+ attributes.put(TextAttribute.LIGATURES, TextAttribute.LIGATURES_ON);
+ Font ligFont = noLigFont.deriveFont(attributes);
+ bi2Graphics.setFont(ligFont);
+ bi2Graphics.drawString(ligStr, 10, 40);
+
+ boolean same = true;
+ for (int x = 0; x < w; x++) {
+ for (int y = 0; y < h; y++) {
+ int c1 = bi1.getRGB(x, y);
+ int c2 = bi2.getRGB(x, y);
+ same &= (c1 == c2);
+ }
+ if (!same) {
+ break;
+ }
+ }
+ if (same) {
+ throw new RuntimeException("Images do not differ - no ligature");
+ }
+ }
+}