|
/*
* @(#)Font2DTest.java 1.28 05/11/17
*
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistribution of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
* ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
* OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
* AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
* AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
* DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST
* REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL,
* INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY
* OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that this software is not designed, licensed or intended
* for use in the design, construction, operation or maintenance of any
* nuclear facility.
*/
/*
* @(#)Font2DTest.java 1.28 05/11/17
*/
import static java.awt.RenderingHints.KEY_ANTIALIASING;
import static java.awt.RenderingHints.KEY_FRACTIONALMETRICS;
import static java.awt.RenderingHints.KEY_TEXT_ANTIALIASING;
import static java.awt.RenderingHints.KEY_TEXT_LCD_CONTRAST;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_OFF;
import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON;
import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_DEFAULT;
import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_OFF;
import static java.awt.RenderingHints.VALUE_FRACTIONALMETRICS_ON;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_GASP;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_OFF;
import static java.awt.RenderingHints.VALUE_TEXT_ANTIALIAS_ON;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.AdjustmentEvent;
import java.awt.event.AdjustmentListener;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.font.FontRenderContext;
import java.awt.font.GlyphVector;
import java.awt.font.LineBreakMeasurer;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterJob;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.text.AttributedString;
import java.util.BitSet;
import java.util.EnumSet;
import java.util.StringTokenizer;
import java.util.Vector;
import javax.imageio.ImageIO;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListCellRenderer;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.JSlider;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.JWindow;
import javax.swing.UIManager;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
/**
* Font2DTest.java
*
* @version
* @(#)Font2DTest.java 1.2 00/08/22
* @author Shinsuke Fukuda
* @author Ankit Patel [Conversion to Swing - 01/07/30]
*/
// / Main Font2DTest Class
public final class Font2DTest extends JPanel implements ActionListener, ItemListener,
ChangeListener {
// / JFrame that will contain Font2DTest
private final JFrame parent;
// / FontPanel class that will contain all graphical output
private final FontPanel fp;
// / RangeMenu class that contains info about the unicode ranges
private final RangeMenu rm;
// / Other menus to set parameters for text drawing
private final ChoiceV2 fontMenu;
private final JTextField sizeField;
private final ChoiceV2 styleMenu;
private final ChoiceV2 textMenu;
private int currentTextChoice = 0;
private final ChoiceV2 transformMenu;
private final ChoiceV2 transformMenuG2;
private final ChoiceV2 methodsMenu;
private final JComboBox antiAliasMenu;
private final JComboBox fracMetricsMenu;
private final JSlider contrastSlider;
// / CheckboxMenuItems
private CheckboxMenuItemV2 displayGridCBMI;
private CheckboxMenuItemV2 force16ColsCBMI;
private CheckboxMenuItemV2 showFontInfoCBMI;
// / JDialog boxes
private JDialog userTextDialog;
private JTextArea userTextArea;
private JDialog printDialog;
private JDialog fontInfoDialog;
private LabelV2 fontInfos[] = new LabelV2[2];
private JFileChooser filePromptDialog = null;
private ButtonGroup printCBGroup;
private JRadioButton printModeCBs[] = new JRadioButton[3];
// / Status bar
private final LabelV2 statusBar;
private int fontStyles[] = { Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC };
// / Text filename
private String tFileName;
// Enabled or disabled status of canDisplay check
private static boolean canDisplayCheck = true;
// / Initialize GUI variables and its layouts
public Font2DTest(JFrame f, boolean isApplet) {
parent = f;
rm = new RangeMenu(this, parent);
fp = new FontPanel(this, parent);
statusBar = new LabelV2("");
fontMenu = new ChoiceV2(this, canDisplayCheck);
sizeField = new JTextField("12", 3);
sizeField.addActionListener(this);
styleMenu = new ChoiceV2(this);
textMenu = new ChoiceV2(); // listener added later
transformMenu = new ChoiceV2(this);
transformMenuG2 = new ChoiceV2(this);
methodsMenu = new ChoiceV2(this);
antiAliasMenu = new JComboBox(EnumSet.allOf(FontPanel.AAValues.class).toArray());
antiAliasMenu.addActionListener(this);
fracMetricsMenu = new JComboBox(EnumSet.allOf(FontPanel.FMValues.class).toArray());
fracMetricsMenu.addActionListener(this);
contrastSlider = new JSlider(JSlider.HORIZONTAL, 100, 250, FontPanel.getDefaultLCDContrast()
.intValue());
contrastSlider.setEnabled(false);
contrastSlider.setMajorTickSpacing(20);
contrastSlider.setMinorTickSpacing(10);
contrastSlider.setPaintTicks(true);
contrastSlider.setPaintLabels(true);
contrastSlider.addChangeListener(this);
setupPanel();
setupMenu(isApplet);
setupDialog(isApplet);
if (canDisplayCheck) {
fireRangeChanged();
}
}
// / Set up the main interface panel
private void setupPanel() {
GridBagLayout gbl = new GridBagLayout();
GridBagConstraints gbc = new GridBagConstraints();
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.weightx = 1;
gbc.insets = new Insets(2, 0, 2, 2);
this.setLayout(gbl);
addLabeledComponentToGBL("Font: ", fontMenu, gbl, gbc, this);
addLabeledComponentToGBL("Size: ", sizeField, gbl, gbc, this);
gbc.gridwidth = GridBagConstraints.REMAINDER;
addLabeledComponentToGBL("Font Transform:", transformMenu, gbl, gbc, this);
gbc.gridwidth = 1;
addLabeledComponentToGBL("Range: ", rm, gbl, gbc, this);
addLabeledComponentToGBL("Style: ", styleMenu, gbl, gbc, this);
gbc.gridwidth = GridBagConstraints.REMAINDER;
addLabeledComponentToGBL("Graphics Transform: ", transformMenuG2, gbl, gbc, this);
gbc.gridwidth = 1;
gbc.anchor = GridBagConstraints.WEST;
addLabeledComponentToGBL("Method: ", methodsMenu, gbl, gbc, this);
addLabeledComponentToGBL("", null, gbl, gbc, this);
gbc.anchor = GridBagConstraints.EAST;
gbc.gridwidth = GridBagConstraints.REMAINDER;
addLabeledComponentToGBL("Text to use:", textMenu, gbl, gbc, this);
gbc.weightx = 1;
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.anchor = GridBagConstraints.WEST;
addLabeledComponentToGBL("LCD contrast: ", contrastSlider, gbl, gbc, this);
gbc.gridwidth = 1;
gbc.fill = GridBagConstraints.NONE;
addLabeledComponentToGBL("Antialiasing: ", antiAliasMenu, gbl, gbc, this);
gbc.anchor = GridBagConstraints.EAST;
gbc.gridwidth = GridBagConstraints.REMAINDER;
addLabeledComponentToGBL("Fractional metrics: ", fracMetricsMenu, gbl, gbc, this);
gbc.weightx = 1;
gbc.weighty = 1;
gbc.anchor = GridBagConstraints.WEST;
gbc.insets = new Insets(2, 0, 0, 2);
gbc.fill = GridBagConstraints.BOTH;
gbl.setConstraints(fp, gbc);
this.add(fp);
gbc.weighty = 0;
gbc.insets = new Insets(0, 2, 0, 0);
gbl.setConstraints(statusBar, gbc);
this.add(statusBar);
}
// / Adds a component to a container with a label to its left in GridBagLayout
private void addLabeledComponentToGBL(String name, JComponent c, GridBagLayout gbl,
GridBagConstraints gbc, Container target) {
LabelV2 l = new LabelV2(name);
GridBagConstraints gbcLabel = (GridBagConstraints) gbc.clone();
gbcLabel.insets = new Insets(2, 2, 2, 0);
gbcLabel.gridwidth = 1;
gbcLabel.weightx = 0;
if (c == null)
c = new JLabel("");
gbl.setConstraints(l, gbcLabel);
target.add(l);
gbl.setConstraints(c, gbc);
target.add(c);
}
// / Sets up menu entries
private void setupMenu(boolean isApplet) {
JMenu fileMenu = new JMenu("File");
JMenu optionMenu = new JMenu("Option");
fileMenu.add(new MenuItemV2("Save Selected Options...", this));
fileMenu.add(new MenuItemV2("Load Options...", this));
fileMenu.addSeparator();
fileMenu.add(new MenuItemV2("Save as PNG...", this));
fileMenu.add(new MenuItemV2("Load PNG File to Compare...", this));
fileMenu.add(new MenuItemV2("Page Setup...", this));
fileMenu.add(new MenuItemV2("Print...", this));
fileMenu.addSeparator();
if (!isApplet)
fileMenu.add(new MenuItemV2("Exit", this));
else
fileMenu.add(new MenuItemV2("Close", this));
displayGridCBMI = new CheckboxMenuItemV2("Display Grid", true, this);
force16ColsCBMI = new CheckboxMenuItemV2("Force 16 Columns", false, this);
showFontInfoCBMI = new CheckboxMenuItemV2("Display Font Info", false, this);
optionMenu.add(displayGridCBMI);
optionMenu.add(force16ColsCBMI);
optionMenu.add(showFontInfoCBMI);
JMenuBar mb = parent.getJMenuBar();
if (mb == null)
mb = new JMenuBar();
mb.add(fileMenu);
mb.add(optionMenu);
parent.setJMenuBar(mb);
String fontList[] = GraphicsEnvironment.getLocalGraphicsEnvironment()
.getAvailableFontFamilyNames();
for (int i = 0; i < fontList.length; i++)
fontMenu.addItem(fontList[i]);
fontMenu.setSelectedItem("Dialog");
styleMenu.addItem("Plain");
styleMenu.addItem("Bold");
styleMenu.addItem("Italic");
styleMenu.addItem("Bold Italic");
transformMenu.addItem("None");
transformMenu.addItem("Scale");
transformMenu.addItem("Shear");
transformMenu.addItem("Rotate");
transformMenuG2.addItem("None");
transformMenuG2.addItem("Scale");
transformMenuG2.addItem("Shear");
transformMenuG2.addItem("Rotate");
methodsMenu.addItem("drawString");
methodsMenu.addItem("drawChars");
methodsMenu.addItem("drawBytes");
methodsMenu.addItem("drawGlyphVector");
methodsMenu.addItem("TextLayout.draw");
methodsMenu.addItem("GlyphVector.getOutline + draw");
methodsMenu.addItem("TextLayout.getOutline + draw");
textMenu.addItem("Unicode Range");
textMenu.addItem("All Glyphs");
textMenu.addItem("User Text");
textMenu.addItem("Text File");
textMenu.addActionListener(this); // listener added later so unneeded events
// not thrown
}
// / Sets up the all dialogs used in Font2DTest...
private void setupDialog(boolean isApplet) {
if (!isApplet)
filePromptDialog = new JFileChooser();
else
filePromptDialog = null;
// / Prepare user text dialog...
userTextDialog = new JDialog(parent, "User Text", false);
JPanel dialogTopPanel = new JPanel();
JPanel dialogBottomPanel = new JPanel();
LabelV2 message1 = new LabelV2("Enter text below and then press update");
LabelV2 message2 = new LabelV2("(Unicode char can be denoted by \\uXXXX)");
LabelV2 message3 = new LabelV2("(Supplementary chars can be denoted by \\UXXXXXX)");
userTextArea = new JTextArea("Java2D!");
ButtonV2 bUpdate = new ButtonV2("Update", this);
userTextArea.setFont(new Font("dialog", Font.PLAIN, 12));
dialogTopPanel.setLayout(new GridLayout(3, 1));
dialogTopPanel.add(message1);
dialogTopPanel.add(message2);
dialogTopPanel.add(message3);
dialogBottomPanel.add(bUpdate);
// ABP
JScrollPane userTextAreaSP = new JScrollPane(userTextArea);
userTextAreaSP.setPreferredSize(new Dimension(300, 100));
userTextDialog.getContentPane().setLayout(new BorderLayout());
userTextDialog.getContentPane().add("North", dialogTopPanel);
userTextDialog.getContentPane().add("Center", userTextAreaSP);
userTextDialog.getContentPane().add("South", dialogBottomPanel);
userTextDialog.pack();
userTextDialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
userTextDialog.hide();
}
});
// / Prepare printing dialog...
printCBGroup = new ButtonGroup();
printModeCBs[fp.ONE_PAGE] = new JRadioButton(
"Print one page from currently displayed character/line", true);
printModeCBs[fp.CUR_RANGE] = new JRadioButton(
"Print all characters in currently selected range", false);
printModeCBs[fp.ALL_TEXT] = new JRadioButton("Print all lines of text", false);
LabelV2 l = new LabelV2(
"Note: Page range in native \"Print\" dialog will not affect the result");
JPanel buttonPanel = new JPanel();
printModeCBs[fp.ALL_TEXT].setEnabled(false);
buttonPanel.add(new ButtonV2("Print", this));
buttonPanel.add(new ButtonV2("Cancel", this));
printDialog = new JDialog(parent, "Print...", true);
printDialog.setResizable(false);
printDialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
printDialog.hide();
}
});
printDialog.getContentPane().setLayout(new GridLayout(printModeCBs.length + 2, 1));
printDialog.getContentPane().add(l);
for (int i = 0; i < printModeCBs.length; i++) {
printCBGroup.add(printModeCBs[i]);
printDialog.getContentPane().add(printModeCBs[i]);
}
printDialog.getContentPane().add(buttonPanel);
printDialog.pack();
// / Prepare font information dialog...
fontInfoDialog = new JDialog(parent, "Font info", false);
fontInfoDialog.setResizable(false);
fontInfoDialog.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
fontInfoDialog.hide();
showFontInfoCBMI.setState(false);
}
});
JPanel fontInfoPanel = new JPanel();
fontInfoPanel.setLayout(new GridLayout(fontInfos.length, 1));
for (int i = 0; i < fontInfos.length; i++) {
fontInfos[i] = new LabelV2("");
fontInfoPanel.add(fontInfos[i]);
}
fontInfoDialog.getContentPane().add(fontInfoPanel);
// / Move the location of the dialog...
userTextDialog.setLocation(200, 300);
fontInfoDialog.setLocation(0, 400);
}
// / RangeMenu object signals using this function
// / when Unicode range has been changed and text needs to be redrawn
public void fireRangeChanged() {
int range[] = rm.getSelectedRange();
fp.setTextToDraw(fp.RANGE_TEXT, range, null, null);
if (canDisplayCheck) {
setupFontList(range[0], range[1]);
}
if (showFontInfoCBMI.getState())
fireUpdateFontInfo();
}
// / Changes the message on the status bar
public void fireChangeStatus(String message, boolean error) {
// / If this is not ran as an applet, use own status bar,
// / Otherwise, use the appletviewer/browser's status bar
statusBar.setText(message);
if (error)
fp.showingError = true;
else
fp.showingError = false;
}
// / Updates the information about the selected font
public void fireUpdateFontInfo() {
if (showFontInfoCBMI.getState()) {
String infos[] = fp.getFontInfo();
for (int i = 0; i < fontInfos.length; i++)
fontInfos[i].setText(infos[i]);
fontInfoDialog.pack();
}
}
private void setupFontList(int rangeStart, int rangeEnd) {
int listCount = fontMenu.getItemCount();
int size = 16;
try {
size = Float.valueOf(sizeField.getText()).intValue();
} catch (Exception e) {
System.out.println("Invalid font size in the size textField. Using default value of 16");
}
int style = fontStyles[styleMenu.getSelectedIndex()];
Font f;
for (int i = 0; i < listCount; i++) {
String fontName = (String) fontMenu.getItemAt(i);
f = new Font(fontName, style, size);
if ((rm.getSelectedIndex() != RangeMenu.SURROGATES_AREA_INDEX)
&& canDisplayRange(f, rangeStart, rangeEnd)) {
fontMenu.setBit(i, true);
} else {
fontMenu.setBit(i, false);
}
}
fontMenu.repaint();
}
protected boolean canDisplayRange(Font font, int rangeStart, int rangeEnd) {
for (int i = rangeStart; i < rangeEnd; i++) {
if (font.canDisplay(i)) {
return true;
}
}
return false;
}
// / Displays a file load/save dialog and returns the specified file
private String promptFile(boolean isSave, String initFileName) {
int retVal;
String str;
// / ABP
if (filePromptDialog == null)
return null;
if (isSave) {
filePromptDialog.setDialogType(JFileChooser.SAVE_DIALOG);
filePromptDialog.setDialogTitle("Save...");
str = "Save";
} else {
filePromptDialog.setDialogType(JFileChooser.OPEN_DIALOG);
filePromptDialog.setDialogTitle("Load...");
str = "Load";
}
if (initFileName != null)
filePromptDialog.setSelectedFile(new File(initFileName));
retVal = filePromptDialog.showDialog(this, str);
if (retVal == JFileChooser.APPROVE_OPTION) {
File file = filePromptDialog.getSelectedFile();
String fileName = file.getAbsolutePath();
if (fileName != null) {
return fileName;
}
}
return null;
}
// / Converts user text into arrays of String, delimited at newline character
// / Also replaces any valid escape sequence with appropriate unicode
// character
// / Support \\UXXXXXX notation for surrogates
private String[] parseUserText(String orig) {
int length = orig.length();
StringTokenizer perLine = new StringTokenizer(orig, "\n");
String textLines[] = new String[perLine.countTokens()];
int lineNumber = 0;
while (perLine.hasMoreElements()) {
StringBuffer converted = new StringBuffer();
String oneLine = perLine.nextToken();
int lineLength = oneLine.length();
int prevEscapeEnd = 0;
int nextEscape = -1;
do {
int nextBMPEscape = oneLine.indexOf("\\u", prevEscapeEnd);
int nextSupEscape = oneLine.indexOf("\\U", prevEscapeEnd);
|