Merge
This commit is contained in:
commit
a6731ea341
@ -140,6 +140,7 @@ abstract class CMap {
|
|||||||
* Using this saves running character coverters repeatedly.
|
* Using this saves running character coverters repeatedly.
|
||||||
*/
|
*/
|
||||||
char[] xlat;
|
char[] xlat;
|
||||||
|
UVS uvs = null;
|
||||||
|
|
||||||
static CMap initialize(TrueTypeFont font) {
|
static CMap initialize(TrueTypeFont font) {
|
||||||
|
|
||||||
@ -149,6 +150,7 @@ abstract class CMap {
|
|||||||
|
|
||||||
int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0,
|
int three0=0, three1=0, three2=0, three3=0, three4=0, three5=0,
|
||||||
three6=0, three10=0;
|
three6=0, three10=0;
|
||||||
|
int zero5 = 0; // for Unicode Variation Sequences
|
||||||
boolean threeStar = false;
|
boolean threeStar = false;
|
||||||
|
|
||||||
ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag);
|
ByteBuffer cmapBuffer = font.getTableBuffer(TrueTypeFont.cmapTag);
|
||||||
@ -173,6 +175,12 @@ abstract class CMap {
|
|||||||
case 6: three6 = offset; break; // Johab
|
case 6: three6 = offset; break; // Johab
|
||||||
case 10: three10 = offset; break; // MS Unicode surrogates
|
case 10: three10 = offset; break; // MS Unicode surrogates
|
||||||
}
|
}
|
||||||
|
} else if (platformID == 0) {
|
||||||
|
encodingID = cmapBuffer.getShort();
|
||||||
|
offset = cmapBuffer.getInt();
|
||||||
|
if (encodingID == 5) {
|
||||||
|
zero5 = offset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -262,6 +270,10 @@ abstract class CMap {
|
|||||||
*/
|
*/
|
||||||
cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8), null);
|
cmap = createCMap(cmapBuffer, cmapBuffer.getInt(8), null);
|
||||||
}
|
}
|
||||||
|
// For Unicode Variation Sequences
|
||||||
|
if (cmap != null && zero5 != 0) {
|
||||||
|
cmap.createUVS(cmapBuffer, zero5);
|
||||||
|
}
|
||||||
return cmap;
|
return cmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,6 +436,25 @@ abstract class CMap {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createUVS(ByteBuffer buffer, int offset) {
|
||||||
|
int subtableFormat = buffer.getChar(offset);
|
||||||
|
if (subtableFormat == 14) {
|
||||||
|
long subtableLength = buffer.getInt(offset + 2) & INTMASK;
|
||||||
|
if (offset + subtableLength > buffer.capacity()) {
|
||||||
|
if (FontUtilities.isLogging()) {
|
||||||
|
FontUtilities.getLogger()
|
||||||
|
.warning("Cmap UVS subtable overflows buffer.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
this.uvs = new UVS(buffer, offset);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
final char charVal(byte[] cmap, int index) {
|
final char charVal(byte[] cmap, int index) {
|
||||||
return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
|
return (char)(((0xff & cmap[index]) << 8)+(0xff & cmap[index+1]));
|
||||||
@ -1059,4 +1090,87 @@ abstract class CMap {
|
|||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static class UVS {
|
||||||
|
int numSelectors;
|
||||||
|
int[] selector;
|
||||||
|
|
||||||
|
//for Non-Default UVS Table
|
||||||
|
int[] numUVSMapping;
|
||||||
|
int[][] unicodeValue;
|
||||||
|
char[][] glyphID;
|
||||||
|
|
||||||
|
UVS(ByteBuffer buffer, int offset) {
|
||||||
|
numSelectors = buffer.getInt(offset+6);
|
||||||
|
selector = new int[numSelectors];
|
||||||
|
numUVSMapping = new int[numSelectors];
|
||||||
|
unicodeValue = new int[numSelectors][];
|
||||||
|
glyphID = new char[numSelectors][];
|
||||||
|
|
||||||
|
for (int i = 0; i < numSelectors; i++) {
|
||||||
|
buffer.position(offset + 10 + i * 11);
|
||||||
|
selector[i] = (buffer.get() & 0xff) << 16; //UINT24
|
||||||
|
selector[i] += (buffer.get() & 0xff) << 8;
|
||||||
|
selector[i] += buffer.get() & 0xff;
|
||||||
|
|
||||||
|
//skip Default UVS Table
|
||||||
|
|
||||||
|
//for Non-Default UVS Table
|
||||||
|
int tableOffset = buffer.getInt(offset + 10 + i * 11 + 7);
|
||||||
|
if (tableOffset == 0) {
|
||||||
|
numUVSMapping[i] = 0;
|
||||||
|
} else if (tableOffset > 0) {
|
||||||
|
buffer.position(offset+tableOffset);
|
||||||
|
numUVSMapping[i] = buffer.getInt() & INTMASK;
|
||||||
|
unicodeValue[i] = new int[numUVSMapping[i]];
|
||||||
|
glyphID[i] = new char[numUVSMapping[i]];
|
||||||
|
|
||||||
|
for (int j = 0; j < numUVSMapping[i]; j++) {
|
||||||
|
int temp = (buffer.get() & 0xff) << 16; //UINT24
|
||||||
|
temp += (buffer.get() & 0xff) << 8;
|
||||||
|
temp += buffer.get() & 0xff;
|
||||||
|
unicodeValue[i][j] = temp;
|
||||||
|
glyphID[i][j] = buffer.getChar();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static final int VS_NOGLYPH = 0;
|
||||||
|
private int getGlyph(int charCode, int variationSelector) {
|
||||||
|
int targetSelector = -1;
|
||||||
|
for (int i = 0; i < numSelectors; i++) {
|
||||||
|
if (selector[i] == variationSelector) {
|
||||||
|
targetSelector = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (targetSelector == -1) {
|
||||||
|
return VS_NOGLYPH;
|
||||||
|
}
|
||||||
|
if (numUVSMapping[targetSelector] > 0) {
|
||||||
|
int index = java.util.Arrays.binarySearch(
|
||||||
|
unicodeValue[targetSelector], charCode);
|
||||||
|
if (index >= 0) {
|
||||||
|
return glyphID[targetSelector][index];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return VS_NOGLYPH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char getVariationGlyph(int charCode, int variationSelector) {
|
||||||
|
char glyph = 0;
|
||||||
|
if (uvs == null) {
|
||||||
|
glyph = getGlyph(charCode);
|
||||||
|
} else {
|
||||||
|
int result = uvs.getGlyph(charCode, variationSelector);
|
||||||
|
if (result > 0) {
|
||||||
|
glyph = (char)(result & 0xFFFF);
|
||||||
|
} else {
|
||||||
|
glyph = getGlyph(charCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,6 +36,10 @@ public abstract class CharToGlyphMapper {
|
|||||||
public static final int HI_SURROGATE_END = 0xDBFF;
|
public static final int HI_SURROGATE_END = 0xDBFF;
|
||||||
public static final int LO_SURROGATE_START = 0xDC00;
|
public static final int LO_SURROGATE_START = 0xDC00;
|
||||||
public static final int LO_SURROGATE_END = 0xDFFF;
|
public static final int LO_SURROGATE_END = 0xDFFF;
|
||||||
|
public static final int VS_START = 0xFE00;
|
||||||
|
public static final int VS_END = 0xFE0F;
|
||||||
|
public static final int VSS_START = 0xE0100;
|
||||||
|
public static final int VSS_END = 0xE01FF;
|
||||||
|
|
||||||
public static final int UNINITIALIZED_GLYPH = -1;
|
public static final int UNINITIALIZED_GLYPH = -1;
|
||||||
public static final int INVISIBLE_GLYPH_ID = 0xffff;
|
public static final int INVISIBLE_GLYPH_ID = 0xffff;
|
||||||
@ -77,6 +81,11 @@ public abstract class CharToGlyphMapper {
|
|||||||
return glyphs[0];
|
return glyphs[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int charToVariationGlyph(int unicode, int variationSelector) {
|
||||||
|
// Override this if variation selector is supported.
|
||||||
|
return charToGlyph(unicode);
|
||||||
|
}
|
||||||
|
|
||||||
public abstract int getNumGlyphs();
|
public abstract int getNumGlyphs();
|
||||||
|
|
||||||
public abstract void charsToGlyphs(int count,
|
public abstract void charsToGlyphs(int count,
|
||||||
@ -88,4 +97,9 @@ public abstract class CharToGlyphMapper {
|
|||||||
public abstract void charsToGlyphs(int count,
|
public abstract void charsToGlyphs(int count,
|
||||||
int[] unicodes, int[] glyphs);
|
int[] unicodes, int[] glyphs);
|
||||||
|
|
||||||
|
public static boolean isVariationSelector(int charCode) {
|
||||||
|
return ((charCode >= VSS_START && charCode <= VSS_END) ||
|
||||||
|
(charCode >= VS_START && charCode <= VS_END));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -214,7 +214,8 @@ public class CompositeGlyphMapper extends CharToGlyphMapper {
|
|||||||
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
|
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (FontUtilities.isComplexCharCode(code)) {
|
else if (FontUtilities.isComplexCharCode(code) ||
|
||||||
|
CharToGlyphMapper.isVariationSelector(code)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (code >= 0x10000) {
|
else if (code >= 0x10000) {
|
||||||
|
@ -524,6 +524,10 @@ public abstract class Font2D {
|
|||||||
return getMapper().charToGlyph(wchar);
|
return getMapper().charToGlyph(wchar);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int charToVariationGlyph(int wchar, int variationSelector) {
|
||||||
|
return getMapper().charToVariationGlyph(wchar, variationSelector);
|
||||||
|
}
|
||||||
|
|
||||||
public int getMissingGlyphCode() {
|
public int getMissingGlyphCode() {
|
||||||
return getMapper().getMissingGlyphCode();
|
return getMapper().getMissingGlyphCode();
|
||||||
}
|
}
|
||||||
|
@ -93,6 +93,32 @@ public class TrueTypeGlyphMapper extends CharToGlyphMapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private char getGlyphFromCMAP(int charCode, int variationSelector) {
|
||||||
|
if (variationSelector == 0) {
|
||||||
|
return getGlyphFromCMAP(charCode);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
char glyphCode = cmap.getVariationGlyph(charCode,
|
||||||
|
variationSelector);
|
||||||
|
if (glyphCode < numGlyphs ||
|
||||||
|
glyphCode >= FileFontStrike.INVISIBLE_GLYPHS) {
|
||||||
|
return glyphCode;
|
||||||
|
} else {
|
||||||
|
if (FontUtilities.isLogging()) {
|
||||||
|
FontUtilities.getLogger().warning
|
||||||
|
(font + " out of range glyph id=" +
|
||||||
|
Integer.toHexString((int)glyphCode) +
|
||||||
|
" for char " + Integer.toHexString(charCode) +
|
||||||
|
" for vs " + Integer.toHexString(variationSelector));
|
||||||
|
}
|
||||||
|
return (char)missingGlyph;
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
handleBadCMAP();
|
||||||
|
return (char) missingGlyph;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void handleBadCMAP() {
|
private void handleBadCMAP() {
|
||||||
if (FontUtilities.isLogging()) {
|
if (FontUtilities.isLogging()) {
|
||||||
FontUtilities.getLogger().severe("Null Cmap for " + font +
|
FontUtilities.getLogger().severe("Null Cmap for " + font +
|
||||||
@ -136,6 +162,18 @@ public class TrueTypeGlyphMapper extends CharToGlyphMapper {
|
|||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int charToVariationGlyph(int unicode, int variationSelector) {
|
||||||
|
if (needsJAremapping) {
|
||||||
|
unicode = remapJAIntChar(unicode);
|
||||||
|
}
|
||||||
|
int glyph = getGlyphFromCMAP(unicode, variationSelector);
|
||||||
|
if (font.checkUseNatives() && glyph < font.glyphToCharMap.length) {
|
||||||
|
font.glyphToCharMap[glyph] = (char)unicode;
|
||||||
|
}
|
||||||
|
return glyph;
|
||||||
|
}
|
||||||
|
|
||||||
public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
|
public void charsToGlyphs(int count, int[] unicodes, int[] glyphs) {
|
||||||
for (int i=0;i<count;i++) {
|
for (int i=0;i<count;i++) {
|
||||||
if (needsJAremapping) {
|
if (needsJAremapping) {
|
||||||
@ -221,7 +259,8 @@ public class TrueTypeGlyphMapper extends CharToGlyphMapper {
|
|||||||
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
|
if (code < FontUtilities.MIN_LAYOUT_CHARCODE) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
else if (FontUtilities.isComplexCharCode(code)) {
|
else if (FontUtilities.isComplexCharCode(code) ||
|
||||||
|
CharToGlyphMapper.isVariationSelector(code)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (code >= 0x10000) {
|
else if (code >= 0x10000) {
|
||||||
|
@ -39,6 +39,7 @@ typedef struct FontManagerNativeIDs {
|
|||||||
jmethodID getTableBytesMID;
|
jmethodID getTableBytesMID;
|
||||||
jmethodID canDisplayMID;
|
jmethodID canDisplayMID;
|
||||||
jmethodID f2dCharToGlyphMID;
|
jmethodID f2dCharToGlyphMID;
|
||||||
|
jmethodID f2dCharToVariationGlyphMID;
|
||||||
|
|
||||||
/* sun/font/CharToGlyphMapper methods */
|
/* sun/font/CharToGlyphMapper methods */
|
||||||
jmethodID charToGlyphMID;
|
jmethodID charToGlyphMID;
|
||||||
|
@ -48,10 +48,18 @@ hb_jdk_get_glyph (hb_font_t *font HB_UNUSED,
|
|||||||
JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
|
JDKFontInfo *jdkFontInfo = (JDKFontInfo*)font_data;
|
||||||
JNIEnv* env = jdkFontInfo->env;
|
JNIEnv* env = jdkFontInfo->env;
|
||||||
jobject font2D = jdkFontInfo->font2D;
|
jobject font2D = jdkFontInfo->font2D;
|
||||||
hb_codepoint_t u = (variation_selector==0) ? unicode : variation_selector;
|
if (variation_selector == 0) {
|
||||||
|
*glyph = (hb_codepoint_t)env->CallIntMethod(
|
||||||
*glyph = (hb_codepoint_t)
|
font2D, sunFontIDs.f2dCharToGlyphMID, unicode);
|
||||||
env->CallIntMethod(font2D, sunFontIDs.f2dCharToGlyphMID, u);
|
} else {
|
||||||
|
*glyph = (hb_codepoint_t)env->CallIntMethod(
|
||||||
|
font2D, sunFontIDs.f2dCharToVariationGlyphMID,
|
||||||
|
unicode, variation_selector);
|
||||||
|
}
|
||||||
|
if (env->ExceptionOccurred())
|
||||||
|
{
|
||||||
|
env->ExceptionClear();
|
||||||
|
}
|
||||||
if ((int)*glyph < 0) {
|
if ((int)*glyph < 0) {
|
||||||
*glyph = 0;
|
*glyph = 0;
|
||||||
}
|
}
|
||||||
|
@ -144,6 +144,8 @@ static void initFontIDs(JNIEnv *env) {
|
|||||||
CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/Font2D"));
|
CHECK_NULL(tmpClass = (*env)->FindClass(env, "sun/font/Font2D"));
|
||||||
CHECK_NULL(sunFontIDs.f2dCharToGlyphMID =
|
CHECK_NULL(sunFontIDs.f2dCharToGlyphMID =
|
||||||
(*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
|
(*env)->GetMethodID(env, tmpClass, "charToGlyph", "(I)I"));
|
||||||
|
CHECK_NULL(sunFontIDs.f2dCharToVariationGlyphMID =
|
||||||
|
(*env)->GetMethodID(env, tmpClass, "charToVariationGlyph", "(II)I"));
|
||||||
CHECK_NULL(sunFontIDs.getMapperMID =
|
CHECK_NULL(sunFontIDs.getMapperMID =
|
||||||
(*env)->GetMethodID(env, tmpClass, "getMapper",
|
(*env)->GetMethodID(env, tmpClass, "getMapper",
|
||||||
"()Lsun/font/CharToGlyphMapper;"));
|
"()Lsun/font/CharToGlyphMapper;"));
|
||||||
|
BIN
test/jdk/java/awt/font/TextLayout/TestVS-expect.png
Normal file
BIN
test/jdk/java/awt/font/TextLayout/TestVS-expect.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
92
test/jdk/java/awt/font/TextLayout/TestVS.java
Normal file
92
test/jdk/java/awt/font/TextLayout/TestVS.java
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* @summary Verify Variation Selector matches an expected image
|
||||||
|
* @bug 8187100
|
||||||
|
* @ignore Requires a special font installed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.border.LineBorder;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JTextArea;
|
||||||
|
import javax.swing.ImageIcon;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
public class TestVS {
|
||||||
|
public static void main(String[] args) {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
public void run() {
|
||||||
|
new TestVS().run();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void run() {
|
||||||
|
Font ourFont = null;
|
||||||
|
final String fontName = "ipaexm.ttf";
|
||||||
|
// download from https://ipafont.ipa.go.jp/node26#en
|
||||||
|
// and place in {user.home}/fonts/
|
||||||
|
try {
|
||||||
|
ourFont = Font.createFont(Font.TRUETYPE_FONT,
|
||||||
|
new java.io.File(new java.io.File(
|
||||||
|
System.getProperty("user.home"),
|
||||||
|
"fonts"), fontName));
|
||||||
|
ourFont = ourFont.deriveFont((float)48.0);
|
||||||
|
final String actualFontName = ourFont.getFontName();
|
||||||
|
if (!actualFontName.equals("IPAexMincho")) {
|
||||||
|
System.err.println("*** Warning: missing font IPAexMincho.");
|
||||||
|
System.err.println("*** Using font: " + actualFontName);
|
||||||
|
}
|
||||||
|
} catch(Throwable t) {
|
||||||
|
t.printStackTrace();
|
||||||
|
System.err.println("Fail: " + t);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
JFrame frame = new JFrame(System.getProperty("java.version"));
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||||
|
JPanel panel = new JPanel();
|
||||||
|
final JTextArea label = new JTextArea("empty");
|
||||||
|
label.setSize(400, 300);
|
||||||
|
label.setBorder(new LineBorder(Color.black));
|
||||||
|
label.setFont(ourFont);
|
||||||
|
|
||||||
|
final String str = "\u845b\udb40\udd00\u845b\udb40\udd01\n";
|
||||||
|
|
||||||
|
label.setText(str);
|
||||||
|
|
||||||
|
panel.add(label);
|
||||||
|
panel.add(new JLabel(ourFont.getFamily()));
|
||||||
|
|
||||||
|
// Show the expected result.
|
||||||
|
panel.add(new JLabel(new ImageIcon("TestVS-expect.png")));
|
||||||
|
|
||||||
|
frame.getContentPane().add(panel);
|
||||||
|
frame.pack();
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
65
test/jdk/java/awt/font/TextLayout/VariationSelectorTest.java
Normal file
65
test/jdk/java/awt/font/TextLayout/VariationSelectorTest.java
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
/* @test
|
||||||
|
* @summary Verify two identical 'a's are rendered
|
||||||
|
* @bug 8187100
|
||||||
|
* @ignore Requires a special font installed.
|
||||||
|
*/
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.WindowConstants;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.Graphics2D;
|
||||||
|
import java.awt.font.FontRenderContext;
|
||||||
|
import java.awt.font.GlyphVector;
|
||||||
|
|
||||||
|
public class VariationSelectorTest {
|
||||||
|
// A font supporting Unicode variation selectors is required
|
||||||
|
// At least DejaVu 2.20 from 2007
|
||||||
|
private static final Font FONT = new Font("DejaVu Sans", Font.PLAIN, 12);
|
||||||
|
|
||||||
|
public static void main(String[] args) {
|
||||||
|
final String fontName = FONT.getFontName();
|
||||||
|
if (!fontName.equals("DejaVuSans")) {
|
||||||
|
System.err.println("*** Warning: Font DejaVuSans not installed.");
|
||||||
|
System.err.println("*** Using font: " + fontName);
|
||||||
|
}
|
||||||
|
SwingUtilities.invokeLater(() -> {
|
||||||
|
JFrame frame = new JFrame();
|
||||||
|
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
|
||||||
|
frame.add(new MyComponent());
|
||||||
|
frame.setSize(200, 200);
|
||||||
|
frame.setVisible(true);
|
||||||
|
frame.setLocationRelativeTo(null);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MyComponent extends JComponent {
|
||||||
|
@Override
|
||||||
|
protected void paintComponent(Graphics g) {
|
||||||
|
Graphics2D g2d = (Graphics2D) g;
|
||||||
|
FontRenderContext frc = g2d.getFontRenderContext();
|
||||||
|
String text = "a";
|
||||||
|
GlyphVector gv = FONT.layoutGlyphVector(
|
||||||
|
frc, text.toCharArray(), 0, text.length(),
|
||||||
|
Font.LAYOUT_LEFT_TO_RIGHT);
|
||||||
|
System.out.println("'a'=" + gv.getNumGlyphs());
|
||||||
|
g2d.drawString("=" + gv.getNumGlyphs() + " ('a')", 100, 50);
|
||||||
|
g2d.drawGlyphVector(gv, 80, 50);
|
||||||
|
String text2 = "a\ufe00";
|
||||||
|
GlyphVector gv2 = FONT.layoutGlyphVector(
|
||||||
|
frc, text2.toCharArray(), 0, text2.length(),
|
||||||
|
Font.LAYOUT_LEFT_TO_RIGHT);
|
||||||
|
g2d.drawGlyphVector(gv2, 80, 100);
|
||||||
|
System.out.println("'a'+VS=" + gv2.getNumGlyphs());
|
||||||
|
g2d.drawString("=" + gv2.getNumGlyphs() + " ('a'+VS)", 100, 100);
|
||||||
|
if ((gv.getNumGlyphs() == 1) && (gv2.getNumGlyphs() == 1)) {
|
||||||
|
System.out.println("PASS");
|
||||||
|
g2d.drawString("PASS", 10, 15);
|
||||||
|
} else {
|
||||||
|
System.err.println("FAIL");
|
||||||
|
g2d.drawString("FAIL", 10, 15);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user