• title: JTextComponentでサロゲートペアのテスト tags: [JEditorPane, JTextComponent, Unicode] author: aterai pubdate: 2012-05-14T11:54:26+09:00 description: JEditorPaneなどで数値文字参照やUnicodeエスケープを使ってサロゲートペアのテストをします。

概要

JEditorPaneなどで数値文字参照やUnicodeエスケープを使ってサロゲートペアのテストをします。

サンプルコード

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>");
}

JEditorPane editor2 = new JEditorPane();
//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)");
View in GitHub: Java, Kotlin

解説

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

  • 上: 数値文字参照(Numeric character reference)
    • JEditorPane(HTMLEditorKit)の場合
      JEditorPane OK: &#xD85B;&#xDE40;
      JEditorPane NG: &#x26E40;
  • ブラウザ(試したのはIE, FireFox, Chrome, Opera)の場合
    Browser NG: &#xD85B;&#xDE40;
    Browser OK: &#x26E40;
  • 下: Unicodeエスケープ(Unicode escapes)
    JEditorPane OK: \uD85B\uDE40
    JEditorPane NG: \u26E40

JTextComponentとブラウザでサロゲートペアの表現が異なるようなので、これらの文字をどちらの環境でも正しく表示したい場合は、数値文字参照やUnicodeエスケープは使用せず、ソースコードなどをUTF-8にしてそのまま𦹀や𠮟と書く(メモ帳などの対応済みエディタで)のがよさそうです。


Windows 7, JDK 1.7.0_02の環境では、JTextComponentからメモ帳などにサロゲートペアの文字をコピーペーストは可能ですが、逆にメモ帳やブラウザからJTextComponentにサロゲートペアの文字をコピーペーストすることができないようです。


JTextComponent(Java 1.7.0)は、異体字セレクタに対応していない

  • フォントをIVSに対応しているIPAmj明朝などに変更し、異体字セレクタ付き文字列のあるUTF-8のテキストをJTextAreaなどに読み込んでも異体字セレクタが下駄になる
  • 数値文字参照、Unicodeエスケープを使う方法でも下駄になる


Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Length must be >= 0.
   at javax.swing.text.GlyphPainter2.getBoundedPosition(GlyphPainter2.java: 205)
import java.awt.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
public class OTFTest {
  public JComponent makeUI() {
    JTextArea textArea = new JTextArea("1234567890\n \uD85B\uDE40");
    String str = "file:///C:/Program Files (x86)/Adobe/Reader 11.0/Resource/CIDFont/KozMinPr6N-Regular.otf"; //6.014
    //String str = "file:///C:/Program Files (x86)/Adobe/Acrobat 9.0/Resource/CIDFont/KozMinPr6N-Regular.otf"; //6.004
    //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()) {
      Font font = (Font.createFont(Font.TRUETYPE_FONT, is)).deriveFont(32f);
      textArea.setFont(font);
      is.close();
    } 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);
  }
}

参考リンク

コメント