• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:JTextComponentでサロゲートペアのテスト
#navi(../)
RIGHT:Posted by [[aterai]] at 2012-05-14
*JTextComponentでサロゲートペアのテスト [#i662a528]
JEditorPaneなどで数値文字参照やUnicodeエスケープを使ってサロゲートペアのテストをします。
---
category: swing
folder: SurrogatePair
title: JTextComponentでサロゲートペアのテスト
tags: [JEditorPane, JTextComponent, Unicode, Fixed]
author: aterai
pubdate: 2012-05-14T11:54:26+09:00
description: JEditorPaneなどで数値文字参照やUnicodeエスケープを使ってサロゲートペアのテストをします。
image: https://lh5.googleusercontent.com/-BY6N3kDDUG8/T7ByWIn0mgI/AAAAAAAABMo/4dpU-rm8zAQ/s800/SurrogatePair.png
---
* 概要 [#summary]
`JEditorPane`などで数値文字参照や`Unicode`エスケープを使ってサロゲートペアのテストをします。

-&jnlp;
-&jar;
-&zip;
#download(https://lh5.googleusercontent.com/-BY6N3kDDUG8/T7ByWIn0mgI/AAAAAAAABMo/4dpU-rm8zAQ/s800/SurrogatePair.png)

//#screenshot
#ref(https://lh5.googleusercontent.com/-BY6N3kDDUG8/T7ByWIn0mgI/AAAAAAAABMo/4dpU-rm8zAQ/s800/SurrogatePair.png)

**サンプルコード [#x2ef8e44]
#code{{
final URL url = getClass().getResource("SurrogatePair.html");
try{
  editor1.read(new InputStreamReader(url.openStream(), "UTF-8"), "html");
}catch(Exception ex) {
  editor1.setText("<html><p>(&#xD85B;&#xDE40;) (&#x26E40;)<br />(&#xD842;&#xDF9F;) (&#x00020B9F;)</p></html>");
* サンプルコード [#sourcecode]
#code(link){{
URL url = getClass().getResource("SurrogatePair.html");
try (Reader reader = new InputStreamReader(url.openStream(), StandardCharsets.UTF_8)) {
  editor1.read(reader , "html");
} catch (Exception ex) {
  editor1.setText(
    "<html><p>(&#xD85B;&#xDE40;) (&#x26E40;)<br />(&#xD842;&#xDF9F;) (&#x00020B9F;)</p></html>");
}

JEditorPane editor2 = new JEditorPane();
//editor2.setFont(new Font("IPAexGothic", Font.PLAIN, 24));
// editor2.setFont(new Font("IPAexGothic", Font.PLAIN, 24));
editor2.putClientProperty(JEditorPane.HONOR_DISPLAY_PROPERTIES, Boolean.TRUE);
editor2.setText("(\uD85B\uDE40) (\u26E40)\n(\uD842\uDF9F) (\u20B9F)");
}}

**解説 [#db4b4e56]
以下、サロゲートペア対応フォントを使えるようにしてテストしています。Java Web Start で起動した場合、"browse"ボタンでSurrogatePair.htmlを表示することはできません。
* 解説 [#explanation]
以下、サロゲートペア対応フォントを使えるようにしてテストしています。`Java Web Start`で起動した場合、このサンプルの`browse`ボタンで`jar`ファイル内の`SurrogatePair.html`を表示することはできません。

-上: 数値文字参照(Numeric character reference)
-- JEditorPane(HTMLEditorKit)の場合
 JEditorPane OK: &#xD85B;&#xDE40;
 JEditorPane NG: &#x26E40;
- 上: 数値文字参照(`Numeric character reference`)
-- [https://bugs.openjdk.org/browse/JDK-6836089 Bug ID: 6836089 Swing HTML parser can't properly decode codepoints outside the Unicode Plane 0 into a surrogate pair]で修正されたので、`&#x26E40;`などでも正常に文字が表示される(上記のスクリーンショットのように文字化けしない)
-- `JEditorPane(HTMLEditorKit)`の場合
--- `JEditorPane` + `&#xD85B;&#xDE40;`: `OK`
--- `JEditorPane` + `&#x26E40;`: `%%NG%%` `OK`

-- ブラウザ(試したのはIE, FireFox, Chrome, Opera)の場合
 Browser NG: &#xD85B;&#xDE40;
 Browser OK: &#x26E40;
-- ブラウザ(試したのは`IE`, `FireFox`, `Chrome`, `Opera`)の場合
--- `Browser` + `&#xD85B;&#xDE40;`: `NG`
--- `Browser` + `&#x26E40;`: `OK`

-下: Unicodeエスケープ(Unicode escapes)
 JEditorPane OK: \uD85B\uDE40
 JEditorPane NG: \u26E40
- 下: `Unicode`エスケープ(`Unicode escapes`)
--- `JEditorPane` + `\uD85B\uDE40`: `OK`
--- `JEditorPane` + `\u26E40`: `NG`

----
JTextComponentとブラウザでサロゲートペアの表現が異なるようなので、これらの文字をどちらの環境でも正しく表示したい場合は、数値文字参照やUnicodeエスケープは使用せず、ソースコードなどをUTF-8にしてそのまま𦹀や𠮟と書く((メモ帳などの対応済みエディタで))のがよさそうです。
- `JTextComponent`とブラウザでサロゲートペアの表現が異なるためこれらの文字をどちらの環境でも正しく表示したい場合は数値文字参照や`Unicode`エスケープは使用せずソースコードなどを`UTF-8`にしてそのまま𦹀や𠮟と書く(メモ帳などの対応済みエディタで)ほうが良さそう
- `Windows 7`、`JDK 1.7.0_02`の環境では`JTextComponent`からメモ帳などにサロゲートペアの文字をコピーペーストは可能だが、逆にメモ帳やブラウザから`JTextComponent`にサロゲートペアの文字をコピーペーストは不可
- `JTextComponent`は異体字セレクタに対応してない
-- フォントを`IVS`に対応している`IPAmj明朝`などに変更し異体字セレクタ付き文字列のある`UTF-8`のテキストを`JTextArea`などに読み込んでも異体字セレクタが〓になる
-- 数値文字参照、`Unicode`エスケープを使う方法でも〓になる
-- [https://terazzo.hatenadiary.org/entry/20110115/1295047469 Java IVSの異体字を元の字と同一視して比較する - terazzoの日記]のように、`VS`を`UTF-16`に(例えば`U+E0101`を`\uDB40\uDD01`に)しても`JTextComponent`では駄目

----
Windows7, JDK 1.7.0_02 の環境では、JTextComponentからメモ帳などにサロゲートペアの文字をコピーペーストは可能ですが、逆にメモ帳やブラウザからJTextComponentにサロゲートペアの文字をコピーペーストすることができないようです。
- 参考メモ: [https://chiku-chiku-nikki.hatenablog.com/entry/20121115/1352932112 MS IVSアドインでDTPにはどんな影響があるのか - ちくちく日記]
-- `Adobe-Japan1 collection`: `小塚明朝 Pr6N`など
-- `Hanyo-Denshi collection`: `IPAmj明朝`など

// %%`小塚明朝 Pr6N`(メモ: `Pr6N`の`N`は`JIS2004`対応の意味で、`IVS`対応とは関係ないらしい)%%

----
現状ではJTextComponentは、異体字セレクタに対応していない?
- フォントをIVS(Adobe-Japan1-6)に対応している小塚明朝 Pr6N や IPAex明朝 などに変更して、数値文字参照、Unicodeエスケープを使っても下駄になったり、ソースコードをUTF-8にしても%%以下のような IllegalArgumentException が発生するようです。%%
- %%`Windows 10 64bit`、`JDK 1.8.0_112`、`小塚明朝 Pr6N R`(`KozMinPr6N-Regular.otf`)で`Font.createFont(...)`を使って`Font`を作成すると`IllegalArgumentException`が発生する場合がある%%
-- %%例外が発生しなくても、文字は正常に表示されない%%
-- [https://bugs.openjdk.org/browse/JDK-5092191 JDK-5092191 RFE: CFF/Type2 embedded fonts not supported with Font.createFont() - Java Bug System]
-- [https://bugs.openjdk.org/browse/JDK-8074562 JDK-8074562 CID keyed OpenType fonts are not supported by T2K - Java Bug System]
-- [https://bugs.openjdk.org/browse/JDK-8168288 JDK-8168288 Dubious FontMetrics values from NullFontScaler - Java Bug System]
--- `Java 9`、`8u152`で修正された

 Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Length must be >= 0.
    at javax.swing.text.GlyphPainter2.getBoundedPosition(GlyphPainter2.java: 205)

- IllegalArgumentExceptionと異体字セレクタは関係なくて、Windows環境のJavaと'小塚明朝 Pr6N R'(OTFフォントだから?) と相性が悪いだけ?
#code{{
import java.awt.*;
import java.io.*;
import java.net.*;
import javax.swing.*;

//**参考リンク
**コメント [#qfcd8f76]
public class OTFTest {
  public JComponent makeUI() {
    JTextArea textArea = new JTextArea("1234567890\n \uD85B\uDE40");
    String str = "file:///C:/Program Files (x86)/Adobe/Acrobat 2015/Resource/CIDFont/KozMinPr6N-Regular.otf";
    //String str = "file:///C:/Program Files (x86)/Adobe/Reader 11.0/Resource/CIDFont/KozMinPr6N-Regular.otf";
    //String str = "file:///C:/Windows/Fonts/meiryo.ttc";
    //String str = "file:///C:/Windows/Fonts/ipaexg.ttf";
    //String str = "file:///C:/Windows/Fonts/A-OTF-ShinGoPro-Regular.otf";
    try (InputStream is = new URL(str).openStream()) {
      //textArea.setFont(Font.createFont(Font.TRUETYPE_FONT, is));
      textArea.setFont(Font.createFont(Font.TRUETYPE_FONT, is).deriveFont(32f));
    } catch (IOException | FontFormatException ex) {
      ex.printStackTrace();
    }
    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(textArea));
    return p;
  }

  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }

  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new OTFTest().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
}}

* 参考リンク [#reference]
- [https://www.mindprod.com/jgloss/opentype.html#JAVASUPPORT Java Font Support - OpenType : Java Glossary]
- [https://docs.oracle.com/javase/jp/8/docs/api/java/awt/font/OpenType.html OpenType (Java Platform SE 8)]
- [https://stackoverflow.com/questions/22605666/java-access-files-in-jar-causes-java-nio-file-filesystemnotfoundexception Java access files in jar causes java.nio.file.FileSystemNotFoundException - Stack Overflow]

* コメント [#comment]
#comment
- 結合文字(`A&#x0300;`、`か&#x3099;`)も`JTextComponent`は未対応。%%ブラウザだと`Chrome`は対応されているが、他は部分的な対応になっている?%% -- &user(aterai); &new{2012-05-15 (火) 11:17:30};
- `Windows 7` + `JDK 1.7.0`で`OTF`フォントは使えない??? -- &user(aterai); &new{2012-06-06 (水) 19:07:01};
- メモ: [https://bugs.openjdk.org/browse/JDK-6836089 Bug ID: 6836089 Swing HTML parser can't properly decode codepoints outside the Unicode Plane 0 into a surrogate pair] -- &user(aterai); &new{2012-06-25 (月) 18:37:16};
-- via: [https://mail.openjdk.org/pipermail/swing-dev/2012-June/002145.html <Swing Dev> <Swind Dev> <7u6> Review request for 6836089: Swing HTML parser can't properly decode codepoints outside the Unicode Plane 0 into a surrogate pair]
-- 確かに`JDK 1.6.0_33`では、`&#x26E40;`などの数値文字参照が`JEditorPane`で正常に表示されている。 -- &user(aterai); &new{2012-06-25 (月) 20:42:16};

#comment