From cbed71d46c617b323e00fa2369b9b18aa7af96c1 Mon Sep 17 00:00:00 2001 From: Akira Nakajima Date: Fri, 6 Jul 2018 15:50:24 +0900 Subject: [PATCH] To make display Variation Selectors on Win and MacOS --- .../java/com/sun/javafx/PlatformUtil.java | 8 +++++ .../com/sun/javafx/text/ScriptMapper.java | 11 +++++- .../java/com/sun/prism/sw/SWGraphics.java | 6 +++- .../java/test/javafx/scene/text/Test_VS.java | 33 ++++++++++++++++++ .../test/javafx/scene/text/Test_VS_expect.png | Bin 0 -> 10588 bytes 5 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 tests/system/src/test/java/test/javafx/scene/text/Test_VS.java create mode 100644 tests/system/src/test/java/test/javafx/scene/text/Test_VS_expect.png diff --git a/modules/javafx.base/src/main/java/com/sun/javafx/PlatformUtil.java b/modules/javafx.base/src/main/java/com/sun/javafx/PlatformUtil.java index 4e527ffd43..c278f59b68 100644 --- a/modules/javafx.base/src/main/java/com/sun/javafx/PlatformUtil.java +++ b/modules/javafx.base/src/main/java/com/sun/javafx/PlatformUtil.java @@ -68,6 +68,7 @@ public class PlatformUtil { private static final boolean WINDOWS_VISTA_OR_LATER = WINDOWS && versionNumberGreaterThanOrEqualTo(6.0f); private static final boolean WINDOWS_7_OR_LATER = WINDOWS && versionNumberGreaterThanOrEqualTo(6.1f); private static final boolean MAC = os.startsWith("Mac"); + private static final boolean MAC_10_6_OR_LATER = MAC && versionNumberGreaterThanOrEqualTo(10.6f); private static final boolean LINUX = os.startsWith("Linux") && !ANDROID; private static final boolean SOLARIS = os.startsWith("SunOS"); private static final boolean IOS = os.startsWith("iOS"); @@ -117,6 +118,13 @@ public static boolean isMac(){ return MAC; } + /** + * Returns true if the operating system is at least Mac OS X 10.6(v10.6). + */ + public static boolean isMac10_6_OrLater(){ + return MAC_10_6_OR_LATER; + } + /** * Returns true if the operating system is a form of Linux. */ diff --git a/modules/javafx.graphics/src/main/java/com/sun/javafx/text/ScriptMapper.java b/modules/javafx.graphics/src/main/java/com/sun/javafx/text/ScriptMapper.java index c439d13138..2bcf70ae4f 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/javafx/text/ScriptMapper.java +++ b/modules/javafx.graphics/src/main/java/com/sun/javafx/text/ScriptMapper.java @@ -24,6 +24,7 @@ */ package com.sun.javafx.text; +import com.sun.javafx.PlatformUtil; public class ScriptMapper { @@ -80,7 +81,9 @@ public static synchronized int getScript(int codePoint) { * in the case where the caller interprets 'layout' to mean where * one 'char' (ie the java type char) does not map to one glyph */ - private static final int MAX_LAYOUT_CHARCODE = 0x206F; + private static final int MAX_LAYOUT_CHARCODE + = (PlatformUtil.isWinVistaOrLater() || PlatformUtil.isMac10_6_OrLater()) + ? 0xE01EF : 0x206F; /* If the character code falls into any of a number of unicode ranges * where we know that simple left->right layout mapping chars to glyphs @@ -166,6 +169,12 @@ else if (code >= 0x202a && code <= 0x202e) { // directional control else if (code >= 0x206a && code <= 0x206f) { // directional control return true; } + else if (code >= 0xfe00 && code <= 0xfe0f) { // SVS + return true; + } + else if (code >= 0xe0100 && code <= 0xe01ef) { // IVS + return true; + } return false; } diff --git a/modules/javafx.graphics/src/main/java/com/sun/prism/sw/SWGraphics.java b/modules/javafx.graphics/src/main/java/com/sun/prism/sw/SWGraphics.java index 65267e104f..ca0d7aa280 100644 --- a/modules/javafx.graphics/src/main/java/com/sun/prism/sw/SWGraphics.java +++ b/modules/javafx.graphics/src/main/java/com/sun/prism/sw/SWGraphics.java @@ -62,6 +62,8 @@ import com.sun.prism.paint.ImagePattern; import com.sun.prism.paint.Paint; +import com.sun.javafx.font.CharToGlyphMapper; + final class SWGraphics implements ReadbackGraphics { private static final BasicStroke DEFAULT_STROKE = @@ -627,8 +629,10 @@ public void drawString(GlyphList gl, FontStrike strike, float x, float y, private void drawGlyph(FontStrike strike, GlyphList gl, int idx, BaseTransform glyphTx, boolean drawAsMasks, float x, float y) { - final Glyph g = strike.getGlyph(gl.getGlyphCode(idx)); + if (g.getGlyphCode() == CharToGlyphMapper.INVISIBLE_GLYPH_ID) { + return; + } if (drawAsMasks) { final Point2D pt = new Point2D((float)(x + tx.getMxt() + gl.getPosX(idx)), (float)(y + tx.getMyt() + gl.getPosY(idx))); diff --git a/tests/system/src/test/java/test/javafx/scene/text/Test_VS.java b/tests/system/src/test/java/test/javafx/scene/text/Test_VS.java new file mode 100644 index 0000000000..ecb6de951a --- /dev/null +++ b/tests/system/src/test/java/test/javafx/scene/text/Test_VS.java @@ -0,0 +1,33 @@ +import javafx.application.Application; +import static javafx.application.Application.launch; +import javafx.scene.Group; +import javafx.scene.Scene; +import javafx.scene.paint.Color; +import javafx.scene.text.Font; +import javafx.scene.text.Text; +import javafx.scene.control.TextArea; +import javafx.scene.text.TextFlow; +import javafx.stage.Stage; + +public class Test_VS extends Application { + @Override + public void start(Stage stage) throws Exception { + final String fontName = "ipamjm.ttf"; + // download from https://mojikiban.ipa.go.jp/1300.html + // place in $(user.home)/fonts/ + + Font ourFont = Font.loadFont("file://"+System.getProperty("user.home")+"/fonts/"+fontName.toString(), 48); + TextFlow textFlow = new TextFlow(); + + final String str = "\u795E+VS1 --> \u795E\uFE00\n" // U+795E,U+FE00 SVS + + "\u795E+VS20 --> \u795E\uDB40\uDD03\n" // U+795E,U+E0103 IVS + + "\uD87A\uDF79+VS17 --> \uD87A\uDF79\uDB40\uDD01\n"; // U+2EB79(Surrogate Pair),U+E0101 IVS + TextArea text = new TextArea(str); + text.setFont(ourFont); + + Group group = new Group(text); + Scene scene = new Scene(group, 400, 200, Color.WHITE); + stage.setScene(scene); + stage.show(); + } +} diff --git a/tests/system/src/test/java/test/javafx/scene/text/Test_VS_expect.png b/tests/system/src/test/java/test/javafx/scene/text/Test_VS_expect.png new file mode 100644 index 0000000000000000000000000000000000000000..1da09e48b99dc18e3bab8b9b3c8ef3b3fad0e482 GIT binary patch literal 10588 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