1 /* 2 * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /** 25 * @test 26 * @bug 6425068 7157659 8132890 27 * @summary Confirm that text prints where we expect to the length we expect. 28 * @run main/manual=yesno PrintTextTest 29 */ 30 31 import java.awt.*; 32 import java.awt.event.*; 33 import java.text.*; 34 import java.util.*; 35 import java.awt.font.*; 36 import java.awt.geom.*; 37 import java.awt.print.*; 38 import javax.swing.*; 39 40 public class PrintTextTest extends Component implements Printable { 41 42 static int preferredSize; 43 Font textFont; 44 AffineTransform gxTx; 45 String page; 46 boolean useFM; 47 main(String args[])48 public static void main(String args[]) { 49 String[] instructions = 50 { 51 "This tests that printed text renders similarly to on-screen", 52 "under a variety of APIs and graphics and font transforms", 53 "Print to your preferred printer. Collect the output.", 54 "Refer to the onscreen buttons to cycle through the on-screen", 55 "content", 56 "For each page, confirm that the printed content corresponds to", 57 "the on-screen rendering for that *same* page.", 58 "Some cases may look odd but its intentional. Verify", 59 "it looks the same on screen and on the printer.", 60 "Note that text does not scale linearly from screen to printer", 61 "so some differences are normal and not a bug.", 62 "The easiest way to spot real problems is to check that", 63 "any underlines are the same length as the underlined text", 64 "and that any rotations are the same in each case.", 65 "Note that each on-screen page is printed in both portrait", 66 "and landscape mode", 67 "So for example, Page 1/Portrait, and Page 1/Landscape when", 68 "rotated to view properly, should both match Page 1 on screen.", 69 }; 70 Sysout.createDialogWithInstructions(instructions); 71 72 73 PrinterJob pjob = PrinterJob.getPrinterJob(); 74 PageFormat portrait = pjob.defaultPage(); 75 portrait.setOrientation(PageFormat.PORTRAIT); 76 preferredSize = (int)portrait.getImageableWidth(); 77 78 PageFormat landscape = pjob.defaultPage(); 79 landscape.setOrientation(PageFormat.LANDSCAPE); 80 81 Book book = new Book(); 82 83 JTabbedPane p = new JTabbedPane(); 84 85 int page = 1; 86 Font font = new Font("Dialog", Font.PLAIN, 18); 87 String name = "Page " + new Integer(page++); 88 PrintTextTest ptt = new PrintTextTest(name, font, null, false); 89 p.add(name, ptt); 90 book.append(ptt, portrait); 91 book.append(ptt, landscape); 92 93 font = new Font("Dialog", Font.PLAIN, 18); 94 name = "Page " + new Integer(page++); 95 ptt = new PrintTextTest(name, font, null, true); 96 p.add(name, ptt); 97 book.append(ptt, portrait); 98 book.append(ptt, landscape); 99 100 font = new Font("Lucida Sans", Font.PLAIN, 18); 101 name = "Page " + new Integer(page++); 102 ptt = new PrintTextTest(name, font, null, false); 103 p.add(name, ptt); 104 book.append(ptt, portrait); 105 book.append(ptt, landscape); 106 107 font = new Font("Lucida Sans", Font.PLAIN, 18); 108 AffineTransform rotTx = AffineTransform.getRotateInstance(0.15); 109 rotTx.translate(60,0); 110 name = "Page " + new Integer(page++); 111 ptt = new PrintTextTest(name, font, rotTx, false); 112 p.add(name, ptt); 113 book.append(ptt, portrait); 114 book.append(ptt, landscape); 115 116 font = new Font("Dialog", Font.PLAIN, 18); 117 AffineTransform scaleTx = AffineTransform.getScaleInstance(1.25, 1.25); 118 name = "Page " + new Integer(page++); 119 ptt = new PrintTextTest(name, font, scaleTx, false); 120 p.add(name, ptt); 121 book.append(ptt, portrait); 122 book.append(ptt, landscape); 123 124 font = new Font("Dialog", Font.PLAIN, 18); 125 scaleTx = AffineTransform.getScaleInstance(-1.25, 1.25); 126 scaleTx.translate(-preferredSize/1.25, 0); 127 name = "Page " + new Integer(page++); 128 ptt = new PrintTextTest(name, font, scaleTx, false); 129 p.add(name, ptt); 130 book.append(ptt, portrait); 131 book.append(ptt, landscape); 132 133 font = new Font("Dialog", Font.PLAIN, 18); 134 scaleTx = AffineTransform.getScaleInstance(1.25, -1.25); 135 scaleTx.translate(0, -preferredSize/1.25); 136 name = "Page " + new Integer(page++); 137 ptt = new PrintTextTest(name, font, scaleTx, false); 138 p.add(name, ptt); 139 book.append(ptt, portrait); 140 book.append(ptt, landscape); 141 142 font = font.deriveFont(rotTx); 143 name = "Page " + new Integer(page++); 144 ptt = new PrintTextTest(name, font, null, false); 145 p.add(ptt, BorderLayout.CENTER); 146 p.add(name, ptt); 147 book.append(ptt, portrait); 148 book.append(ptt, landscape); 149 150 font = new Font("Monospaced", Font.PLAIN, 12); 151 name = "Page " + new Integer(page++); 152 ptt = new PrintTextTest(name, font, null, false); 153 p.add(ptt, BorderLayout.CENTER); 154 p.add(name, ptt); 155 book.append(ptt, portrait); 156 book.append(ptt, landscape); 157 158 Font xfont = font.deriveFont(AffineTransform.getScaleInstance(1.5, 1)); 159 name = "Page " + new Integer(page++); 160 ptt = new PrintTextTest(name, xfont, null, false); 161 p.add(ptt, BorderLayout.CENTER); 162 p.add(name, ptt); 163 book.append(ptt, portrait); 164 book.append(ptt, landscape); 165 166 Font yfont = font.deriveFont(AffineTransform.getScaleInstance(1, 1.5)); 167 name = "Page " + new Integer(page++); 168 ptt = new PrintTextTest(name, yfont, null, false); 169 p.add(ptt, BorderLayout.CENTER); 170 p.add(name, ptt); 171 book.append(ptt, portrait); 172 book.append(ptt, landscape); 173 174 if (System.getProperty("os.name").startsWith("Windows")) { 175 font = new Font("MS Gothic", Font.PLAIN, 12); 176 name = "Page " + new Integer(page++); 177 ptt = new PrintJAText(name, font, null, true); 178 p.add(ptt, BorderLayout.CENTER); 179 p.add(name, ptt); 180 book.append(ptt, portrait); 181 book.append(ptt, landscape); 182 183 font = new Font("MS Gothic", Font.PLAIN, 12); 184 name = "Page " + new Integer(page++); 185 rotTx = AffineTransform.getRotateInstance(0.15); 186 ptt = new PrintJAText(name, font, rotTx, true); 187 p.add(ptt, BorderLayout.CENTER); 188 p.add(name, ptt); 189 book.append(ptt, portrait); 190 book.append(ptt, landscape); 191 } 192 193 pjob.setPageable(book); 194 195 JFrame f = new JFrame(); 196 f.add(BorderLayout.CENTER, p); 197 f.addWindowListener(new WindowAdapter() { 198 public void windowClosing(WindowEvent e) {System.exit(0);} 199 }); 200 f.pack(); 201 f.show(); 202 203 try { 204 if (pjob.printDialog()) { 205 pjob.print(); 206 } 207 } catch (PrinterException e) { 208 throw new RuntimeException(e.getMessage()); 209 } 210 } 211 PrintTextTest(String page, Font font, AffineTransform gxTx, boolean fm)212 public PrintTextTest(String page, Font font, AffineTransform gxTx, 213 boolean fm) { 214 this.page = page; 215 textFont = font; 216 this.gxTx = gxTx; 217 this.useFM = fm; 218 setBackground(Color.white); 219 } 220 getIterator(String s)221 public static AttributedCharacterIterator getIterator(String s) { 222 return new AttributedString(s).getIterator(); 223 } 224 orient(PageFormat pf)225 static String orient(PageFormat pf) { 226 if (pf.getOrientation() == PageFormat.PORTRAIT) { 227 return "Portrait"; 228 } else { 229 return "Landscape"; 230 } 231 } 232 print(Graphics g, PageFormat pf, int pageIndex)233 public int print(Graphics g, PageFormat pf, int pageIndex) { 234 235 Graphics2D g2d = (Graphics2D)g; 236 g2d.translate(pf.getImageableX(), pf.getImageableY()); 237 g.drawString(page+" "+orient(pf),50,20); 238 g.translate(0, 25); 239 paint(g); 240 return PAGE_EXISTS; 241 } 242 getMinimumSize()243 public Dimension getMinimumSize() { 244 return getPreferredSize(); 245 } 246 getPreferredSize()247 public Dimension getPreferredSize() { 248 return new Dimension(preferredSize, preferredSize); 249 } 250 paint(Graphics g)251 public void paint(Graphics g) { 252 253 /* fill with white before any transformation is applied */ 254 g.setColor(Color.white); 255 g.fillRect(0, 0, getSize().width, getSize().height); 256 257 258 Graphics2D g2d = (Graphics2D) g; 259 if (gxTx != null) { 260 g2d.transform(gxTx); 261 } 262 if (useFM) { 263 g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 264 RenderingHints.VALUE_FRACTIONALMETRICS_ON); 265 } 266 267 g.setFont(textFont); 268 FontMetrics fm = g.getFontMetrics(); 269 270 String s; 271 int LS = 30; 272 int ix=10, iy=LS+10; 273 g.setColor(Color.black); 274 275 s = "drawString(String str, int x, int y)"; 276 g.drawString(s, ix, iy); 277 if (!textFont.isTransformed()) { 278 g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1); 279 } 280 281 iy += LS; 282 s = "drawString(AttributedCharacterIterator iterator, int x, int y)"; 283 g.drawString(getIterator(s), ix, iy); 284 285 iy += LS; 286 s = "\tdrawChars(\t\r\nchar[], int off, int len, int x, int y\t)"; 287 g.drawChars(s.toCharArray(), 0, s.length(), ix, iy); 288 if (!textFont.isTransformed()) { 289 g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1); 290 } 291 292 iy += LS; 293 s = "drawBytes(byte[], int off, int len, int x, int y)"; 294 byte data[] = new byte[s.length()]; 295 for (int i = 0; i < data.length; i++) { 296 data[i] = (byte) s.charAt(i); 297 } 298 g.drawBytes(data, 0, data.length, ix, iy); 299 300 Font f = g2d.getFont(); 301 FontRenderContext frc = g2d.getFontRenderContext(); 302 303 iy += LS; 304 s = "drawString(String s, float x, float y)"; 305 g2d.drawString(s, (float) ix, (float) iy); 306 if (!textFont.isTransformed()) { 307 g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1); 308 } 309 310 iy += LS; 311 s = "drawString(AttributedCharacterIterator iterator, "+ 312 "float x, float y)"; 313 g2d.drawString(getIterator(s), (float) ix, (float) iy); 314 315 iy += LS; 316 s = "drawGlyphVector(GlyphVector g, float x, float y)"; 317 GlyphVector gv = f.createGlyphVector(frc, s); 318 g2d.drawGlyphVector(gv, ix, iy); 319 Point2D adv = gv.getGlyphPosition(gv.getNumGlyphs()); 320 if (!textFont.isTransformed()) { 321 g.drawLine(ix, iy+1, ix+(int)adv.getX(), iy+1); 322 } 323 324 iy += LS; 325 s = "GlyphVector with position adjustments"; 326 327 gv = f.createGlyphVector(frc, s); 328 int ng = gv.getNumGlyphs(); 329 adv = gv.getGlyphPosition(ng); 330 for (int i=0; i<ng; i++) { 331 Point2D gp = gv.getGlyphPosition(i); 332 double gx = gp.getX(); 333 double gy = gp.getY(); 334 if (i % 2 == 0) { 335 gy+=5; 336 } else { 337 gy-=5; 338 } 339 gp.setLocation(gx, gy); 340 gv.setGlyphPosition(i, gp); 341 } 342 g2d.drawGlyphVector(gv, ix, iy); 343 if (!textFont.isTransformed()) { 344 g.drawLine(ix, iy+1, ix+(int)adv.getX(), iy+1); 345 } 346 347 iy +=LS; 348 s = "drawString: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End."; 349 g.drawString(s, ix, iy); 350 if (!textFont.isTransformed()) { 351 g.drawLine(ix, iy+1, ix+fm.stringWidth(s), iy+1); 352 } 353 354 iy += LS; 355 s = "TextLayout 1: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End."; 356 TextLayout tl = new TextLayout(s, new HashMap(), frc); 357 tl.draw(g2d, ix, iy); 358 359 iy += LS; 360 s = "TextLayout 2: \u0924\u094d\u0930 \u0915\u0948\u0930\u0947 End."; 361 tl = new TextLayout(s, f, frc); 362 tl.draw(g2d, ix, iy); 363 } 364 } 365 366 class PrintJAText extends PrintTextTest { 367 368 PrintJAText(String page, Font font, AffineTransform gxTx, boolean fm)369 public PrintJAText(String page, Font font, AffineTransform gxTx, 370 boolean fm) { 371 super(page, font, gxTx, fm); 372 } 373 374 private static final String TEXT = 375 "\u3042\u3044\u3046\u3048\u304a\u30a4\u30ed\u30cf" + 376 "\u30cb\u30db\u30d8\u30c8\u4e00\u4e01\u4e02\u4e05\uff08"; 377 378 paint(Graphics g)379 public void paint(Graphics g) { 380 381 /* fill with white before any transformation is applied */ 382 g.setColor(Color.white); 383 g.fillRect(0, 0, getSize().width, getSize().height); 384 385 386 Graphics2D g2d = (Graphics2D) g; 387 if (gxTx != null) { 388 g2d.transform(gxTx); 389 } 390 if (useFM) { 391 g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, 392 RenderingHints.VALUE_FRACTIONALMETRICS_ON); 393 } 394 395 String text = TEXT + TEXT + TEXT; 396 g.setColor(Color.black); 397 int y = 20; 398 float origSize = 7f; 399 for (int i=0;i<11;i++) { 400 float size = origSize+(i*0.1f); 401 g2d.translate(0, size+6); 402 Font f = textFont.deriveFont(size); 403 g2d.setFont(f); 404 FontMetrics fontMetrics = g2d.getFontMetrics(); 405 int stringWidth = fontMetrics.stringWidth(text); 406 g.drawLine(0, y+1, stringWidth, y+1); 407 g.drawString(text, 0, y); 408 y +=10; 409 } 410 } 411 } 412 413 class Sysout 414 { 415 private static TestDialog dialog; 416 createDialogWithInstructions( String[] instructions )417 public static void createDialogWithInstructions( String[] instructions ) 418 { 419 dialog = new TestDialog( new Frame(), "Instructions" ); 420 dialog.printInstructions( instructions ); 421 dialog.show(); 422 println( "Any messages for the tester will display here." ); 423 } 424 createDialog( )425 public static void createDialog( ) 426 { 427 dialog = new TestDialog( new Frame(), "Instructions" ); 428 String[] defInstr = { "Instructions will appear here. ", "" } ; 429 dialog.printInstructions( defInstr ); 430 dialog.show(); 431 println( "Any messages for the tester will display here." ); 432 } 433 434 printInstructions( String[] instructions )435 public static void printInstructions( String[] instructions ) 436 { 437 dialog.printInstructions( instructions ); 438 } 439 440 println( String messageIn )441 public static void println( String messageIn ) 442 { 443 dialog.displayMessage( messageIn ); 444 } 445 446 }// Sysout class 447 448 /** 449 This is part of the standard test machinery. It provides a place for the 450 test instructions to be displayed, and a place for interactive messages 451 to the user to be displayed. 452 To have the test instructions displayed, see Sysout. 453 To have a message to the user be displayed, see Sysout. 454 Do not call anything in this dialog directly. 455 */ 456 class TestDialog extends Dialog 457 { 458 459 TextArea instructionsText; 460 TextArea messageText; 461 int maxStringLength = 80; 462 463 //DO NOT call this directly, go through Sysout TestDialog( Frame frame, String name )464 public TestDialog( Frame frame, String name ) 465 { 466 super( frame, name ); 467 int scrollBoth = TextArea.SCROLLBARS_BOTH; 468 instructionsText = new TextArea( "", 20, maxStringLength, scrollBoth ); 469 add( "North", instructionsText ); 470 471 messageText = new TextArea( "", 5, maxStringLength, scrollBoth ); 472 add("South", messageText); 473 474 pack(); 475 476 show(); 477 }// TestDialog() 478 479 //DO NOT call this directly, go through Sysout printInstructions( String[] instructions )480 public void printInstructions( String[] instructions ) 481 { 482 //Clear out any current instructions 483 instructionsText.setText( "" ); 484 485 //Go down array of instruction strings 486 487 String printStr, remainingStr; 488 for( int i=0; i < instructions.length; i++ ) 489 { 490 //chop up each into pieces maxSringLength long 491 remainingStr = instructions[ i ]; 492 while( remainingStr.length() > 0 ) 493 { 494 //if longer than max then chop off first max chars to print 495 if( remainingStr.length() >= maxStringLength ) 496 { 497 //Try to chop on a word boundary 498 int posOfSpace = remainingStr. 499 lastIndexOf( ' ', maxStringLength - 1 ); 500 501 if( posOfSpace <= 0 ) posOfSpace = maxStringLength - 1; 502 503 printStr = remainingStr.substring( 0, posOfSpace + 1 ); 504 remainingStr = remainingStr.substring( posOfSpace + 1 ); 505 } 506 //else just print 507 else 508 { 509 printStr = remainingStr; 510 remainingStr = ""; 511 } 512 513 instructionsText.append( printStr + "\n" ); 514 515 }// while 516 517 }// for 518 519 }//printInstructions() 520 521 //DO NOT call this directly, go through Sysout displayMessage( String messageIn )522 public void displayMessage( String messageIn ) 523 { 524 messageText.append( messageIn + "\n" ); 525 } 526 527 }// TestDialog class 528