TITLE:JTextComponentでサロゲートペアのテスト
Posted by aterai at 2012-05-14

JTextComponentでサロゲートペアのテスト

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

概要

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

サンプルコード

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

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

解説

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

解説

以下、サロゲートペア対応フォントを使えるようにしてテストしています。Java Web Startで起動した場合、このサンプルのbrowseボタンでjarファイル内のSurrogatePair.htmlを表示することはできません。
  • ブラウザ(試したのは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にしてそのまま𦹀や𠮟と書く*1のがよさそうです。
  • JTextComponentとブラウザでサロゲートペアの表現が異なるためこれらの文字をどちらの環境でも正しく表示したい場合は数値文字参照やUnicodeエスケープは使用せずソースコードなどをUTF-8にしてそのまま𦹀や𠮟と書く(メモ帳などの対応済みエディタで)ほうが良さそう
  • Windows 7JDK 1.7.0_02の環境ではJTextComponentからメモ帳などにサロゲートペアの文字をコピーペーストは可能だが、逆にメモ帳やブラウザからJTextComponentにサロゲートペアの文字をコピーペーストは不可
  • JTextComponentは異体字セレクタに対応してない
    • フォントをIVSに対応しているIPAmj明朝などに変更し異体字セレクタ付き文字列のあるUTF-8のテキストをJTextAreaなどに読み込んでも異体字セレクタが〓になる
    • 数値文字参照、Unicodeエスケープを使う方法でも〓になる
    • Java IVSの異体字を元の字と同一視して比較する - terazzoの日記のように、VSUTF-16に(例えばU+E0101\uDB40\uDD01に)してもJTextComponentでは駄目

Windows7, JDK 1.7.0_02 の環境では、JTextComponentからメモ帳などにサロゲートペアの文字をコピーペーストは可能ですが、逆にメモ帳やブラウザからJTextComponentにサロゲートペアの文字をコピーペーストすることができないようです。
現状ではJTextComponentは、異体字セレクタに対応していない?
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フォントだから?)と相性が悪いだけ?
  • Font.createFont(...)で、C:\Program Files (x86)\Adobe\Acrobat 9.0\Resource\CIDFont\KozMinPr6N-Regular.otf からフォントを作ると???
    #spanend
    #spanadd
    import java.awt.*;
    #spanend
    #spanadd
    import java.io.*;
    #spanend
    #spanadd
    import java.net.*;
    #spanend
    #spanadd
    import javax.swing.*;
    #spanend
    
    #spandel
    //**参考リンク
    #spanend
    #spandel
    **コメント [#qfcd8f76]
    #spanend
    - 結合文字(A&#x0300; か&#x3099;)もJTextComponentは未対応。%%ブラウザだとChromeは対応されているが、他は部分的な対応になっている?%% -- [[aterai]] &new{2012-05-15 (火) 11:17:30};
    #spanadd
    public class OTFTest {
    #spanend
      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();
          }
        });
      }
    #spanadd
    
    #spanend
      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);
      }
    #spanadd
    }
    #spanend
    #spanadd
    

参考リンク

コメント