1 /* 2 * Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * - Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 11 * - Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * - Neither the name of Oracle nor the names of its 16 * contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 20 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 21 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 26 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 27 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 28 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 29 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * This source code is provided to illustrate the usage of a given feature 34 * or technique and has been deliberately simplified. Additional steps 35 * required for a production-quality application, such as security checks, 36 * input validation and proper error handling, might not be present in 37 * this sample code. 38 */ 39 40 41 42 import java.awt.BorderLayout; 43 import java.awt.Color; 44 import java.awt.Cursor; 45 import java.awt.Dimension; 46 import java.awt.Font; 47 import java.awt.FontMetrics; 48 import java.awt.Graphics; 49 import java.awt.Graphics2D; 50 import java.awt.GraphicsConfiguration; 51 import java.awt.GraphicsEnvironment; 52 import java.awt.Point; 53 import java.awt.Rectangle; 54 import java.awt.RenderingHints; 55 import java.awt.Toolkit; 56 import java.awt.event.AdjustmentEvent; 57 import java.awt.event.AdjustmentListener; 58 import java.awt.event.ComponentAdapter; 59 import java.awt.event.ComponentEvent; 60 import java.awt.event.MouseEvent; 61 import java.awt.event.MouseListener; 62 import java.awt.event.MouseMotionListener; 63 import java.awt.font.FontRenderContext; 64 import java.awt.font.GlyphVector; 65 import java.awt.font.LineBreakMeasurer; 66 import java.awt.font.TextLayout; 67 import java.awt.geom.AffineTransform; 68 import java.awt.geom.NoninvertibleTransformException; 69 import java.awt.geom.Rectangle2D; 70 import java.awt.image.BufferedImage; 71 import java.awt.print.PageFormat; 72 import java.awt.print.Printable; 73 import java.awt.print.PrinterJob; 74 import java.io.BufferedOutputStream; 75 import java.io.FileOutputStream; 76 import java.text.AttributedString; 77 import java.util.EnumSet; 78 import java.util.Vector; 79 80 import javax.imageio.*; 81 import javax.swing.*; 82 83 import static java.awt.RenderingHints.*; 84 85 /** 86 * FontPanel.java 87 * 88 * @author Shinsuke Fukuda 89 * @author Ankit Patel [Conversion to Swing - 01/07/30] 90 */ 91 92 /// This panel is combination of the text drawing area of Font2DTest 93 /// and the custom controlled scroll bar 94 95 public final class FontPanel extends JPanel implements AdjustmentListener { 96 97 /// Drawing Option Constants 98 private final String[] STYLES = 99 { "plain", "bold", "italic", "bold italic" }; 100 101 private final int NONE = 0; 102 private final int SCALE = 1; 103 private final int SHEAR = 2; 104 private final int ROTATE = 3; 105 private final String[] TRANSFORMS = 106 { "with no transforms", "with scaling", "with Shearing", "with rotation" }; 107 108 private final int DRAW_STRING = 0; 109 private final int DRAW_CHARS = 1; 110 private final int DRAW_BYTES = 2; 111 private final int DRAW_GLYPHV = 3; 112 private final int TL_DRAW = 4; 113 private final int GV_OUTLINE = 5; 114 private final int TL_OUTLINE = 6; 115 private final String[] METHODS = { 116 "drawString", "drawChars", "drawBytes", "drawGlyphVector", 117 "TextLayout.draw", "GlyphVector.getOutline", "TextLayout.getOutline" }; 118 119 public final int RANGE_TEXT = 0; 120 public final int ALL_GLYPHS = 1; 121 public final int USER_TEXT = 2; 122 public final int FILE_TEXT = 3; 123 private final String[] MS_OPENING = 124 { " Unicode ", " Glyph Code ", " lines ", " lines " }; 125 private final String[] MS_CLOSING = 126 { "", "", " of User Text ", " of LineBreakMeasurer-reformatted Text " }; 127 128 /// General Graphics Variable 129 private final JScrollBar verticalBar; 130 private final FontCanvas fc; 131 private boolean updateFontMetrics = true; 132 private boolean updateFont = true; 133 private boolean force16Cols = false; 134 public boolean showingError = false; 135 private int g2Transform = NONE; /// ABP 136 137 /// Printing constants and variables 138 public final int ONE_PAGE = 0; 139 public final int CUR_RANGE = 1; 140 public final int ALL_TEXT = 2; 141 private int printMode = ONE_PAGE; 142 private PageFormat page = null; 143 private PrinterJob printer = null; 144 145 /// Text drawing variables 146 private String fontName = "Dialog"; 147 private float fontSize = 12; 148 private int fontStyle = Font.PLAIN; 149 private int fontTransform = NONE; 150 private Font testFont = null; 151 private Object antiAliasType = VALUE_TEXT_ANTIALIAS_DEFAULT; 152 private Object fractionalMetricsType = VALUE_FRACTIONALMETRICS_DEFAULT; 153 private Object lcdContrast = getDefaultLCDContrast(); 154 private int drawMethod = DRAW_STRING; 155 private int textToUse = RANGE_TEXT; 156 private String[] userText = null; 157 private String[] fileText = null; 158 private int[] drawRange = { 0x0000, 0x007f }; 159 private String[] fontInfos = new String[2]; 160 private boolean showGrid = true; 161 162 /// Parent Font2DTest panel 163 private final Font2DTest f2dt; 164 private final JFrame parent; 165 166 public FontPanel( Font2DTest demo, JFrame f ) { 167 f2dt = demo; 168 parent = f; 169 170 verticalBar = new JScrollBar ( JScrollBar.VERTICAL ); 171 fc = new FontCanvas(); 172 173 this.setLayout( new BorderLayout() ); 174 this.add( "Center", fc ); 175 this.add( "East", verticalBar ); 176 177 verticalBar.addAdjustmentListener( this ); 178 this.addComponentListener( new ComponentAdapter() { 179 public void componentResized( ComponentEvent e ) { 180 updateFontMetrics = true; 181 } 182 }); 183 184 /// Initialize font and its infos 185 testFont = new Font(fontName, fontStyle, (int)fontSize); 186 if ((float)((int)fontSize) != fontSize) { 187 testFont = testFont.deriveFont(fontSize); 188 } 189 updateFontInfo(); 190 } 191 192 public Dimension getPreferredSize() { 193 return new Dimension(600, 200); 194 } 195 196 /// Functions called by the main programs to set the various parameters 197 198 public void setTransformG2( int transform ) { 199 g2Transform = transform; 200 updateFontMetrics = true; 201 fc.repaint(); 202 } 203 204 /// convenience fcn to create AffineTransform of appropriate type 205 private AffineTransform getAffineTransform( int transform ) { 206 /// ABP 207 AffineTransform at = new AffineTransform(); 208 switch ( transform ) 209 { 210 case SCALE: 211 at.setToScale( 1.5f, 1.5f ); break; 212 case ROTATE: 213 at.setToRotation( Math.PI / 6 ); break; 214 case SHEAR: 215 at.setToShear( 0.4f, 0 ); break; 216 case NONE: 217 break; 218 default: 219 //System.err.println( "Illegal G2 Transform Arg: " + transform); 220 break; 221 } 222 223 return at; 224 } 225 226 public void setFontParams(Object obj, float size, 227 int style, int transform) { 228 setFontParams( (String)obj, size, style, transform ); 229 } 230 231 public void setFontParams(String name, float size, 232 int style, int transform) { 233 boolean fontModified = false; 234 if ( !name.equals( fontName ) || style != fontStyle ) 235 fontModified = true; 236 237 fontName = name; 238 fontSize = size; 239 fontStyle = style; 240 fontTransform = transform; 241 242 /// Recreate the font as specified 243 testFont = new Font(fontName, fontStyle, (int)fontSize); 244 if ((float)((int)fontSize) != fontSize) { 245 testFont = testFont.deriveFont(fontSize); 246 } 247 248 if ( fontTransform != NONE ) { 249 AffineTransform at = getAffineTransform( fontTransform ); 250 testFont = testFont.deriveFont( at ); 251 } 252 updateFontMetrics = true; 253 fc.repaint(); 254 if ( fontModified ) { 255 /// Tell main panel to update the font info 256 updateFontInfo(); 257 f2dt.fireUpdateFontInfo(); 258 } 259 } 260 261 public void setRenderingHints( Object aa, Object fm, Object contrast) { 262 antiAliasType = ((AAValues)aa).getHint(); 263 fractionalMetricsType = ((FMValues)fm).getHint(); 264 lcdContrast = contrast; 265 updateFontMetrics = true; 266 fc.repaint(); 267 } 268 269 public void setDrawMethod( int i ) { 270 drawMethod = i; 271 fc.repaint(); 272 } 273 274 public void setTextToDraw( int i, int[] range, 275 String[] textSet, String[] fileData ) { 276 textToUse = i; 277 278 if ( textToUse == RANGE_TEXT ) 279 drawRange = range; 280 else if ( textToUse == ALL_GLYPHS ) 281 drawMethod = DRAW_GLYPHV; 282 else if ( textToUse == USER_TEXT ) 283 userText = textSet; 284 else if ( textToUse == FILE_TEXT ) { 285 fileText = fileData; 286 drawMethod = TL_DRAW; 287 } 288 289 updateFontMetrics = true; 290 fc.repaint(); 291 updateFontInfo(); 292 } 293 294 public void setGridDisplay( boolean b ) { 295 showGrid = b; 296 fc.repaint(); 297 } 298 299 public void setForce16Columns( boolean b ) { 300 force16Cols = b; 301 updateFontMetrics = true; 302 fc.repaint(); 303 } 304 305 /// Prints out the text display area 306 public void doPrint( int i ) { 307 if ( printer == null ) { 308 printer = PrinterJob.getPrinterJob(); 309 page = printer.defaultPage(); 310 } 311 printMode = i; 312 printer.setPrintable( fc, page ); 313 314 if ( printer.printDialog() ) { 315 try { 316 printer.print(); 317 } 318 catch ( Exception e ) { 319 f2dt.fireChangeStatus( "ERROR: Printing Failed; See Stack Trace", true ); 320 } 321 } 322 } 323 324 /// Displays the page setup dialog and updates PageFormat info 325 public void doPageSetup() { 326 if ( printer == null ) { 327 printer = PrinterJob.getPrinterJob(); 328 page = printer.defaultPage(); 329 } 330 page = printer.pageDialog( page ); 331 } 332 333 /// Obtains the information about selected font 334 private void updateFontInfo() { 335 int numGlyphs = 0, numCharsInRange = drawRange[1] - drawRange[0] + 1; 336 fontInfos[0] = "Font Face Name: " + testFont.getFontName(); 337 fontInfos[1] = "Glyphs in This Range: "; 338 339 if ( textToUse == RANGE_TEXT ) { 340 for ( int i = drawRange[0]; i < drawRange[1]; i++ ) 341 if ( testFont.canDisplay( i )) 342 numGlyphs++; 343 fontInfos[1] = fontInfos[1] + numGlyphs + " / " + numCharsInRange; 344 } 345 else 346 fontInfos[1] = null; 347 } 348 349 /// Accessor for the font information 350 public String[] getFontInfo() { 351 return fontInfos; 352 } 353 354 /// Collects the currectly set options and returns them as string 355 public String getCurrentOptions() { 356 /// Create a new String to store the options 357 /// The array will contain all 8 setting (font name, size...) and 358 /// character range or user text data used (no file text data) 359 int userTextSize = 0; 360 String options; 361 362 options = ( fontName + "\n" + fontSize + "\n" + fontStyle + "\n" + 363 fontTransform + "\n" + g2Transform + "\n"+ 364 textToUse + "\n" + drawMethod + "\n" + 365 AAValues.getHintVal(antiAliasType) + "\n" + 366 FMValues.getHintVal(fractionalMetricsType) + "\n" + 367 lcdContrast + "\n"); 368 if ( textToUse == USER_TEXT ) 369 for ( int i = 0; i < userText.length; i++ ) 370 options += ( userText[i] + "\n" ); 371 372 return options; 373 } 374 375 /// Reload all options and refreshes the canvas 376 public void loadOptions( boolean grid, boolean force16, int start, int end, 377 String name, float size, int style, 378 int transform, int g2transform, 379 int text, int method, int aa, int fm, 380 int contrast, String[] user ) { 381 int[] range = { start, end }; 382 383 /// Since repaint call has a low priority, these functions will finish 384 /// before the actual repainting is done 385 setGridDisplay( grid ); 386 setForce16Columns( force16 ); 387 // previous call to readTextFile has already set the text to draw 388 if (textToUse != FILE_TEXT) { 389 setTextToDraw( text, range, user, null ); 390 } 391 setFontParams( name, size, style, transform ); 392 setTransformG2( g2transform ); // ABP 393 setDrawMethod( method ); 394 setRenderingHints(AAValues.getValue(aa), FMValues.getValue(fm), 395 Integer.valueOf(contrast)); 396 } 397 398 /// Writes the current screen to PNG file 399 public void doSavePNG( String fileName ) { 400 fc.writePNG( fileName ); 401 } 402 403 /// When scrolled using the scroll bar, update the backbuffer 404 public void adjustmentValueChanged( AdjustmentEvent e ) { 405 fc.repaint(); 406 } 407 408 public void paintComponent( Graphics g ) { 409 // Windows does not repaint correctly, after 410 // a zoom. Thus, we need to force the canvas 411 // to repaint, but only once. After the first repaint, 412 // everything stabilizes. [ABP] 413 fc.repaint(); 414 } 415 416 /// Inner class definition... 417 418 /// Inner panel that holds the actual drawing area and its routines 419 private class FontCanvas extends JPanel implements MouseListener, MouseMotionListener, Printable { 420 421 /// Number of characters that will fit across and down this canvas 422 private int numCharAcross, numCharDown; 423 424 /// First and last character/line that will be drawn 425 /// Limit is the end of range/text where no more draw will be done 426 private int drawStart, drawEnd, drawLimit; 427 428 /// FontMetrics variables 429 /// Here, gridWidth is equivalent to maxAdvance (slightly bigger though) 430 /// and gridHeight is equivalent to lineHeight 431 private int maxAscent, maxDescent, gridWidth = 0, gridHeight = 0; 432 433 /// Offset from the top left edge of the canvas where the draw will start 434 private int canvasInset_X = 5, canvasInset_Y = 5; 435 436 /// LineBreak'ed TextLayout vector 437 private Vector<TextLayout> lineBreakTLs = null; 438 439 /// Whether the current draw command requested is for printing 440 private boolean isPrinting = false; 441 442 /// Other printing infos 443 private int lastPage, printPageNumber, currentlyShownChar = 0; 444 private final int PR_OFFSET = 10; 445 private final int PR_TITLE_LINEHEIGHT = 30; 446 447 /// Information about zooming (used with range text draw) 448 private final JWindow zoomWindow; 449 private BufferedImage zoomImage = null; 450 private int mouseOverCharX = -1, mouseOverCharY = -1; 451 private int currMouseOverChar = -1, prevZoomChar = -1; 452 private float ZOOM = 2.0f; 453 private boolean nowZooming = false; 454 private boolean firstTime = true; 455 // ABP 456 457 /// Status bar message backup 458 private String backupStatusString = null; 459 460 /// Error constants 461 private final String[] ERRORS = { 462 "ERROR: drawBytes cannot handle characters beyond 0x00FF. Select different range or draw methods.", 463 "ERROR: Cannot fit text with the current font size. Resize the window or use smaller font size.", 464 "ERROR: Cannot print with the current font size. Use smaller font size.", 465 }; 466 467 private final int DRAW_BYTES_ERROR = 0; 468 private final int CANT_FIT_DRAW = 1; 469 private final int CANT_FIT_PRINT = 2; 470 471 /// Other variables 472 private final Cursor blankCursor; 473 474 public FontCanvas() { 475 this.addMouseListener( this ); 476 this.addMouseMotionListener( this ); 477 this.setForeground( Color.black ); 478 this.setBackground( Color.white ); 479 480 /// Creates an invisble pointer by giving it bogus image 481 /// Possibly find a workaround for this... 482 Toolkit tk = Toolkit.getDefaultToolkit(); 483 byte[] bogus = { (byte) 0 }; 484 blankCursor = 485 tk.createCustomCursor( tk.createImage( bogus ), new Point(0, 0), "" ); 486 487 zoomWindow = new JWindow( parent ) { 488 public void paint( Graphics g ) { 489 g.drawImage( zoomImage, 0, 0, zoomWindow ); 490 } 491 }; 492 zoomWindow.setCursor( blankCursor ); 493 zoomWindow.pack(); 494 } 495 496 public boolean firstTime() { return firstTime; } 497 public void refresh() { 498 firstTime = false; 499 repaint(); 500 } 501 502 /// Sets the font, hints, according to the set parameters 503 private void setParams( Graphics2D g2 ) { 504 g2.setFont( testFont ); 505 g2.setRenderingHint(KEY_TEXT_ANTIALIASING, antiAliasType); 506 g2.setRenderingHint(KEY_FRACTIONALMETRICS, fractionalMetricsType); 507 g2.setRenderingHint(KEY_TEXT_LCD_CONTRAST, lcdContrast); 508 /* I am preserving a somewhat dubious behaviour of this program. 509 * Outline text would be drawn anti-aliased by setting the 510 * graphics anti-aliasing hint if the text anti-aliasing hint 511 * was set. The dubious element here is that people simply 512 * using this program may think this is built-in behaviour 513 * but its not - at least not when the app explicitly draws 514 * outline text. 515 * This becomes more dubious in cases such as "GASP" where the 516 * size at which text is AA'ed is not something you can easily 517 * calculate, so mimicing that behaviour isn't going to be easy. 518 * So I precisely preserve the behaviour : this is done only 519 * if the AA value is "ON". Its not applied in the other cases. 520 */ 521 if (antiAliasType == VALUE_TEXT_ANTIALIAS_ON && 522 (drawMethod == TL_OUTLINE || drawMethod == GV_OUTLINE)) { 523 g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); 524 } else { 525 g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_OFF); 526 } 527 } 528 529 /// Draws the grid (Used for unicode/glyph range drawing) 530 private void drawGrid( Graphics2D g2 ) { 531 int totalGridWidth = numCharAcross * gridWidth; 532 int totalGridHeight = numCharDown * gridHeight; 533 534 g2.setColor( Color.black ); 535 for ( int i = 0; i < numCharDown + 1; i++ ) 536 g2.drawLine( canvasInset_X, i * gridHeight + canvasInset_Y, 537 canvasInset_X + totalGridWidth, i * gridHeight + canvasInset_Y ); 538 for ( int i = 0; i < numCharAcross + 1; i++ ) 539 g2.drawLine( i * gridWidth + canvasInset_X, canvasInset_Y, 540 i * gridWidth + canvasInset_X, canvasInset_Y + totalGridHeight ); 541 } 542 543 /// Draws one character at time onto the canvas according to 544 /// the method requested (Used for RANGE_TEXT and ALL_GLYPHS) 545 public void modeSpecificDrawChar( Graphics2D g2, int charCode, 546 int baseX, int baseY ) { 547 GlyphVector gv; 548 int[] oneGlyph = { charCode }; 549 char[] charArray = Character.toChars( charCode ); 550 551 FontRenderContext frc = g2.getFontRenderContext(); 552 AffineTransform oldTX = g2.getTransform(); 553 554 /// Create GlyphVector to measure the exact visual advance 555 /// Using that number, adjust the position of the character drawn 556 if ( textToUse == ALL_GLYPHS ) 557 gv = testFont.createGlyphVector( frc, oneGlyph ); 558 else 559 gv = testFont.createGlyphVector( frc, charArray ); 560 Rectangle2D r2d2 = gv.getPixelBounds(frc, 0, 0); 561 int shiftedX = baseX; 562 // getPixelBounds returns a result in device space. 563 // we need to convert back to user space to be able to 564 // calculate the shift as baseX is in user space. 565 try { 566 double[] pt = new double[4]; 567 pt[0] = r2d2.getX(); 568 pt[1] = r2d2.getY(); 569 pt[2] = r2d2.getX()+r2d2.getWidth(); 570 pt[3] = r2d2.getY()+r2d2.getHeight(); 571 oldTX.inverseTransform(pt,0,pt,0,2); 572 shiftedX = baseX - (int) ( pt[2] / 2 + pt[0] ); 573 } catch (NoninvertibleTransformException e) { 574 } 575 576 /// ABP - keep track of old tform, restore it later 577 578 g2.translate( shiftedX, baseY ); 579 g2.transform( getAffineTransform( g2Transform ) ); 580 581 if ( textToUse == ALL_GLYPHS ) 582 g2.drawGlyphVector( gv, 0f, 0f ); 583 else { 584 if ( testFont.canDisplay( charCode )) 585 g2.setColor( Color.black ); 586 else { 587 g2.setColor( Color.lightGray ); 588 } 589 590 switch ( drawMethod ) { 591 case DRAW_STRING: 592 g2.drawString( new String( charArray ), 0, 0 ); 593 break; 594 case DRAW_CHARS: 595 g2.drawChars( charArray, 0, 1, 0, 0 ); 596 break; 597 case DRAW_BYTES: 598 if ( charCode > 0xff ) 599 throw new CannotDrawException( DRAW_BYTES_ERROR ); 600 byte[] oneByte = { (byte) charCode }; 601 g2.drawBytes( oneByte, 0, 1, 0, 0 ); 602 break; 603 case DRAW_GLYPHV: 604 g2.drawGlyphVector( gv, 0f, 0f ); 605 break; 606 case TL_DRAW: 607 TextLayout tl = new TextLayout( new String( charArray ), testFont, frc ); 608 tl.draw( g2, 0f, 0f ); 609 break; 610 case GV_OUTLINE: 611 r2d2 = gv.getVisualBounds(); 612 shiftedX = baseX - (int) ( r2d2.getWidth() / 2 + r2d2.getX() ); 613 g2.draw( gv.getOutline( 0f, 0f )); 614 break; 615 case TL_OUTLINE: 616 r2d2 = gv.getVisualBounds(); 617 shiftedX = baseX - (int) ( r2d2.getWidth() / 2 + r2d2.getX() ); 618 TextLayout tlo = 619 new TextLayout( new String( charArray ), testFont, 620 g2.getFontRenderContext() ); 621 g2.draw( tlo.getOutline( null )); 622 } 623 } 624 625 /// ABP - restore old tform 626 g2.setTransform ( oldTX ); 627 } 628 629 /// Draws one line of text at given position 630 private void modeSpecificDrawLine( Graphics2D g2, String line, 631 int baseX, int baseY ) { 632 /// ABP - keep track of old tform, restore it later 633 AffineTransform oldTx = null; 634 oldTx = g2.getTransform(); 635 g2.translate( baseX, baseY ); 636 g2.transform( getAffineTransform( g2Transform ) ); 637 638 switch ( drawMethod ) { 639 case DRAW_STRING: 640 g2.drawString( line, 0, 0 ); 641 break; 642 case DRAW_CHARS: 643 g2.drawChars( line.toCharArray(), 0, line.length(), 0, 0 ); 644 break; 645 case DRAW_BYTES: 646 try { 647 byte[] lineBytes = line.getBytes( "ISO-8859-1" ); 648 g2.drawBytes( lineBytes, 0, lineBytes.length, 0, 0 ); 649 } 650 catch ( Exception e ) { 651 e.printStackTrace(); 652 } 653 break; 654 case DRAW_GLYPHV: 655 GlyphVector gv = 656 testFont.createGlyphVector( g2.getFontRenderContext(), line ); 657 g2.drawGlyphVector( gv, (float) 0, (float) 0 ); 658 break; 659 case TL_DRAW: 660 TextLayout tl = new TextLayout( line, testFont, 661 g2.getFontRenderContext() ); 662 tl.draw( g2, (float) 0, (float) 0 ); 663 break; 664 case GV_OUTLINE: 665 GlyphVector gvo = 666 testFont.createGlyphVector( g2.getFontRenderContext(), line ); 667 g2.draw( gvo.getOutline( (float) 0, (float) 0 )); 668 break; 669 case TL_OUTLINE: 670 TextLayout tlo = 671 new TextLayout( line, testFont, 672 g2.getFontRenderContext() ); 673 AffineTransform at = new AffineTransform(); 674 g2.draw( tlo.getOutline( at )); 675 } 676 677 /// ABP - restore old tform 678 g2.setTransform ( oldTx ); 679 680 } 681 682 /// Draws one line of text at given position 683 private void tlDrawLine( Graphics2D g2, TextLayout tl, 684 float baseX, float baseY ) { 685 /// ABP - keep track of old tform, restore it later 686 AffineTransform oldTx = null; 687 oldTx = g2.getTransform(); 688 g2.translate( baseX, baseY ); 689 g2.transform( getAffineTransform( g2Transform ) ); 690 691 tl.draw( g2, (float) 0, (float) 0 ); 692 693 /// ABP - restore old tform 694 g2.setTransform ( oldTx ); 695 696 } 697 698 699 /// If textToUse is set to range drawing, then convert 700 /// int to hex string and prepends 0s to make it length 4 701 /// Otherwise line number was fed; simply return number + 1 converted to String 702 /// (This is because first line is 1, not 0) 703 private String modeSpecificNumStr( int i ) { 704 if ( textToUse == USER_TEXT || textToUse == FILE_TEXT ) 705 return String.valueOf( i + 1 ); 706 707 StringBuffer s = new StringBuffer( Integer.toHexString( i )); 708 while ( s.length() < 4 ) 709 s.insert( 0, "0" ); 710 return s.toString().toUpperCase(); 711 } 712 713 /// Resets the scrollbar to display correct range of text currently on screen 714 /// (This scrollbar is not part of a "ScrollPane". It merely simulates its effect by 715 /// indicating the necessary area to be drawn within the panel. 716 /// By doing this, it prevents creating gigantic panel when large text range, 717 /// i.e. CJK Ideographs, is requested) 718 private void resetScrollbar( int oldValue ) { 719 int totalNumRows = 1, numCharToDisplay; 720 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) { 721 if ( textToUse == RANGE_TEXT ) 722 numCharToDisplay = drawRange[1] - drawRange[0]; 723 else /// textToUse == ALL_GLYPHS 724 numCharToDisplay = testFont.getNumGlyphs(); 725 726 totalNumRows = numCharToDisplay / numCharAcross; 727 if ( numCharToDisplay % numCharAcross != 0 ) 728 totalNumRows++; 729 if ( oldValue / numCharAcross > totalNumRows ) 730 oldValue = 0; 731 732 verticalBar.setValues( oldValue / numCharAcross, 733 numCharDown, 0, totalNumRows ); 734 } 735 else { 736 if ( textToUse == USER_TEXT ) 737 totalNumRows = userText.length; 738 else /// textToUse == FILE_TEXT; 739 totalNumRows = lineBreakTLs.size(); 740 verticalBar.setValues( oldValue, numCharDown, 0, totalNumRows ); 741 } 742 if ( totalNumRows <= numCharDown && drawStart == 0) { 743 verticalBar.setEnabled( false ); 744 } 745 else { 746 verticalBar.setEnabled( true ); 747 } 748 } 749 750 /// Calculates the font's metrics that will be used for draw 751 private void calcFontMetrics( Graphics2D g2d, int w, int h ) { 752 FontMetrics fm; 753 Graphics2D g2 = (Graphics2D)g2d.create(); 754 755 /// ABP 756 if ( g2Transform != NONE && textToUse != FILE_TEXT ) { 757 g2.setFont( g2.getFont().deriveFont( getAffineTransform( g2Transform )) ); 758 fm = g2.getFontMetrics(); 759 } 760 else { 761 fm = g2.getFontMetrics(); 762 } 763 764 maxAscent = fm.getMaxAscent(); 765 maxDescent = fm.getMaxDescent(); 766 if (maxAscent == 0) maxAscent = 10; 767 if (maxDescent == 0) maxDescent = 5; 768 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) { 769 /// Give slight extra room for each character 770 maxAscent += 3; 771 maxDescent += 3; 772 gridWidth = fm.getMaxAdvance() + 6; 773 gridHeight = maxAscent + maxDescent; 774 if ( force16Cols ) 775 numCharAcross = 16; 776 else 777 numCharAcross = ( w - 10 ) / gridWidth; 778 numCharDown = ( h - 10 ) / gridHeight; 779 780 canvasInset_X = ( w - numCharAcross * gridWidth ) / 2; 781 canvasInset_Y = ( h - numCharDown * gridHeight ) / 2; 782 if ( numCharDown == 0 || numCharAcross == 0 ) 783 throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW ); 784 785 if ( !isPrinting ) 786 resetScrollbar( verticalBar.getValue() * numCharAcross ); 787 } 788 else { 789 maxDescent += fm.getLeading(); 790 canvasInset_X = 5; 791 canvasInset_Y = 5; 792 /// gridWidth and numCharAcross will not be used in this mode... 793 gridHeight = maxAscent + maxDescent; 794 numCharDown = ( h - canvasInset_Y * 2 ) / gridHeight; 795 796 if ( numCharDown == 0 ) 797 throw new CannotDrawException( isPrinting ? CANT_FIT_PRINT : CANT_FIT_DRAW ); 798 /// If this is text loaded from file, prepares the LineBreak'ed 799 /// text layout at this point 800 if ( textToUse == FILE_TEXT ) { 801 if ( !isPrinting ) 802 f2dt.fireChangeStatus( "LineBreaking Text... Please Wait", false ); 803 lineBreakTLs = new Vector<>(); 804 for ( int i = 0; i < fileText.length; i++ ) { 805 AttributedString as = 806 new AttributedString( fileText[i], g2.getFont().getAttributes() ); 807 808 LineBreakMeasurer lbm = 809 new LineBreakMeasurer( as.getIterator(), g2.getFontRenderContext() ); 810 811 while ( lbm.getPosition() < fileText[i].length() ) 812 lineBreakTLs.add( lbm.nextLayout( (float) w )); 813 814 } 815 } 816 if ( !isPrinting ) 817 resetScrollbar( verticalBar.getValue() ); 818 } 819 } 820 821 /// Calculates the amount of text that will be displayed on screen 822 private void calcTextRange() { 823 String displaying = null; 824 825 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) { 826 if ( isPrinting ) 827 if ( printMode == ONE_PAGE ) 828 drawStart = currentlyShownChar; 829 else /// printMode == CUR_RANGE 830 drawStart = numCharAcross * numCharDown * printPageNumber; 831 else 832 drawStart = verticalBar.getValue() * numCharAcross; 833 if ( textToUse == RANGE_TEXT ) { 834 drawStart += drawRange[0]; 835 drawLimit = drawRange[1]; 836 } 837 else 838 drawLimit = testFont.getNumGlyphs(); 839 drawEnd = drawStart + numCharAcross * numCharDown - 1; 840 841 if ( drawEnd >= drawLimit ) 842 drawEnd = drawLimit; 843 } 844 else { 845 if ( isPrinting ) 846 if ( printMode == ONE_PAGE ) 847 drawStart = currentlyShownChar; 848 else /// printMode == ALL_TEXT 849 drawStart = numCharDown * printPageNumber; 850 else { 851 drawStart = verticalBar.getValue(); 852 } 853 854 drawEnd = drawStart + numCharDown - 1; 855 856 if ( textToUse == USER_TEXT ) 857 drawLimit = userText.length - 1; 858 else 859 drawLimit = lineBreakTLs.size() - 1; 860 861 if ( drawEnd >= drawLimit ) 862 drawEnd = drawLimit; 863 } 864 865 // ABP 866 if ( drawStart > drawEnd ) { 867 drawStart = 0; 868 verticalBar.setValue(drawStart); 869 } 870 871 872 /// Change the status bar if not printing... 873 if ( !isPrinting ) { 874 backupStatusString = ( "Displaying" + MS_OPENING[textToUse] + 875 modeSpecificNumStr( drawStart ) + " to " + 876 modeSpecificNumStr( drawEnd ) + 877 MS_CLOSING[textToUse] ); 878 f2dt.fireChangeStatus( backupStatusString, false ); 879 } 880 } 881 882 /// Draws text according to the parameters set by Font2DTest GUI 883 private void drawText( Graphics g, int w, int h ) { 884 Graphics2D g2 = (Graphics2D) g; 885 g2.setColor(Color.white); 886 g2.fillRect(0, 0, w, h); 887 g2.setColor(Color.black); 888 889 /// sets font, RenderingHints. 890 setParams( g2 ); 891 892 /// If flag is set, recalculate fontMetrics and reset the scrollbar 893 if ( updateFontMetrics || isPrinting ) { 894 /// NOTE: re-calculates in case G2 transform 895 /// is something other than NONE 896 calcFontMetrics( g2, w, h ); 897 updateFontMetrics = false; 898 } 899 /// Calculate the amount of text that can be drawn... 900 calcTextRange(); 901 902 /// Draw according to the set "Text to Use" mode 903 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) { 904 int charToDraw = drawStart; 905 if ( showGrid ) 906 drawGrid( g2 ); 907 908 for ( int i = 0; i < numCharDown && charToDraw <= drawEnd; i++ ) { 909 for ( int j = 0; j < numCharAcross && charToDraw <= drawEnd; j++, charToDraw++ ) { 910 int gridLocX = j * gridWidth + canvasInset_X; 911 int gridLocY = i * gridHeight + canvasInset_Y; 912 913 modeSpecificDrawChar( g2, charToDraw, 914 gridLocX + gridWidth / 2, 915 gridLocY + maxAscent ); 916 917 } 918 } 919 } 920 else if ( textToUse == USER_TEXT ) { 921 g2.drawRect( 0, 0, w - 1, h - 1 ); 922 for ( int i = drawStart; i <= drawEnd; i++ ) { 923 int lineStartX = canvasInset_Y; 924 int lineStartY = ( i - drawStart ) * gridHeight + maxAscent; 925 modeSpecificDrawLine( g2, userText[i], lineStartX, lineStartY ); 926 } 927 } 928 else { 929 float xPos, yPos = (float) canvasInset_Y; 930 g2.drawRect( 0, 0, w - 1, h - 1 ); 931 for ( int i = drawStart; i <= drawEnd; i++ ) { 932 TextLayout oneLine = lineBreakTLs.elementAt( i ); 933 xPos = 934 oneLine.isLeftToRight() ? 935 canvasInset_X : ( (float) w - oneLine.getAdvance() - canvasInset_X ); 936 937 float[] fmData = {0, oneLine.getAscent(), 0, oneLine.getDescent(), 0, oneLine.getLeading()}; 938 if (g2Transform != NONE) { 939 AffineTransform at = getAffineTransform(g2Transform); 940 at.transform( fmData, 0, fmData, 0, 3); 941 } 942 //yPos += oneLine.getAscent(); 943 yPos += fmData[1]; // ascent 944 //oneLine.draw( g2, xPos, yPos ); 945 tlDrawLine( g2, oneLine, xPos, yPos ); 946 //yPos += oneLine.getDescent() + oneLine.getLeading(); 947 yPos += fmData[3] + fmData[5]; // descent + leading 948 } 949 } 950 g2.dispose(); 951 } 952 953 /// Component paintComponent function... 954 /// Draws/Refreshes canvas according to flag(s) set by other functions 955 public void paintComponent( Graphics g ) { 956 super.paintComponent(g); 957 958 Dimension d = this.getSize(); 959 isPrinting = false; 960 try { 961 drawText( g, d.width, d.height ); 962 } 963 catch ( CannotDrawException e ) { 964 super.paintComponent(g); 965 f2dt.fireChangeStatus( ERRORS[ e.id ], true ); 966 return; 967 } 968 969 showingError = false; 970 } 971 972 /// Printable interface function 973 /// Component print function... 974 public int print( Graphics g, PageFormat pf, int pageIndex ) { 975 if ( pageIndex == 0 ) { 976 /// Reset the last page index to max... 977 lastPage = Integer.MAX_VALUE; 978 currentlyShownChar = verticalBar.getValue() * numCharAcross; 979 } 980 981 if ( printMode == ONE_PAGE ) { 982 if ( pageIndex > 0 ) 983 return NO_SUCH_PAGE; 984 } 985 else { 986 if ( pageIndex > lastPage ) 987 return NO_SUCH_PAGE; 988 } 989 990 int pageWidth = (int) pf.getImageableWidth(); 991 int pageHeight = (int) pf.getImageableHeight(); 992 /// Back up metrics and other drawing info before printing modifies it 993 int backupDrawStart = drawStart, backupDrawEnd = drawEnd; 994 int backupNumCharAcross = numCharAcross, backupNumCharDown = numCharDown; 995 Vector<TextLayout> backupLineBreakTLs = null; 996 if ( textToUse == FILE_TEXT ) 997 backupLineBreakTLs = new Vector<>(lineBreakTLs); 998 999 printPageNumber = pageIndex; 1000 isPrinting = true; 1001 /// Push the actual draw area 60 down to allow info to be printed 1002 g.translate( (int) pf.getImageableX(), (int) pf.getImageableY() + 60 ); 1003 try { 1004 drawText( g, pageWidth, pageHeight - 60 ); 1005 } 1006 catch ( CannotDrawException e ) { 1007 f2dt.fireChangeStatus( ERRORS[ e.id ], true ); 1008 return NO_SUCH_PAGE; 1009 } 1010 1011 /// Draw information about what is being printed 1012 String hints = ( " with antialias " + antiAliasType + "and" + 1013 " fractional metrics " + fractionalMetricsType + 1014 " and lcd contrast = " + lcdContrast); 1015 String infoLine1 = ( "Printing" + MS_OPENING[textToUse] + 1016 modeSpecificNumStr( drawStart ) + " to " + 1017 modeSpecificNumStr( drawEnd ) + MS_CLOSING[textToUse] ); 1018 String infoLine2 = ( "With " + fontName + " " + STYLES[fontStyle] + " at " + 1019 fontSize + " point size " + TRANSFORMS[fontTransform] ); 1020 String infoLine3 = "Using " + METHODS[drawMethod] + hints; 1021 String infoLine4 = "Page: " + ( pageIndex + 1 ); 1022 g.setFont( new Font( "dialog", Font.PLAIN, 12 )); 1023 g.setColor( Color.black ); 1024 g.translate( 0, -60 ); 1025 g.drawString( infoLine1, 15, 10 ); 1026 g.drawString( infoLine2, 15, 22 ); 1027 g.drawString( infoLine3, 15, 34 ); 1028 g.drawString( infoLine4, 15, 46 ); 1029 1030 if ( drawEnd == drawLimit ) 1031 /// This indicates that the draw will be completed with this page 1032 lastPage = pageIndex; 1033 1034 /// Restore the changed values back... 1035 /// This is important for JScrollBar settings and LineBreak'ed TLs 1036 drawStart = backupDrawStart; 1037 drawEnd = backupDrawEnd; 1038 numCharAcross = backupNumCharAcross; 1039 numCharDown = backupNumCharDown; 1040 if ( textToUse == FILE_TEXT ) 1041 lineBreakTLs = backupLineBreakTLs; 1042 return PAGE_EXISTS; 1043 } 1044 1045 /// Ouputs the current canvas into a given PNG file 1046 public void writePNG( String fileName ) { 1047 try { 1048 int w = this.getSize().width; 1049 int h = this.getSize().height; 1050 BufferedImage buffer = (BufferedImage) this.createImage( w, h ); 1051 Graphics2D g2 = buffer.createGraphics(); 1052 g2.setColor(Color.white); 1053 g2.fillRect(0, 0, w, h); 1054 g2.setColor(Color.black); 1055 updateFontMetrics = true; 1056 drawText(g2, w, h); 1057 updateFontMetrics = true; 1058 ImageIO.write(buffer, "png", new java.io.File(fileName)); 1059 } 1060 catch ( Exception e ) { 1061 f2dt.fireChangeStatus( "ERROR: Failed to Save PNG image; See stack trace", true ); 1062 e.printStackTrace(); 1063 } 1064 } 1065 1066 /// Figures out whether a character at the pointer location is valid 1067 /// And if so, updates mouse location informations, as well as 1068 /// the information on the status bar 1069 private boolean checkMouseLoc( MouseEvent e ) { 1070 if ( gridWidth != 0 && gridHeight != 0 ) 1071 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) { 1072 int charLocX = ( e.getX() - canvasInset_X ) / gridWidth; 1073 int charLocY = ( e.getY() - canvasInset_Y ) / gridHeight; 1074 1075 /// Check to make sure the mouse click location is within drawn area 1076 if ( charLocX >= 0 && charLocY >= 0 && 1077 charLocX < numCharAcross && charLocY < numCharDown ) { 1078 int mouseOverChar = 1079 charLocX + ( verticalBar.getValue() + charLocY ) * numCharAcross; 1080 if ( textToUse == RANGE_TEXT ) 1081 mouseOverChar += drawRange[0]; 1082 if ( mouseOverChar > drawEnd ) 1083 return false; 1084 1085 mouseOverCharX = charLocX; 1086 mouseOverCharY = charLocY; 1087 currMouseOverChar = mouseOverChar; 1088 /// Update status bar 1089 f2dt.fireChangeStatus( "Pointing to" + MS_OPENING[textToUse] + 1090 modeSpecificNumStr( mouseOverChar ), false ); 1091 return true; 1092 } 1093 } 1094 return false; 1095 } 1096 1097 /// Shows (updates) the character zoom window 1098 public void showZoomed() { 1099 GlyphVector gv; 1100 Font backup = testFont; 1101 Point canvasLoc = this.getLocationOnScreen(); 1102 1103 /// Calculate the zoom area's location and size... 1104 int dialogOffsetX = (int) ( gridWidth * ( ZOOM - 1 ) / 2 ); 1105 int dialogOffsetY = (int) ( gridHeight * ( ZOOM - 1 ) / 2 ); 1106 int zoomAreaX = 1107 mouseOverCharX * gridWidth + canvasInset_X - dialogOffsetX; 1108 int zoomAreaY = 1109 mouseOverCharY * gridHeight + canvasInset_Y - dialogOffsetY; 1110 int zoomAreaWidth = (int) ( gridWidth * ZOOM ); 1111 int zoomAreaHeight = (int) ( gridHeight * ZOOM ); 1112 1113 /// Position and set size of zoom window as needed 1114 zoomWindow.setLocation( canvasLoc.x + zoomAreaX, canvasLoc.y + zoomAreaY ); 1115 if ( !nowZooming ) { 1116 if ( zoomWindow.getWarningString() != null ) 1117 /// If this is not opened as a "secure" window, 1118 /// it has a banner below the zoom dialog which makes it look really BAD 1119 /// So enlarge it by a bit 1120 zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 20 ); 1121 else 1122 zoomWindow.setSize( zoomAreaWidth + 1, zoomAreaHeight + 1 ); 1123 } 1124 1125 /// Prepare zoomed image 1126 zoomImage = 1127 (BufferedImage) zoomWindow.createImage( zoomAreaWidth + 1, 1128 zoomAreaHeight + 1 ); 1129 Graphics2D g2 = (Graphics2D) zoomImage.getGraphics(); 1130 testFont = testFont.deriveFont( fontSize * ZOOM ); 1131 setParams( g2 ); 1132 g2.setColor( Color.white ); 1133 g2.fillRect( 0, 0, zoomAreaWidth, zoomAreaHeight ); 1134 g2.setColor( Color.black ); 1135 g2.drawRect( 0, 0, zoomAreaWidth, zoomAreaHeight ); 1136 modeSpecificDrawChar( g2, currMouseOverChar, 1137 zoomAreaWidth / 2, (int) ( maxAscent * ZOOM )); 1138 g2.dispose(); 1139 if ( !nowZooming ) 1140 zoomWindow.setVisible(true); 1141 /// This is sort of redundant... since there is a paint function 1142 /// inside zoomWindow definition that does the drawImage. 1143 /// (I should be able to call just repaint() here) 1144 /// However, for some reason, that paint function fails to respond 1145 /// from second time and on; So I have to force the paint here... 1146 zoomWindow.getGraphics().drawImage( zoomImage, 0, 0, this ); 1147 1148 nowZooming = true; 1149 prevZoomChar = currMouseOverChar; 1150 testFont = backup; 1151 1152 // Windows does not repaint correctly, after 1153 // a zoom. Thus, we need to force the canvas 1154 // to repaint, but only once. After the first repaint, 1155 // everything stabilizes. [ABP] 1156 if ( firstTime() ) { 1157 refresh(); 1158 } 1159 } 1160 1161 /// Listener Functions 1162 1163 /// MouseListener interface function 1164 /// Zooms a character when mouse is pressed above it 1165 public void mousePressed( MouseEvent e ) { 1166 if ( !showingError) { 1167 if ( checkMouseLoc( e )) { 1168 showZoomed(); 1169 this.setCursor( blankCursor ); 1170 } 1171 } 1172 } 1173 1174 /// MouseListener interface function 1175 /// Redraws the area that was drawn over by zoomed character 1176 public void mouseReleased( MouseEvent e ) { 1177 if ( textToUse == RANGE_TEXT || textToUse == ALL_GLYPHS ) { 1178 if ( nowZooming ) 1179 zoomWindow.setVisible(false); 1180 nowZooming = false; 1181 } 1182 this.setCursor( Cursor.getDefaultCursor() ); 1183 } 1184 1185 /// MouseListener interface function 1186 /// Resets the status bar to display range instead of a specific character 1187 public void mouseExited( MouseEvent e ) { 1188 if ( !showingError && !nowZooming ) 1189 f2dt.fireChangeStatus( backupStatusString, false ); 1190 } 1191 1192 /// MouseMotionListener interface function 1193 /// Adjusts the status bar message when mouse moves over a character 1194 public void mouseMoved( MouseEvent e ) { 1195 if ( !showingError ) { 1196 if ( !checkMouseLoc( e )) 1197 f2dt.fireChangeStatus( backupStatusString, false ); 1198 } 1199 } 1200 1201 /// MouseMotionListener interface function 1202 /// Scrolls the zoomed character when mouse is dragged 1203 public void mouseDragged( MouseEvent e ) { 1204 if ( !showingError ) 1205 if ( nowZooming ) { 1206 if ( checkMouseLoc( e ) && currMouseOverChar != prevZoomChar ) 1207 showZoomed(); 1208 } 1209 } 1210 1211 /// Empty function to comply with interface requirement 1212 public void mouseClicked( MouseEvent e ) {} 1213 public void mouseEntered( MouseEvent e ) {} 1214 } 1215 1216 private final class CannotDrawException extends RuntimeException { 1217 /// Error ID 1218 public final int id; 1219 1220 public CannotDrawException( int i ) { 1221 id = i; 1222 } 1223 } 1224 1225 enum FMValues { 1226 FMDEFAULT ("DEFAULT", VALUE_FRACTIONALMETRICS_DEFAULT), 1227 FMOFF ("OFF", VALUE_FRACTIONALMETRICS_OFF), 1228 FMON ("ON", VALUE_FRACTIONALMETRICS_ON); 1229 1230 private String name; 1231 private Object hint; 1232 1233 private static FMValues[] valArray; 1234 1235 FMValues(String s, Object o) { 1236 name = s; 1237 hint = o; 1238 } 1239 1240 public String toString() { 1241 return name; 1242 } 1243 1244 public Object getHint() { 1245 return hint; 1246 } 1247 public static Object getValue(int ordinal) { 1248 if (valArray == null) { 1249 valArray = EnumSet.allOf(FMValues.class).toArray(new FMValues[0]); 1250 } 1251 for (int i=0;i<valArray.length;i++) { 1252 if (valArray[i].ordinal() == ordinal) { 1253 return valArray[i]; 1254 } 1255 } 1256 return valArray[0]; 1257 } 1258 private static FMValues[] getArray() { 1259 if (valArray == null) { 1260 valArray = EnumSet.allOf(FMValues.class).toArray(new FMValues[0]); 1261 } 1262 return valArray; 1263 } 1264 1265 public static int getHintVal(Object hint) { 1266 getArray(); 1267 for (int i=0;i<valArray.length;i++) { 1268 if (valArray[i].getHint() == hint) { 1269 return i; 1270 } 1271 } 1272 return 0; 1273 } 1274 } 1275 1276 enum AAValues { 1277 AADEFAULT ("DEFAULT", VALUE_TEXT_ANTIALIAS_DEFAULT), 1278 AAOFF ("OFF", VALUE_TEXT_ANTIALIAS_OFF), 1279 AAON ("ON", VALUE_TEXT_ANTIALIAS_ON), 1280 AAGASP ("GASP", VALUE_TEXT_ANTIALIAS_GASP), 1281 AALCDHRGB ("LCD_HRGB", VALUE_TEXT_ANTIALIAS_LCD_HRGB), 1282 AALCDHBGR ("LCD_HBGR", VALUE_TEXT_ANTIALIAS_LCD_HBGR), 1283 AALCDVRGB ("LCD_VRGB", VALUE_TEXT_ANTIALIAS_LCD_VRGB), 1284 AALCDVBGR ("LCD_VBGR", VALUE_TEXT_ANTIALIAS_LCD_VBGR); 1285 1286 private String name; 1287 private Object hint; 1288 1289 private static AAValues[] valArray; 1290 1291 AAValues(String s, Object o) { 1292 name = s; 1293 hint = o; 1294 } 1295 1296 public String toString() { 1297 return name; 1298 } 1299 1300 public Object getHint() { 1301 return hint; 1302 } 1303 1304 public static boolean isLCDMode(Object o) { 1305 return (o instanceof AAValues && 1306 ((AAValues)o).ordinal() >= AALCDHRGB.ordinal()); 1307 } 1308 1309 public static Object getValue(int ordinal) { 1310 if (valArray == null) { 1311 valArray = EnumSet.allOf(AAValues.class).toArray(new AAValues[0]); 1312 } 1313 for (int i=0;i<valArray.length;i++) { 1314 if (valArray[i].ordinal() == ordinal) { 1315 return valArray[i]; 1316 } 1317 } 1318 return valArray[0]; 1319 } 1320 1321 private static AAValues[] getArray() { 1322 if (valArray == null) { 1323 Object [] oa = EnumSet.allOf(AAValues.class).toArray(new AAValues[0]); 1324 valArray = EnumSet.allOf(AAValues.class).toArray(new AAValues[0]); 1325 } 1326 return valArray; 1327 } 1328 1329 public static int getHintVal(Object hint) { 1330 getArray(); 1331 for (int i=0;i<valArray.length;i++) { 1332 if (valArray[i].getHint() == hint) { 1333 return i; 1334 } 1335 } 1336 return 0; 1337 } 1338 1339 } 1340 1341 private static Integer defaultContrast; 1342 static Integer getDefaultLCDContrast() { 1343 if (defaultContrast == null) { 1344 GraphicsConfiguration gc = 1345 GraphicsEnvironment.getLocalGraphicsEnvironment(). 1346 getDefaultScreenDevice().getDefaultConfiguration(); 1347 Graphics2D g2d = 1348 (Graphics2D)(gc.createCompatibleImage(1,1).getGraphics()); 1349 defaultContrast = (Integer) 1350 g2d.getRenderingHint(RenderingHints.KEY_TEXT_LCD_CONTRAST); 1351 } 1352 return defaultContrast; 1353 } 1354 }