1 /* 2 * Copyright (c) 1996, 2011, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include "awt.h" 27 #include <math.h> 28 #include <windef.h> 29 #include <wtypes.h> 30 #include <winuser.h> 31 #include <commdlg.h> 32 #include <winspool.h> 33 34 #include "awt_Toolkit.h" 35 #include "awt_Component.h" 36 #include "awt_Dialog.h" 37 #include "awt_Font.h" 38 #include "awt_PrintDialog.h" 39 #include "awt_PrintControl.h" 40 #include "awt_Window.h" 41 #include "ComCtl32Util.h" 42 43 #include <sun_awt_windows_WPrinterJob.h> 44 #include <jlong_md.h> 45 #include <float.h> 46 47 #define DEBUG_PRINTING 0 48 49 /* Round 'num' to the nearest integer and return 50 * the result as a long. 51 */ 52 #define ROUND_TO_LONG(num) ((long) floor((num) + 0.5)) 53 54 /* Round 'num' to the nearest integer and return 55 * the result as an int. 56 */ 57 #define ROUND_TO_INT(num) ((int) floor((num) + 0.5)) 58 59 /************************************************************************ 60 * WPrintJob native methods 61 */ 62 63 extern "C" { 64 65 /*** Private Constants ***/ 66 67 static char *kJavaIntStr = "I"; 68 static char *kJavaLongStr = "J"; 69 70 /* 2D printing uses 3 byte BGR pixels in Raster printing */ 71 static int J2DRasterBPP = 3; 72 73 /* 74 * Class Names 75 */ 76 static const char *PRINTEREXCEPTION_STR = "java/awt/print/PrinterException"; 77 78 /* 79 * The following strings are the names of instance variables in WPrintJob2D. 80 */ 81 static const char *PRINTPAPERSIZE_STR = "mPrintPaperSize"; // The paper size 82 static const char *XRES_STR = "mPrintXRes"; // The x dpi. 83 static const char *YRES_STR = "mPrintYRes"; // The y dpi. 84 static const char *PHYSX_STR = "mPrintPhysX"; // pixel x of printable area 85 static const char *PHYSY_STR = "mPrintPhysY"; // pixel y of printable area 86 static const char *PHYSW_STR = "mPrintWidth"; // pixel wid of printable area 87 static const char *PHYSH_STR = "mPrintHeight"; // pixel hgt of printable area 88 static const char *PAGEW_STR = "mPageWidth"; // pixel wid of page 89 static const char *PAGEH_STR = "mPageHeight"; // pixel hgt of page 90 91 static const char *DRIVER_COPIES_STR = "driverDoesMultipleCopies"; 92 static const char *DRIVER_COLLATE_STR = "driverDoesCollation"; 93 static const char *USER_COLLATE_STR = "userRequestedCollation"; 94 static const char *NO_DEFAULTPRINTER_STR = "noDefaultPrinter"; 95 static const char *LANDSCAPE_270_STR = "landscapeRotates270"; 96 97 98 // public int java.awt.print.PrinterJob.getCopies() 99 100 static const char *GETCOPIES_STR = "getCopies"; 101 static const char *GETCOPIES_SIG = "()I"; 102 103 /* 104 * Methods and fields in awt.print.PageFormat. 105 */ 106 107 // public Paper getPaper() 108 static const char *GETPAPER_STR = "getPaper"; 109 static const char *GETPAPER_SIG = "()Ljava/awt/print/Paper;"; 110 111 // public void setPaper(Paper paper) 112 static const char *SETPAPER_STR = "setPaper"; 113 static const char *SETPAPER_SIG = "(Ljava/awt/print/Paper;)V"; 114 115 // public int getOrientation() 116 static const char *GETORIENT_STR = "getOrientation"; 117 static const char *GETORIENT_SIG = "()I"; 118 119 // public void setOrientation(int orientation) 120 static const char *SETORIENT_STR = "setOrientation"; 121 static const char *SETORIENT_SIG = "(I)V"; 122 123 static const int PAGEFORMAT_LANDSCAPE = 0; 124 static const int PAGEFORMAT_PORTRAIT = 1; 125 //static const int PAGEFORMAT_REVERSELANDSCAPE = 2; 126 127 // instance variables for PrintRequestAttribute settings 128 static const char *ATTSIDES_STR = "mAttSides"; 129 static const char *ATTCHROMATICITY_STR = "mAttChromaticity"; 130 static const char *ATTXRES_STR = "mAttXRes"; 131 static const char *ATTYRES_STR = "mAttYRes"; 132 static const char *ATTQUALITY_STR = "mAttQuality"; 133 static const char *ATTCOLLATE_STR = "mAttCollate"; 134 static const char *ATTCOPIES_STR = "mAttCopies"; 135 static const char *ATTMEDIASZNAME_STR = "mAttMediaSizeName"; 136 static const char *ATTMEDIATRAY_STR = "mAttMediaTray"; 137 138 /* 139 * Methods in awt.print.Paper. 140 */ 141 142 // public void setSize(double width, double height) 143 static const char *SETSIZE_STR = "setSize"; 144 static const char *SETSIZE_SIG = "(DD)V"; 145 146 // protected void setImageableArea(double x, double y, double width, 147 // double height) 148 static const char *SETIMAGEABLE_STR = "setImageableArea"; 149 static const char *SETIMAGEABLE_SIG = "(DDDD)V"; 150 151 // public double getWidth() 152 static const char *GETWIDTH_STR = "getWidth"; 153 static const char *GETWIDTH_SIG = "()D"; 154 155 // public double getHeight() 156 static const char *GETHEIGHT_STR = "getHeight"; 157 static const char *GETHEIGHT_SIG = "()D"; 158 159 // public double getImageableX() 160 static const char *GETIMG_X_STR = "getImageableX"; 161 static const char *GETIMG_X_SIG = "()D"; 162 163 // public double getImageableY() 164 static const char *GETIMG_Y_STR = "getImageableY"; 165 static const char *GETIMG_Y_SIG = "()D"; 166 167 // public double getImageableWidth() 168 static const char *GETIMG_W_STR = "getImageableWidth"; 169 static const char *GETIMG_W_SIG = "()D"; 170 171 // public double getImageableHeight() 172 static const char *GETIMG_H_STR = "getImageableHeight"; 173 static const char *GETIMG_H_SIG = "()D"; 174 175 /* Multiply a Window's MM_HIENGLISH value 176 * (1000th of an inch) by this number to 177 * get a value in 72nds of an inch. 178 */ 179 static const double HIENGLISH_TO_POINTS = (72.0 / 1000.0); 180 181 /* Multiply a Window's MM_HIMETRIC value 182 * (100ths of a millimeter) by this 183 * number to get a value in 72nds of an inch. 184 */ 185 static const double HIMETRIC_TO_POINTS = (72.0 / 2540.0); 186 187 /* Multiply a Window's MM_LOMETRIC value 188 * (10ths of a millimeter) by this 189 * number to get a value in 72nds of an inch. 190 */ 191 static const double LOMETRIC_TO_POINTS = (72.0 / 254.0); 192 193 /* Multiply a measurement in 1/72's of an inch by this 194 * value to convert it to Window's MM_HIENGLISH 195 * (1000th of an inch) units. 196 */ 197 static const double POINTS_TO_HIENGLISH = (1000.0 / 72.0); 198 199 /* Multiply a measurement in 1/72's of an inch by this 200 * value to convert it to Window's MM_HIMETRIC 201 * (100th of an millimeter) units. 202 */ 203 static const double POINTS_TO_HIMETRIC = (2540.0 / 72.0); 204 205 /* Multiply a measurement in 1/72's of an inch by this 206 * value to convert it to Window's MM_LOMETRIC 207 * (10th of an millimeter) units. 208 */ 209 static const double POINTS_TO_LOMETRIC = (254.0 / 72.0); 210 211 jfieldID AwtPrintDialog::pageID; 212 213 214 /*** Private Macros ***/ 215 216 /* A Page Setup paint hook passes a word describing the 217 orientation and type of page being displayed in the 218 dialog. These macros break the word down into meaningful 219 values. 220 */ 221 #define PRINTER_TYPE_MASK (0x0003) 222 #define PORTRAIT_MASK (0x0004) 223 #define ENVELOPE_MASK (0x0008) 224 225 #define IS_ENVELOPE(param) (((param) & ENVELOPE_MASK) != 0) 226 #define IS_PORTRAIT(param) (((param) & PORTRAIT_MASK) != 0) 227 228 /* If the Pagable does not know the number of pages in the document, 229 then we limit the print dialog to this number of pages. 230 */ 231 #define MAX_UNKNOWN_PAGES 9999 232 233 /* When making a font that is already at least bold, 234 * bolder then we increase the LOGFONT lfWeight field 235 * by this amount. 236 */ 237 #define EMBOLDEN_WEIGHT (100) 238 239 /* The lfWeight field of a GDI LOGFONT structure should not 240 * exceed this value. 241 */ 242 #define MAX_FONT_WEIGHT (1000) 243 244 /*** Private Variable Types ***/ 245 246 typedef struct { 247 jdouble x; 248 jdouble y; 249 jdouble width; 250 jdouble height; 251 } RectDouble; 252 253 /*** Private Prototypes ***/ 254 255 static UINT CALLBACK pageDlgHook(HWND hDlg, UINT msg, 256 WPARAM wParam, LPARAM lParam); 257 static void initPrinter(JNIEnv *env, jobject self); 258 static HDC getDefaultPrinterDC(JNIEnv *env, jobject printerJob); 259 static void pageFormatToSetup(JNIEnv *env, jobject job, jobject page, 260 PAGESETUPDLG *setup, HDC hDC); 261 static WORD getOrientationFromDevMode2(HGLOBAL hDevMode); 262 static WORD getOrientationFromDevMode(JNIEnv *env, jobject self); 263 static void setOrientationInDevMode(HGLOBAL hDevMode, jboolean isPortrait); 264 static void doPrintBand(JNIEnv *env, jboolean browserPrinting, 265 HDC printDC, jbyteArray imageArray, 266 jint x, jint y, jint width, jint height); 267 static int bitsToDevice(HDC printDC, jbyte *image, long destX, long destY, 268 long width, long height); 269 static void retrievePaperInfo(const PAGESETUPDLG *setup, POINT *paperSize, 270 RECT *margins, jint *orientation, 271 HDC hdc); 272 static jint getCopies(JNIEnv *env, jobject printerJob); 273 static jobject getPaper(JNIEnv *env, jobject page); 274 static void setPaper(JNIEnv *env, jobject page, jobject paper); 275 static jint getPageFormatOrientation(JNIEnv *env, jobject page); 276 static void setPageFormatOrientation(JNIEnv *env, jobject page, jint orient); 277 static void getPaperValues(JNIEnv *env, jobject paper, RectDouble *paperSize, 278 RectDouble *margins, BOOL widthAsMargin=TRUE); 279 static void setPaperValues(JNIEnv *env, jobject paper, const POINT *paperSize, 280 const RECT *margins, int units); 281 static long convertFromPoints(double value, int units); 282 static double convertToPoints(long value, int units); 283 void setCapabilities(JNIEnv *env, jobject self, HDC printDC); 284 static inline WORD getPrintPaperSize(JNIEnv *env, jobject self); 285 static inline void setPrintPaperSize(JNIEnv *env, jobject self, WORD sz); 286 static jint getIntField(JNIEnv *env, jobject self, const char *fieldName); 287 static jlong getLongField(JNIEnv *env, jobject self, const char *fieldName); 288 static void setIntField(JNIEnv *env, jobject self, 289 const char *fieldName, jint value); 290 static void setLongField(JNIEnv *env, jobject self, 291 const char *fieldName, jlong value); 292 static jfieldID getIdOfIntField(JNIEnv *env, jobject self, 293 const char *fieldName); 294 static jfieldID getIdOfLongField(JNIEnv *env, jobject self, 295 const char *fieldName); 296 static void setBooleanField(JNIEnv *env, jobject self, 297 const char *fieldName, jboolean value); 298 299 static jbyte *findNonWhite(jbyte *image, long sy, long width, long height, 300 long scanLineStride, long *numLinesP); 301 static jbyte *findWhite(jbyte *image, long sy, long width, long height, 302 long scanLineStride, long *numLines); 303 static void dumpDevMode(HGLOBAL hDevMode); 304 static void dumpPrinterCaps(HANDLE hDevNames); 305 static void throwPrinterException(JNIEnv *env, DWORD err); 306 static void matchPaperSize(HDC printDC, HGLOBAL hDevMode, HGLOBAL hDevNames, 307 double origWid, double origHgt, 308 double* newHgt, double *newWid, 309 WORD* paperSize); 310 311 /***********************************************************************/ 312 313 static jboolean jFontToWFontW(JNIEnv *env, HDC printDC, jstring fontName, 314 jfloat fontSize, jboolean isBold, jboolean isItalic, 315 jint rotation, jfloat awScale); 316 static jboolean jFontToWFontA(JNIEnv *env, HDC printDC, jstring fontName, 317 jfloat fontSize, jboolean isBold, jboolean isItalic, 318 jint rotation, jfloat awScale); 319 320 static int CALLBACK fontEnumProcW(ENUMLOGFONTEXW *lpelfe, 321 NEWTEXTMETRICEX *lpntme, 322 int FontType, 323 LPARAM lParam); 324 static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA *logfont, 325 NEWTEXTMETRICEX *lpntme, 326 int FontType, 327 LPARAM lParam); 328 329 static int embolden(int currentWeight); 330 static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin); 331 332 /************************************************************************ 333 * WPageDialog native methods 334 */ 335 JNIEXPORT void JNICALL 336 Java_sun_awt_windows_WPageDialog_initIDs(JNIEnv *env, jclass cls) 337 { 338 TRY; 339 340 AwtPrintDialog::pageID = 341 env->GetFieldID(cls, "page", "Ljava/awt/print/PageFormat;"); 342 343 DASSERT(AwtPrintDialog::pageID != NULL); 344 345 CATCH_BAD_ALLOC; 346 } 347 348 /************************************************************************ 349 * WPageDialogPeer native methods 350 */ 351 352 /* 353 * Class: sun_awt_windows_WPageDialogPeer 354 * Method: show 355 * Signature: ()Z 356 * 357 */ 358 359 JNIEXPORT jboolean JNICALL 360 Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer) 361 { 362 TRY; 363 364 // as peer object is used later on another thread, create global ref here 365 jobject peerGlobalRef = env->NewGlobalRef(peer); 366 DASSERT(peerGlobalRef != NULL); 367 jobject target = env->GetObjectField(peerGlobalRef, AwtObject::targetID); 368 369 jobject parent = env->GetObjectField(peerGlobalRef, AwtPrintDialog::parentID); 370 371 jobject page = env->GetObjectField(target, AwtPrintDialog::pageID); 372 DASSERT(page != NULL); 373 374 jobject self = env->GetObjectField(target, AwtPrintDialog::controlID); 375 DASSERT(self != NULL); 376 377 AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL; 378 HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL; 379 380 jboolean doIt = JNI_FALSE; // Assume the user will cancel the dialog. 381 PAGESETUPDLG setup; 382 memset(&setup, 0, sizeof(setup)); 383 384 setup.lStructSize = sizeof(setup); 385 386 /* 387 Fix for 6488834. 388 To disable Win32 native parent modality we have to set 389 hwndOwner field to either NULL or some hidden window. For 390 parentless dialogs we use NULL to show them in the taskbar, 391 and for all other dialogs AwtToolkit's HWND is used. 392 */ 393 if (awtParent != NULL) 394 { 395 setup.hwndOwner = AwtToolkit::GetInstance().GetHWnd(); 396 } 397 else 398 { 399 setup.hwndOwner = NULL; 400 } 401 402 setup.hDevMode = NULL; 403 setup.hDevNames = NULL; 404 setup.Flags = PSD_RETURNDEFAULT | PSD_DEFAULTMINMARGINS; 405 // setup.ptPaperSize = 406 // setup.rtMinMargin = 407 // setup.rtMargin = 408 setup.hInstance = NULL; 409 setup.lCustData = (LPARAM)peerGlobalRef; 410 setup.lpfnPageSetupHook = reinterpret_cast<LPPAGESETUPHOOK>(pageDlgHook); 411 setup.lpfnPagePaintHook = NULL; 412 setup.lpPageSetupTemplateName = NULL; 413 setup.hPageSetupTemplate = NULL; 414 415 416 /* Because the return default flag is set, this first call 417 * will not display the dialog but will return default values, inc 418 * including hDevMode, hDevName, ptPaperSize, and rtMargin values. 419 * We can use the devmode to set the orientation of the page 420 * and the size of the page. 421 * The units used by the user is also needed. 422 */ 423 if (AwtPrintControl::getPrintHDMode(env, self) == NULL || 424 AwtPrintControl::getPrintHDName(env,self) == NULL) { 425 (void)::PageSetupDlg(&setup); 426 /* check if hDevMode and hDevNames are set. 427 * If both are null, then there is no default printer. 428 */ 429 if ((setup.hDevMode == NULL) && (setup.hDevNames == NULL)) { 430 return JNI_FALSE; 431 } 432 } else { 433 int measure = PSD_INTHOUSANDTHSOFINCHES; 434 int sz = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IMEASURE, NULL, 0); 435 if (sz > 0) { 436 LPTSTR str = (LPTSTR)safe_Malloc(sizeof(TCHAR) * sz); 437 if (str != NULL) { 438 sz = GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_IMEASURE, str, sz); 439 if (sz > 0) { 440 if (_tcscmp(TEXT("0"), str) == 0) { 441 measure = PSD_INHUNDREDTHSOFMILLIMETERS; 442 } 443 } 444 free((LPTSTR)str); 445 } 446 } 447 setup.Flags |= measure; 448 setup.hDevMode = AwtPrintControl::getPrintHDMode(env, self); 449 setup.hDevNames = AwtPrintControl::getPrintHDName(env, self); 450 } 451 /* Move page size and orientation from the PageFormat object 452 * into the Windows setup structure so that the format can 453 * be displayed in the dialog. 454 */ 455 pageFormatToSetup(env, self, page, &setup, 456 AwtPrintControl::getPrintDC(env, self)); 457 458 setup.lpfnPageSetupHook = reinterpret_cast<LPPAGESETUPHOOK>(pageDlgHook); 459 setup.Flags = PSD_ENABLEPAGESETUPHOOK | PSD_MARGINS; 460 461 AwtDialog::CheckInstallModalHook(); 462 463 BOOL ret = ::PageSetupDlg(&setup); 464 if (ret) { 465 466 jobject paper = getPaper(env, page); 467 468 int units = setup.Flags & PSD_INTHOUSANDTHSOFINCHES ? 469 MM_HIENGLISH : 470 MM_HIMETRIC; 471 POINT paperSize; 472 RECT margins; 473 jint orientation; 474 475 /* The printer may have been changed, and we track that change, 476 * but then need to get a new DC for the current printer so that 477 * we validate the paper size correctly 478 */ 479 if (setup.hDevNames != NULL) { 480 DEVNAMES* names = (DEVNAMES*)::GlobalLock(setup.hDevNames); 481 if (names != NULL) { 482 LPTSTR printer = (LPTSTR)names+names->wDeviceOffset; 483 SAVE_CONTROLWORD 484 HDC newDC = ::CreateDC(TEXT("WINSPOOL"), printer, NULL, NULL); 485 RESTORE_CONTROLWORD 486 if (newDC != NULL) { 487 HDC oldDC = AwtPrintControl::getPrintDC(env, self); 488 if (oldDC != NULL) { 489 ::DeleteDC(oldDC); 490 } 491 } 492 AwtPrintControl::setPrintDC(env, self, newDC); 493 } 494 ::GlobalUnlock(setup.hDevNames); 495 } 496 497 /* Get the Windows paper and margins description. 498 */ 499 retrievePaperInfo(&setup, &paperSize, &margins, &orientation, 500 AwtPrintControl::getPrintDC(env, self)); 501 502 /* Convert the Windows' paper and margins description 503 * and place them into a Paper instance. 504 */ 505 setPaperValues(env, paper, &paperSize, &margins, units); 506 507 /* Put the updated Paper instance and the orientation into 508 * the PageFormat. 509 */ 510 setPaper(env, page, paper); 511 512 setPageFormatOrientation(env, page, orientation); 513 514 if (setup.hDevMode != NULL) { 515 DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup.hDevMode); 516 if (devmode != NULL) { 517 if (devmode->dmFields & DM_PAPERSIZE) { 518 setPrintPaperSize(env, self, devmode->dmPaperSize); 519 } 520 } 521 ::GlobalUnlock(setup.hDevMode); 522 } 523 doIt = JNI_TRUE; 524 } 525 526 DASSERT(env->GetLongField(peer, AwtComponent::hwndID) == 0L); 527 528 AwtDialog::CheckUninstallModalHook(); 529 530 AwtDialog::ModalActivateNextWindow(NULL, target, peer); 531 532 HGLOBAL oldG = AwtPrintControl::getPrintHDMode(env, self); 533 if (setup.hDevMode != oldG) { 534 AwtPrintControl::setPrintHDMode(env, self, setup.hDevMode); 535 } 536 537 oldG = AwtPrintControl::getPrintHDName(env, self); 538 if (setup.hDevNames != oldG) { 539 AwtPrintControl::setPrintHDName(env, self, setup.hDevNames); 540 } 541 542 env->DeleteGlobalRef(peerGlobalRef); 543 if (target != NULL) { 544 env->DeleteLocalRef(target); 545 } 546 if (parent != NULL) { 547 env->DeleteLocalRef(parent); 548 } 549 env->DeleteLocalRef(page); 550 env->DeleteLocalRef(self); 551 552 return doIt; 553 554 CATCH_BAD_ALLOC_RET(0); 555 } 556 557 /************************************************************************ 558 * WPrinterJob native methods 559 */ 560 561 /* 562 * Class: sun_awt_windows_WPrinterJob 563 * Method: setCopies 564 * Signature: (I)V 565 */ 566 JNIEXPORT void JNICALL 567 Java_sun_awt_windows_WPrinterJob_setNativeCopies(JNIEnv *env, jobject self, 568 jint copies) { 569 HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, self); 570 if (hDevMode != NULL) { 571 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 572 if (devmode != NULL) { 573 short nCopies = (copies < (jint)SHRT_MAX) 574 ? static_cast<short>(copies) : SHRT_MAX; 575 devmode->dmCopies = nCopies; 576 devmode->dmFields |= DM_COPIES; 577 } 578 ::GlobalUnlock(hDevMode); 579 } 580 } 581 582 /* 583 * Class: sun_awt_windows_WPrinterJob 584 * Method: getDefaultPage 585 * Signature: (Ljava/awt/print/PageFormat;)V 586 */ 587 JNIEXPORT void JNICALL 588 Java_sun_awt_windows_WPrinterJob_getDefaultPage(JNIEnv *env, jobject self, 589 jobject page) { 590 591 TRY; 592 593 // devnames and dc are initialized at setting of Print Service, 594 // through print dialog or start of printing 595 // None of those may have happened yet, so call initPrinter() 596 initPrinter(env, self); 597 HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, self); 598 HDC hdc = AwtPrintControl::getPrintDC(env, self); 599 600 if ((hDevNames == NULL) || (hdc == NULL)) { 601 return; 602 } 603 604 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); 605 606 if (devnames != NULL) { 607 608 LPTSTR lpdevnames = (LPTSTR)devnames; 609 LPTSTR printerName = _tcsdup(lpdevnames+devnames->wDeviceOffset); 610 611 HANDLE hPrinter = NULL; 612 LPDEVMODE pDevMode; 613 614 /* Start by opening the printer */ 615 if (!::OpenPrinter(printerName, &hPrinter, NULL)) { 616 if (hPrinter != NULL) { 617 ::ClosePrinter(hPrinter); 618 } 619 ::GlobalUnlock(hDevNames); 620 free ((LPTSTR) printerName); 621 return; 622 } 623 624 if (!AwtPrintControl::getDevmode(hPrinter, printerName, &pDevMode)) { 625 /* if failure, cleanup and return failure */ 626 if (pDevMode != NULL) { 627 ::GlobalFree(pDevMode); 628 } 629 ::ClosePrinter(hPrinter); 630 ::GlobalUnlock(hDevNames); 631 free ((LPTSTR) printerName); 632 return ; 633 } 634 635 if ((pDevMode->dmFields & DM_PAPERSIZE) || 636 (pDevMode->dmFields & DM_PAPERWIDTH) || 637 (pDevMode->dmFields & DM_PAPERLENGTH)) { 638 POINT paperSize; 639 RECT margins; 640 jint orientation = PAGEFORMAT_PORTRAIT; 641 642 if (hdc != NULL) { 643 644 int units = MM_HIENGLISH; 645 int sz = GetLocaleInfo(LOCALE_USER_DEFAULT, 646 LOCALE_IMEASURE, NULL, 0); 647 if (sz > 0) { 648 LPTSTR str = (LPTSTR)safe_Malloc(sizeof(TCHAR) * sz); 649 if (str != NULL) { 650 sz = GetLocaleInfo(LOCALE_USER_DEFAULT, 651 LOCALE_IMEASURE, str, sz); 652 if (sz > 0) { 653 if (_tcscmp(TEXT("0"), str) == 0) { 654 units = MM_HIMETRIC; 655 } 656 } 657 free((LPTSTR)str); 658 } 659 } 660 661 int width = ::GetDeviceCaps(hdc, PHYSICALWIDTH); 662 int height = ::GetDeviceCaps(hdc, PHYSICALHEIGHT); 663 int resx = ::GetDeviceCaps(hdc, LOGPIXELSX); 664 int resy = ::GetDeviceCaps(hdc, LOGPIXELSY); 665 666 double w = (double)width/resx; 667 double h = (double)height/resy; 668 669 paperSize.x = convertFromPoints(w*72, units); 670 paperSize.y = convertFromPoints(h*72, units); 671 672 // set margins to 1" 673 margins.left = convertFromPoints(72, units); 674 margins.top = convertFromPoints(72, units);; 675 margins.right = convertFromPoints(72, units);; 676 margins.bottom = convertFromPoints(72, units);; 677 678 jobject paper = getPaper(env, page); 679 setPaperValues(env, paper, &paperSize, &margins, units); 680 setPaper(env, page, paper); 681 682 if ((pDevMode->dmFields & DM_ORIENTATION) && 683 (pDevMode->dmOrientation == DMORIENT_LANDSCAPE)) { 684 orientation = PAGEFORMAT_LANDSCAPE; 685 } 686 setPageFormatOrientation(env, page, orientation); 687 } 688 689 } else { 690 setBooleanField(env, self, NO_DEFAULTPRINTER_STR, (jint)JNI_TRUE); 691 } 692 ::GlobalFree(pDevMode); 693 694 free ((LPTSTR) printerName); 695 696 ::ClosePrinter(hPrinter); 697 698 } 699 ::GlobalUnlock(hDevNames); 700 701 CATCH_BAD_ALLOC; 702 703 } 704 705 /* 706 * Class: sun_awt_windows_WPrinterJob 707 * Method: validatePaper 708 * Signature: (Ljava/awt/print/Paper;Ljava/awt/print/Paper;)V 709 * 710 * Query the current or default printer to find all paper sizes it 711 * supports and find the closest matching to the origPaper. 712 * For the matching size, validate the margins and printable area 713 * against the printer's capabilities. 714 */ 715 JNIEXPORT void JNICALL 716 Java_sun_awt_windows_WPrinterJob_validatePaper(JNIEnv *env, jobject self, 717 jobject origPaper, jobject newPaper) { 718 TRY; 719 720 /* If the print dialog has been displayed or a DC has otherwise 721 * been created, use that. Else get a DC for the default printer 722 * which we discard before returning. 723 */ 724 725 HDC printDC = AwtPrintControl::getPrintDC(env, self); 726 HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, self); 727 HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, self); 728 BOOL privateDC = FALSE; 729 730 if (printDC == NULL) { 731 PRINTDLG pd; 732 memset(&pd, 0, sizeof(PRINTDLG)); 733 pd.lStructSize = sizeof(PRINTDLG); 734 pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC; 735 736 if (::PrintDlg(&pd)) { 737 printDC = pd.hDC; 738 hDevMode = pd.hDevMode; 739 hDevNames = pd.hDevNames; 740 privateDC = TRUE; 741 } 742 } 743 744 if (printDC == NULL) { 745 return; 746 } 747 748 /* We try to mitigate the effects of floating point rounding errors 749 * by only setting a value if it would differ from the value in the 750 * target by at least 0.10 points = 1/720 inches. 751 * eg if the values present in the target are close to the calculated 752 * values then we accept the target. 753 */ 754 const double epsilon = 0.10; 755 756 jdouble paperWidth, paperHeight; 757 WORD dmPaperSize = getPrintPaperSize(env, self); 758 759 double ix, iy, iw, ih, pw, ph; 760 761 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 762 jmethodID getID; 763 764 jclass paperClass = env->GetObjectClass(origPaper); 765 getID = env->GetMethodID(paperClass, GETWIDTH_STR, GETWIDTH_SIG); 766 pw = env->CallDoubleMethod(origPaper, getID); 767 getID = env->GetMethodID(paperClass, GETHEIGHT_STR, GETHEIGHT_SIG); 768 ph = env->CallDoubleMethod(origPaper, getID); 769 getID = env->GetMethodID(paperClass, GETIMG_X_STR, GETIMG_X_SIG); 770 ix = env->CallDoubleMethod(origPaper, getID); 771 getID = env->GetMethodID(paperClass, GETIMG_Y_STR, GETIMG_Y_SIG); 772 iy = env->CallDoubleMethod(origPaper, getID); 773 getID = env->GetMethodID(paperClass, GETIMG_W_STR, GETIMG_W_SIG); 774 iw = env->CallDoubleMethod(origPaper, getID); 775 getID = env->GetMethodID(paperClass, GETIMG_H_STR, GETIMG_H_SIG); 776 ih = env->CallDoubleMethod(origPaper, getID); 777 778 matchPaperSize(printDC, hDevMode, hDevNames, pw, ph, 779 &paperWidth, &paperHeight, &dmPaperSize); 780 781 /* Validate margins and imageable area */ 782 783 // pixels per inch in x and y direction 784 jint xPixelRes = GetDeviceCaps(printDC, LOGPIXELSX); 785 jint yPixelRes = GetDeviceCaps(printDC, LOGPIXELSY); 786 787 // x & y coord of printable area in pixels 788 jint xPixelOrg = GetDeviceCaps(printDC, PHYSICALOFFSETX); 789 jint yPixelOrg = GetDeviceCaps(printDC, PHYSICALOFFSETY); 790 791 // width & height of printable area in pixels 792 jint imgPixelWid = GetDeviceCaps(printDC, HORZRES); 793 jint imgPixelHgt = GetDeviceCaps(printDC, VERTRES); 794 795 // if the values were obtained from a rotated device, swap. 796 if (getOrientationFromDevMode2(hDevMode) == DMORIENT_LANDSCAPE) { 797 jint tmp; 798 tmp = xPixelRes; 799 xPixelRes = yPixelRes; 800 yPixelRes = tmp; 801 802 tmp = xPixelOrg; 803 xPixelOrg = yPixelOrg; 804 yPixelOrg = tmp; 805 806 tmp = imgPixelWid; 807 imgPixelWid = imgPixelHgt; 808 imgPixelHgt = tmp; 809 } 810 811 // page imageable area in 1/72" 812 jdouble imgX = (jdouble)((xPixelOrg * 72)/(jdouble)xPixelRes); 813 jdouble imgY = (jdouble)((yPixelOrg * 72)/(jdouble)yPixelRes); 814 jdouble imgWid = (jdouble)((imgPixelWid * 72)/(jdouble)xPixelRes); 815 jdouble imgHgt = (jdouble)((imgPixelHgt * 72)/(jdouble)yPixelRes); 816 817 /* Check each of the individual values is within range. 818 * Then make sure imageable area is placed within imageable area. 819 * Allow for a small floating point error in the comparisons 820 */ 821 822 if (ix < 0.0 ) { 823 ix = 0.0; 824 } 825 if (iy < 0.0 ) { 826 iy = 0.0; 827 } 828 if (iw < 0.0) { 829 iw = 0.0; 830 } 831 if (ih < 0.0) { 832 ih = 0.0; 833 } 834 if ((ix + epsilon) < imgX) { 835 ix = imgX; 836 } 837 if ((iy + epsilon) < imgY) { 838 iy = imgY; 839 } 840 if (iw + epsilon > imgWid) { 841 iw = imgWid; 842 } 843 if (ih + epsilon > imgHgt) { 844 ih = imgHgt; 845 } 846 if ((ix + iw + epsilon) > (imgX+imgWid)) { 847 ix = (imgX+imgWid) - iw; 848 } 849 if ((iy + ih + epsilon) > (imgY+imgHgt)) { 850 iy = (imgY+imgHgt) - ih; 851 } 852 853 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 854 855 jmethodID setSizeID = env->GetMethodID(paperClass, 856 SETSIZE_STR, SETSIZE_SIG); 857 jmethodID setImageableID = env->GetMethodID(paperClass, 858 SETIMAGEABLE_STR, SETIMAGEABLE_SIG); 859 860 env->CallVoidMethod(newPaper, setSizeID, paperWidth, paperHeight); 861 env->CallVoidMethod(newPaper, setImageableID, ix, iy, iw, ih); 862 863 /* Free any resources allocated */ 864 if (privateDC == TRUE) { 865 if (printDC != NULL) { 866 /* In this case we know that this DC has no GDI objects to free */ 867 ::DeleteDC(printDC); 868 } 869 if (hDevMode != NULL) { 870 ::GlobalFree(hDevMode); 871 } 872 if (hDevNames != NULL) { 873 ::GlobalFree(hDevNames); 874 } 875 } 876 877 CATCH_BAD_ALLOC; 878 } 879 880 static void initPrinter(JNIEnv *env, jobject self) { 881 882 HDC printDC = AwtPrintControl::getPrintDC(env, self); 883 884 /* 885 * The print device context will be NULL if the 886 * user never okayed a print dialog. This 887 * will happen most often when the java application 888 * decides not to present a print dialog to the user. 889 * We create a device context for the default printer. 890 */ 891 if (printDC == NULL) { 892 printDC = getDefaultPrinterDC(env, self); 893 if (printDC){ 894 AwtPrintControl::setPrintDC(env, self, printDC); 895 setCapabilities(env, self, printDC); 896 } 897 } 898 } 899 900 901 /* 902 * Class: sun_awt_windows_WPrinterJob 903 * Method: initPrinter 904 * Signature: ()V 905 */ 906 JNIEXPORT void JNICALL 907 Java_sun_awt_windows_WPrinterJob_initPrinter(JNIEnv *env, jobject self) { 908 TRY; 909 910 initPrinter(env, self); 911 912 // check for collation 913 HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, self); 914 if (hDevNames != NULL) { 915 DWORD dmFields; 916 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); 917 918 if (devnames != NULL) { 919 LPTSTR lpdevnames = (LPTSTR)devnames; 920 LPTSTR printername = lpdevnames+devnames->wDeviceOffset; 921 LPTSTR port = lpdevnames+devnames->wOutputOffset; 922 923 SAVE_CONTROLWORD 924 dmFields = ::DeviceCapabilities(printername, port, 925 DC_FIELDS, NULL, NULL); 926 int devLandRotation = (int)DeviceCapabilities(printername, port, 927 DC_ORIENTATION, NULL, NULL); 928 RESTORE_CONTROLWORD 929 ::GlobalUnlock(devnames); 930 931 if (devLandRotation == 270) { 932 setBooleanField(env, self, LANDSCAPE_270_STR, JNI_TRUE); 933 } else { 934 setBooleanField(env, self, LANDSCAPE_270_STR, JNI_FALSE); 935 } 936 } 937 938 if (dmFields & DM_COLLATE) { 939 setBooleanField(env, self, DRIVER_COLLATE_STR, JNI_TRUE); 940 } else { 941 setBooleanField(env, self, DRIVER_COLLATE_STR, JNI_FALSE); 942 } 943 944 } 945 946 CATCH_BAD_ALLOC; 947 } 948 949 950 static bool setPrintReqAttribute(JNIEnv *env, jobject self, DEVMODE* devmode) { 951 952 /* The xRes/yRes fields are only initialised if there is a resolution 953 * attribute. Otherwise they both will be zero, in which case default 954 * resolution should be fine. Consider calling getXRes()/getResY() 955 * rather than accessing the fields directly 956 */ 957 int xRes=getIntField(env, self, ATTXRES_STR); 958 int yRes=getIntField(env, self, ATTYRES_STR); 959 int quality=getIntField(env, self, ATTQUALITY_STR); 960 int printColor = getIntField(env, self, ATTCHROMATICITY_STR); 961 int sides = getIntField(env, self, ATTSIDES_STR); 962 int collate = getIntField(env, self, ATTCOLLATE_STR); 963 int copies = 1; 964 jclass myClass = env->GetObjectClass(self); 965 // There may be cases when driver reports it cannot handle 966 // multiple copies although it actually can . So this modification 967 // handles that, to make sure that we report copies = 1 because 968 // we already emulated multiple copies. 969 jfieldID fieldId = env->GetFieldID(myClass, DRIVER_COPIES_STR, "Z"); 970 if (env->GetBooleanField(self, fieldId)) { 971 copies = getIntField(env, self, ATTCOPIES_STR); 972 } // else "driverDoesMultipleCopies" is false, copies should be 1 (default) 973 int mediatray = getIntField(env, self, ATTMEDIATRAY_STR); 974 int mediaszname = getIntField(env, self, ATTMEDIASZNAME_STR); 975 bool ret = true; 976 977 if (quality && quality < 0) { 978 if (quality != devmode->dmPrintQuality) { 979 devmode->dmPrintQuality = quality; 980 devmode->dmFields |= DM_PRINTQUALITY; 981 // ret of "false" means that setCapabilities needs to be called 982 ret = false; 983 } 984 } else { 985 /* If we didn't set quality, maybe we have resolution settings. */ 986 if (xRes && (xRes != devmode->dmPrintQuality)) { 987 devmode->dmPrintQuality = xRes; 988 devmode->dmFields |= DM_PRINTQUALITY; 989 } 990 991 if (yRes && (yRes != devmode->dmYResolution)) { 992 devmode->dmYResolution = yRes; 993 devmode->dmFields |= DM_YRESOLUTION; 994 } 995 } 996 997 if (printColor && (printColor != devmode->dmColor)) { 998 devmode->dmColor = printColor; 999 devmode->dmFields |= DM_COLOR; 1000 } 1001 1002 if (sides && (sides != devmode->dmDuplex)) { 1003 devmode->dmDuplex = sides; 1004 devmode->dmFields |= DM_DUPLEX; 1005 } 1006 1007 if ((collate != -1) && (collate != devmode->dmCollate)) { 1008 devmode->dmCollate = collate; 1009 devmode->dmFields |= DM_COLLATE; 1010 } 1011 1012 if (copies && (copies != devmode->dmCopies)) { 1013 devmode->dmCopies = copies; 1014 devmode->dmFields |= DM_COPIES; 1015 } 1016 1017 if (mediatray && (mediatray != devmode->dmDefaultSource)) { 1018 devmode->dmDefaultSource = mediatray; 1019 devmode->dmFields |= DM_DEFAULTSOURCE; 1020 } 1021 1022 if (mediaszname && (mediaszname != devmode->dmPaperSize)) { 1023 devmode->dmPaperSize = mediaszname; 1024 devmode->dmFields |= DM_PAPERSIZE; 1025 } 1026 1027 return ret; 1028 } 1029 1030 static LPTSTR GetPrinterPort(JNIEnv *env, LPTSTR printer) { 1031 1032 HANDLE hPrinter; 1033 if (::OpenPrinter(printer, &hPrinter, NULL) == FALSE) { 1034 return NULL; 1035 } 1036 1037 DWORD bytesReturned, bytesNeeded; 1038 ::GetPrinter(hPrinter, 2, NULL, 0, &bytesNeeded); 1039 PRINTER_INFO_2* info2 = (PRINTER_INFO_2*)::GlobalAlloc(GPTR, bytesNeeded); 1040 if (info2 == NULL) { 1041 ::ClosePrinter(hPrinter); 1042 return NULL; 1043 } 1044 1045 int ret = ::GetPrinter(hPrinter, 2, (LPBYTE)info2, 1046 bytesNeeded, &bytesReturned); 1047 ::ClosePrinter(hPrinter); 1048 if (!ret) { 1049 ::GlobalFree(info2); 1050 return NULL; 1051 } 1052 1053 LPTSTR port = _wcsdup(info2->pPortName); 1054 ::GlobalFree(info2); 1055 return port; 1056 } 1057 1058 static jboolean isFilePort(LPTSTR port) { 1059 return wcscmp(port, TEXT("FILE:")) == 0; 1060 } 1061 1062 /* 1063 * This is called when printing is about to start and we have not specified 1064 * a file destination - which is in fact the 99.99% case. 1065 * We can discover from the DEVNAMES if the DC is actually associated 1066 * with "FILE:", which is going to occur 1067 * 1) if the native print dialog was used and print to file was selected, or 1068 * 2) the printer driver is configured to print to file. 1069 * In that former case we have a conflict since if the destination is a 1070 * file, JDK will normally supply that destination to StartDoc, so what 1071 * must have happened is the app de-associated the job from the file, but 1072 * the printer DC etc is still hooked up to the file. If we find 1073 * the DEVNAMES specified is set to "FILE:" 1074 * First find out if the DC was associated with a FILE. If it is, 1075 * then unless that is its normal configuration, we'll get a new DC. 1076 * If the default destination ends with ":", this is sufficient clue 1077 * to windows it must be a device. Otherwise we need to create a new DC. 1078 */ 1079 LPTSTR VerifyDestination(JNIEnv *env, jobject wPrinterJob) { 1080 1081 LPTSTR dest = NULL; 1082 HDC printDC = AwtPrintControl::getPrintDC(env, wPrinterJob); 1083 HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, wPrinterJob); 1084 if (hDevNames == NULL || printDC == NULL) { 1085 return NULL; 1086 } 1087 1088 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); 1089 if (devnames != NULL) { 1090 LPTSTR lpdevnames = (LPTSTR)devnames; 1091 LPTSTR printer = lpdevnames+devnames->wDeviceOffset; 1092 LPTSTR port = lpdevnames+devnames->wOutputOffset; 1093 if (port != NULL && isFilePort(port)) { 1094 LPTSTR defPort = GetPrinterPort(env, printer); 1095 if (!isFilePort(defPort)) { // not a FILE: port by default 1096 int len = wcslen(defPort); 1097 if (len > 0 && port[len-1] == L':') { // is a device port 1098 dest = defPort; 1099 } else { 1100 /* We need to create a new DC */ 1101 HDC newDC = ::CreateDC(TEXT("WINSPOOL"), 1102 printer, NULL, NULL); 1103 AwtPrintControl::setPrintDC(env, wPrinterJob, newDC); 1104 DeleteDC(printDC); 1105 } 1106 } 1107 if (dest != defPort) { 1108 free(defPort); 1109 } 1110 } 1111 ::GlobalUnlock(hDevNames); 1112 } 1113 return dest; 1114 } 1115 1116 /* 1117 * Class: sun_awt_windows_WPrinterJob 1118 * Method: startDoc 1119 * Signature: ()V 1120 */ 1121 JNIEXPORT jboolean JNICALL 1122 Java_sun_awt_windows_WPrinterJob__1startDoc(JNIEnv *env, jobject self, 1123 jstring dest, jstring jobname) { 1124 TRY; 1125 1126 int err = 0; 1127 1128 LPTSTR destination = NULL; 1129 if (dest != NULL) { 1130 destination = (LPTSTR)JNU_GetStringPlatformChars(env, dest, NULL); 1131 } else { 1132 destination = VerifyDestination(env, self); 1133 } 1134 LPTSTR docname = NULL; 1135 if (jobname != NULL) { 1136 LPTSTR tmp = (LPTSTR)JNU_GetStringPlatformChars(env, jobname, NULL); 1137 docname = _tcsdup(tmp); 1138 JNU_ReleaseStringPlatformChars(env, jobname, tmp); 1139 } else { 1140 docname = TEXT("Java Printing"); 1141 } 1142 1143 initPrinter(env, self); 1144 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1145 1146 SAVE_CONTROLWORD 1147 /* We do our own rotation, so device must be in portrait mode. 1148 * This should be in effect only whilst we are printing, so that 1149 * if the app displays the native dialog again for the same printerjob 1150 * instance, it shows the setting the user expects. 1151 * So in EndDoc, and AbortDoc or if we fail out of this function, 1152 * we need to restore this. 1153 */ 1154 HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, self); 1155 if (printDC != NULL && hDevMode != NULL) { 1156 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 1157 if (devmode != NULL) { 1158 devmode->dmFields |= DM_ORIENTATION; 1159 devmode->dmOrientation = DMORIENT_PORTRAIT; 1160 /* set attribute values into devmode */ 1161 bool ret = setPrintReqAttribute(env, self, devmode); 1162 ::ResetDC(printDC, devmode); 1163 RESTORE_CONTROLWORD 1164 1165 if (!ret) { 1166 /* 1167 Need to read in updated device capabilities because 1168 print quality has been changed. 1169 */ 1170 setCapabilities(env, self, printDC); 1171 } 1172 } 1173 ::GlobalUnlock(hDevMode); 1174 } 1175 1176 if (printDC){ 1177 DOCINFO docInfo; 1178 memset(&docInfo, 0, sizeof(DOCINFO)); 1179 docInfo.cbSize = sizeof (DOCINFO); 1180 docInfo.lpszDocName = docname; 1181 1182 TCHAR fullPath[_MAX_PATH]; 1183 if (destination != NULL) { 1184 _tfullpath(fullPath, destination, _MAX_PATH); 1185 docInfo.lpszOutput = fullPath; 1186 } 1187 1188 docInfo.fwType = 0; 1189 1190 err = ::StartDoc(printDC, &docInfo); 1191 RESTORE_CONTROLWORD 1192 free((void*)docInfo.lpszDocName); 1193 if (err <= 0) { 1194 err = GetLastError(); 1195 } else { 1196 err = 0; 1197 } 1198 if (dest != NULL) { 1199 JNU_ReleaseStringPlatformChars(env, dest, destination); 1200 } 1201 } 1202 else { 1203 jclass printerException = env->FindClass(PRINTEREXCEPTION_STR); 1204 env->ThrowNew(printerException, "No printer found."); 1205 } 1206 1207 if (err && err != ERROR_CANCELLED) { 1208 throwPrinterException(env, err); 1209 } 1210 if (err == ERROR_CANCELLED) { 1211 return JNI_FALSE; 1212 } else { 1213 return JNI_TRUE; 1214 } 1215 1216 CATCH_BAD_ALLOC_RET(0); 1217 } 1218 1219 /* 1220 * Class: sun_awt_windows_WPrinterJob 1221 * Method: endDoc 1222 * Signature: ()V 1223 */ 1224 JNIEXPORT void JNICALL 1225 Java_sun_awt_windows_WPrinterJob_endDoc(JNIEnv *env, jobject self) { 1226 TRY; 1227 1228 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1229 1230 if (printDC != NULL){ 1231 SAVE_CONTROLWORD 1232 ::EndDoc(printDC); 1233 RESTORE_CONTROLWORD 1234 } 1235 1236 CATCH_BAD_ALLOC; 1237 } 1238 1239 /* 1240 * Class: sun_awt_windows_WPrinterJob 1241 * Method: abortDoc 1242 * Signature: ()V 1243 */ 1244 JNIEXPORT void JNICALL 1245 Java_sun_awt_windows_WPrinterJob_abortDoc(JNIEnv *env, jobject self) { 1246 TRY; 1247 1248 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1249 1250 if (printDC != NULL){ 1251 ::AbortDoc(printDC); 1252 } 1253 1254 CATCH_BAD_ALLOC; 1255 } 1256 1257 static void DeletePrintDC(HDC printDC) { 1258 if (printDC==NULL) { 1259 return; 1260 } 1261 /* Free any GDI objects we may have selected into the DC. 1262 * It is not harmful to call DeleteObject if the retrieved objects 1263 * happen to be stock objects. 1264 */ 1265 HBRUSH hbrush = (HBRUSH)::SelectObject(printDC, 1266 ::GetStockObject(BLACK_BRUSH)); 1267 if (hbrush != NULL) { 1268 ::DeleteObject(hbrush); 1269 } 1270 HPEN hpen = (HPEN)::SelectObject(printDC, ::GetStockObject(BLACK_PEN)); 1271 if (hpen != NULL) { 1272 ::DeleteObject(hpen); 1273 } 1274 HFONT hfont = (HFONT)::SelectObject(printDC,::GetStockObject(SYSTEM_FONT)); 1275 if (hfont != NULL) { 1276 ::DeleteObject(hfont); 1277 } 1278 ::DeleteDC(printDC); 1279 } 1280 1281 /* 1282 * Class: sun_awt_windows_WPrinterJob 1283 * Method: deleteDC 1284 * Signature: ()V 1285 * Called after WPrinterJob has been GCed, not before. 1286 */ 1287 JNIEXPORT void JNICALL 1288 Java_sun_awt_windows_WPrinterJob_deleteDC 1289 (JNIEnv *env, jclass wpjClass, jlong dc, jlong devmode, jlong devnames) { 1290 1291 TRY_NO_VERIFY; 1292 1293 DeletePrintDC((HDC)dc); 1294 1295 if ((HGLOBAL)devmode != NULL){ 1296 ::GlobalFree((HGLOBAL)devmode); 1297 } 1298 if ((HGLOBAL)devnames != NULL){ 1299 ::GlobalFree((HGLOBAL)devnames); 1300 } 1301 1302 CATCH_BAD_ALLOC; 1303 } 1304 1305 /* 1306 * Class: sun_awt_windows_WPrinterJob 1307 * Method: deviceStartPage 1308 * Signature: (Ljava/awt/print/PageFormat;Ljava/awt/print/Printable;I)V 1309 */ 1310 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_deviceStartPage 1311 (JNIEnv *env, jobject self, jobject format, jobject painter, jint pageIndex, 1312 jboolean pageChanged) { 1313 TRY; 1314 1315 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1316 1317 if (printDC != NULL){ 1318 LONG retval = 0; 1319 HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, self); 1320 HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, self); 1321 WORD dmPaperSize = getPrintPaperSize(env, self); 1322 SAVE_CONTROLWORD 1323 // Unless the PageFormat has been changed, do not set the paper 1324 // size for a new page. Doing so is unnecessary, perhaps expensive, 1325 // and can lead some printers to emit the paper prematurely in 1326 // duplex mode. 1327 if (hDevMode != NULL && hDevNames != NULL && pageChanged) { 1328 1329 RectDouble paperSize; 1330 RectDouble margins; 1331 jobject paper = getPaper(env, format); 1332 getPaperValues(env, paper, &paperSize, &margins); 1333 double paperWidth, paperHeight; 1334 matchPaperSize(printDC, hDevMode, hDevNames, 1335 paperSize.width, paperSize.height, 1336 &paperWidth, &paperHeight, &dmPaperSize); 1337 1338 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 1339 if (devmode != NULL) { 1340 if (dmPaperSize == 0) { 1341 devmode->dmFields |= DM_PAPERLENGTH | DM_PAPERWIDTH 1342 | DM_PAPERSIZE; 1343 devmode->dmPaperSize = DMPAPER_USER; 1344 devmode->dmPaperWidth = 1345 (short)(convertFromPoints(paperSize.width, MM_LOMETRIC)); 1346 devmode->dmPaperLength = 1347 (short)(convertFromPoints(paperSize.height, MM_LOMETRIC)); 1348 // sync with public devmode settings 1349 { 1350 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); 1351 if (devnames != NULL) { 1352 1353 LPTSTR lpdevnames = (LPTSTR)devnames; 1354 LPTSTR printerName = _tcsdup(lpdevnames+devnames->wDeviceOffset); 1355 1356 HANDLE hPrinter; 1357 if (::OpenPrinter(printerName, &hPrinter, NULL)== TRUE) { 1358 1359 // Need to call DocumentProperties to update change 1360 // in paper setting because some drivers do not update 1361 // it with a simple call to ResetDC. 1362 retval = ::DocumentProperties(NULL, hPrinter,printerName, 1363 devmode, devmode, 1364 DM_IN_BUFFER|DM_OUT_BUFFER); 1365 RESTORE_CONTROLWORD 1366 1367 ::ClosePrinter(hPrinter); 1368 free ((char*)printerName); 1369 } 1370 } 1371 1372 ::GlobalUnlock(hDevNames); 1373 } // sync 1374 HDC res = ::ResetDC(printDC, devmode); 1375 RESTORE_CONTROLWORD 1376 } // if (dmPaperSize == 0) 1377 // if DocumentProperties() fail 1378 if (retval < 0) { 1379 ::GlobalUnlock(hDevMode); 1380 return; 1381 } 1382 } 1383 ::GlobalUnlock(hDevMode); 1384 } 1385 1386 ::StartPage(printDC); 1387 RESTORE_CONTROLWORD 1388 1389 /* The origin for a glyph will be along the left 1390 * edge of its bnounding box at the base line. 1391 * The coincides with the Java text glyph origin. 1392 */ 1393 ::SetTextAlign(printDC, TA_LEFT | TA_BASELINE); 1394 1395 /* The background mode is used when GDI draws text, 1396 * hatched brushes and poen that are not solid. 1397 * We set the mode to transparentso that when 1398 * drawing text only the glyphs themselves are 1399 * drawn. The boundingbox of the string is not 1400 * erased to the background color. 1401 */ 1402 ::SetBkMode(printDC, TRANSPARENT); 1403 } 1404 1405 CATCH_BAD_ALLOC; 1406 } 1407 1408 /* 1409 * Class: sun_awt_windows_WPrinterJob 1410 * Method: deviceEndPage 1411 * Signature: (Ljava/awt/print/PageFormat;Ljava/awt/print/Printable;I)V 1412 */ 1413 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_deviceEndPage 1414 (JNIEnv *env, jobject self, jobject format, jobject painter, jint pageIndex) { 1415 TRY; 1416 1417 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1418 1419 if (printDC != NULL){ 1420 SAVE_CONTROLWORD 1421 ::EndPage(printDC); 1422 RESTORE_CONTROLWORD 1423 } 1424 1425 CATCH_BAD_ALLOC; 1426 } 1427 1428 /* 1429 * Class: sun_awt_windows_WEmbeddedFrame 1430 * Method: isPrinterDC 1431 * Signature: (J)Z 1432 */ 1433 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WEmbeddedFrame_isPrinterDC 1434 (JNIEnv *env, jobject self, jlong hdc) { 1435 1436 HDC realHDC = (HDC)hdc; 1437 if (realHDC == NULL) { 1438 return JNI_FALSE; 1439 } 1440 1441 int technology = GetDeviceCaps(realHDC, TECHNOLOGY); 1442 #if DEBUG_PRINTING 1443 FILE *file = fopen("c:\\plog.txt", "a"); 1444 fprintf(file,"tech is %d\n", technology); 1445 fclose(file); 1446 #endif //DEBUG_PRINTING 1447 switch (GetDeviceCaps(realHDC, TECHNOLOGY)) { 1448 case DT_RASPRINTER : 1449 return JNI_TRUE; 1450 case DT_RASDISPLAY : 1451 case DT_METAFILE : 1452 if (GetObjectType(realHDC) == OBJ_ENHMETADC) { 1453 return JNI_TRUE; 1454 } 1455 default : return JNI_FALSE; 1456 } 1457 } 1458 1459 /* 1460 * Class: sun_awt_windows_WEmbeddedFrame 1461 * Method: printBand 1462 * Signature: (J[BIIIIIIIII)V 1463 */ 1464 JNIEXPORT void JNICALL Java_sun_awt_windows_WEmbeddedFrame_printBand 1465 (JNIEnv *env, jobject self, jlong theHDC, jbyteArray imageArray, 1466 jint offset, jint srcX, jint srcY, jint srcWidth, jint srcHeight, 1467 jint destX, jint destY, jint destWidth, jint destHeight) { 1468 1469 if (theHDC == NULL || imageArray == NULL || 1470 srcWidth <= 0 || srcHeight == 0 || destWidth == 0 || destHeight <=0) { 1471 return; 1472 } 1473 1474 HDC hDC = (HDC)theHDC; 1475 1476 /* The code below is commented out until its proven necessary. In its 1477 * original form of PatBlit(hDC, destX,destY,destWidth, destHeight ..) 1478 * it resulted in the PS driver showing a white fringe, perhaps because 1479 * the PS driver enclosed the specified area rather than filling its 1480 * interior. The code is believed to have been there to prevent such 1481 * artefacts rather than cause them. This may have been related to 1482 * the earlier implementation using findNonWhite(..) and breaking the 1483 * image blit up into multiple blit calls. This currently looks as if 1484 * its unnecessary as the driver performs adequate compression where 1485 * such all white spans exist 1486 */ 1487 // HGDIOBJ oldBrush = 1488 // ::SelectObject(hDC, AwtBrush::Get(RGB(0xff, 0xff, 0xff))->GetHandle()); 1489 // ::PatBlt(hDC, destX+1, destY+1, destWidth-2, destHeight-2, PATCOPY); 1490 // ::SelectObject(hDC, oldBrush); 1491 1492 TRY; 1493 jbyte *image = NULL; 1494 try { 1495 image = (jbyte *)env->GetPrimitiveArrayCritical(imageArray, 0); 1496 struct { 1497 BITMAPINFOHEADER bmiHeader; 1498 DWORD* bmiColors; 1499 } bitMapHeader; 1500 1501 memset(&bitMapHeader,0,sizeof(bitMapHeader)); 1502 bitMapHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 1503 bitMapHeader.bmiHeader.biWidth = srcWidth; 1504 bitMapHeader.bmiHeader.biHeight = srcHeight; 1505 bitMapHeader.bmiHeader.biPlanes = 1; 1506 bitMapHeader.bmiHeader.biBitCount = 24; 1507 bitMapHeader.bmiHeader.biCompression = BI_RGB; 1508 1509 int result = 1510 ::StretchDIBits(hDC, 1511 destX, // left of dest rect 1512 destY, // top of dest rect 1513 destWidth, // width of dest rect 1514 destHeight, // height of dest rect 1515 srcX, // left of source rect 1516 srcY, // top of source rect 1517 srcWidth, // number of 1st source scan line 1518 srcHeight, // number of source scan lines 1519 image+offset, // points to the DIB 1520 (BITMAPINFO *)&bitMapHeader, 1521 DIB_RGB_COLORS, 1522 SRCCOPY); 1523 #if DEBUG_PRINTING 1524 FILE *file = fopen("c:\\plog.txt", "a"); 1525 fprintf(file,"sh=%d dh=%d sy=%d dy=%d result=%d\n", srcHeight, destHeight, srcY, destY, result); 1526 fclose(file); 1527 #endif //DEBUG_PRINTING 1528 } catch (...) { 1529 if (image != NULL) { 1530 env->ReleasePrimitiveArrayCritical(imageArray, image, 0); 1531 } 1532 throw; 1533 } 1534 1535 env->ReleasePrimitiveArrayCritical(imageArray, image, 0); 1536 1537 CATCH_BAD_ALLOC; 1538 } 1539 1540 /* 1541 * Class: sun_awt_windows_WPrinterJob 1542 * Method: printBand 1543 * Signature: ([BIIII)V 1544 */ 1545 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_printBand 1546 (JNIEnv *env, jobject self, jbyteArray imageArray, jint x, jint y, 1547 jint width, jint height) { 1548 1549 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1550 doPrintBand(env, JNI_FALSE, printDC, imageArray, x, y, width, height); 1551 } 1552 1553 /* 1554 * Class: sun_awt_windows_WPrinterJob 1555 * Method: beginPath 1556 * Signature: (J)V 1557 */ 1558 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_beginPath 1559 (JNIEnv *env , jobject self, jlong printDC) { 1560 TRY; 1561 1562 (void) ::BeginPath((HDC)printDC); 1563 1564 CATCH_BAD_ALLOC; 1565 } 1566 1567 /* 1568 * Class: sun_awt_windows_WPrinterJob 1569 * Method: endPath 1570 * Signature: (J)V 1571 */ 1572 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_endPath 1573 (JNIEnv *env, jobject self, jlong printDC) { 1574 TRY; 1575 1576 (void) ::EndPath((HDC)printDC); 1577 1578 CATCH_BAD_ALLOC; 1579 } 1580 1581 /* 1582 * Class: sun_awt_windows_WPrinterJob 1583 * Method: fillPath 1584 * Signature: (J)V 1585 */ 1586 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_fillPath 1587 (JNIEnv *env, jobject self, jlong printDC) { 1588 TRY; 1589 1590 (void) ::FillPath((HDC)printDC); 1591 1592 CATCH_BAD_ALLOC; 1593 } 1594 1595 /* 1596 * Class: sun_awt_windows_WPrinterJob 1597 * Method: closeFigure 1598 * Signature: (J)V 1599 */ 1600 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_closeFigure 1601 (JNIEnv *env, jobject self, jlong printDC) { 1602 TRY; 1603 1604 (void) ::CloseFigure((HDC)printDC); 1605 1606 CATCH_BAD_ALLOC; 1607 } 1608 1609 /* 1610 * Class: sun_awt_windows_WPrinterJob 1611 * Method: lineTo 1612 * Signature: (JFF)V 1613 */ 1614 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_lineTo 1615 (JNIEnv *env, jobject self, jlong printDC, jfloat x, jfloat y) { 1616 TRY; 1617 1618 (void) ::LineTo((HDC)printDC, ROUND_TO_LONG(x), ROUND_TO_LONG(y)); 1619 1620 CATCH_BAD_ALLOC; 1621 } 1622 1623 1624 /* 1625 * Class: sun_awt_windows_WPrinterJob 1626 * Method: moveTo 1627 * Signature: (JFF)V 1628 */ 1629 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_moveTo 1630 (JNIEnv *env, jobject self, jlong printDC, jfloat x, jfloat y) { 1631 TRY; 1632 1633 (void) ::MoveToEx((HDC)printDC, ROUND_TO_LONG(x), ROUND_TO_LONG(y), NULL); 1634 1635 CATCH_BAD_ALLOC; 1636 } 1637 1638 /* 1639 * Class: sun_awt_windows_WPrinterJob 1640 * Method: polyBezierTo 1641 * Signature: (JFFFFFF)V 1642 */ 1643 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_polyBezierTo 1644 (JNIEnv *env, jobject self, jlong printDC, 1645 jfloat control1x, jfloat control1y, 1646 jfloat control2x, jfloat control2y, 1647 jfloat endX, jfloat endY) { 1648 1649 TRY; 1650 1651 POINT points[3]; 1652 1653 points[0].x = ROUND_TO_LONG(control1x); 1654 points[0].y = ROUND_TO_LONG(control1y); 1655 points[1].x = ROUND_TO_LONG(control2x); 1656 points[1].y = ROUND_TO_LONG(control2y); 1657 points[2].x = ROUND_TO_LONG(endX); 1658 points[2].y = ROUND_TO_LONG(endY); 1659 1660 (void) ::PolyBezierTo((HDC)printDC, points, 3); 1661 1662 CATCH_BAD_ALLOC; 1663 } 1664 1665 /* 1666 * Class: sun_awt_windows_WPrinterJob 1667 * Method: setPolyFillMode 1668 * Signature: (JI)V 1669 */ 1670 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setPolyFillMode 1671 (JNIEnv *env, jobject self, jlong printDC, jint fillRule) { 1672 TRY; 1673 1674 (void) ::SetPolyFillMode((HDC)printDC, fillRule); 1675 1676 CATCH_BAD_ALLOC; 1677 } 1678 1679 /* 1680 * Class: sun_awt_windows_WPrinterJob 1681 * Method: selectSolidBrush 1682 * Signature: (JIII)V 1683 */ 1684 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectSolidBrush 1685 (JNIEnv *env, jobject self, jlong printDC, jint red, jint green, jint blue) { 1686 1687 TRY; 1688 1689 HBRUSH colorBrush = ::CreateSolidBrush(RGB(red, green, blue)); 1690 HBRUSH oldBrush = (HBRUSH)::SelectObject((HDC)printDC, colorBrush); 1691 DeleteObject(oldBrush); 1692 1693 CATCH_BAD_ALLOC; 1694 } 1695 1696 /* 1697 * Class: sun_awt_windows_WPrinterJob 1698 * Method: getPenX 1699 * Signature: (J)I 1700 */ 1701 JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getPenX 1702 (JNIEnv *env, jobject self, jlong printDC) { 1703 1704 TRY; 1705 1706 POINT where; 1707 ::GetCurrentPositionEx((HDC)printDC, &where); 1708 1709 return (jint) where.x; 1710 1711 CATCH_BAD_ALLOC_RET(0); 1712 } 1713 1714 /* 1715 * Class: sun_awt_windows_WPrinterJob 1716 * Method: getPenY 1717 * Signature: (J)I 1718 */ 1719 JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getPenY 1720 (JNIEnv *env, jobject self, jlong printDC) { 1721 1722 TRY; 1723 1724 POINT where; 1725 ::GetCurrentPositionEx((HDC)printDC, &where); 1726 1727 return (jint) where.y; 1728 1729 CATCH_BAD_ALLOC_RET(0); 1730 } 1731 1732 /* 1733 * Class: sun_awt_windows_WPrinterJob 1734 * Method: selectClipPath 1735 * Signature: (J)V 1736 */ 1737 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectClipPath 1738 (JNIEnv *env, jobject self, jlong printDC) { 1739 1740 TRY; 1741 1742 ::SelectClipPath((HDC)printDC, RGN_COPY); 1743 1744 CATCH_BAD_ALLOC; 1745 } 1746 1747 1748 /* 1749 * Class: sun_awt_windows_WPrinterJob 1750 * Method: frameRect 1751 * Signature: (JFFFF)V 1752 */ 1753 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_frameRect 1754 (JNIEnv *env, jobject self, jlong printDC, 1755 jfloat x, jfloat y, jfloat width, jfloat height) { 1756 1757 TRY; 1758 1759 POINT points[5]; 1760 1761 points[0].x = ROUND_TO_LONG(x); 1762 points[0].y = ROUND_TO_LONG(y); 1763 points[1].x = ROUND_TO_LONG(x+width); 1764 points[1].y = ROUND_TO_LONG(y); 1765 points[2].x = ROUND_TO_LONG(x+width); 1766 points[2].y = ROUND_TO_LONG(y+height); 1767 points[3].x = ROUND_TO_LONG(x); 1768 points[3].y = ROUND_TO_LONG(y+height); 1769 points[4].x = ROUND_TO_LONG(x); 1770 points[4].y = ROUND_TO_LONG(y); 1771 1772 ::Polyline((HDC)printDC, points, sizeof(points)/sizeof(points[0])); 1773 1774 CATCH_BAD_ALLOC; 1775 } 1776 1777 /* 1778 * Class: sun_awt_windows_WPrinterJob 1779 * Method: fillRect 1780 * Signature: (JFFFFIII)V 1781 */ 1782 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_fillRect 1783 (JNIEnv *env, jobject self, jlong printDC, 1784 jfloat x, jfloat y, jfloat width, jfloat height, 1785 jint red, jint green, jint blue) { 1786 1787 TRY; 1788 1789 RECT rect; 1790 rect.left = ROUND_TO_LONG(x); 1791 rect.top = ROUND_TO_LONG(y); 1792 rect.right = ROUND_TO_LONG(x+width); 1793 rect.bottom = ROUND_TO_LONG(y+height); 1794 1795 HBRUSH brush = ::CreateSolidBrush(RGB(red, green, blue)); 1796 1797 if (brush != NULL) { 1798 ::FillRect((HDC)printDC, (LPRECT) &rect, brush); 1799 DeleteObject(brush); 1800 } 1801 1802 CATCH_BAD_ALLOC; 1803 } 1804 1805 1806 /* 1807 * Class: sun_awt_windows_WPrinterJob 1808 * Method: selectPen 1809 * Signature: (JFIII)V 1810 */ 1811 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectPen 1812 (JNIEnv *env, jobject self, jlong printDC, jfloat width, 1813 jint red, jint green, jint blue) { 1814 1815 TRY; 1816 1817 HPEN hpen = ::CreatePen(PS_SOLID, ROUND_TO_LONG(width), 1818 RGB(red, green, blue)); 1819 1820 if (hpen != NULL) { 1821 HPEN oldpen = (HPEN) ::SelectObject((HDC)printDC, hpen); 1822 1823 if (oldpen != NULL) { 1824 DeleteObject(oldpen); 1825 } 1826 } 1827 1828 CATCH_BAD_ALLOC; 1829 } 1830 1831 1832 /* 1833 * Class: sun_awt_windows_WPrinterJob 1834 * Method: selectStylePen 1835 * Signature: (JJJFIII)Z 1836 */ 1837 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_selectStylePen 1838 (JNIEnv *env, jobject self, jlong printDC, jlong cap, jlong join, jfloat width, 1839 jint red, jint green, jint blue) { 1840 1841 TRY; 1842 1843 LOGBRUSH logBrush; 1844 1845 logBrush.lbStyle = PS_SOLID ; 1846 logBrush.lbColor = RGB(red, green, blue); 1847 logBrush.lbHatch = 0 ; 1848 1849 HPEN hpen = ::ExtCreatePen(PS_GEOMETRIC | PS_SOLID | (DWORD)cap 1850 | (DWORD)join, ROUND_TO_LONG(width), 1851 &logBrush, 0, NULL); 1852 1853 if (hpen != NULL) { 1854 HPEN oldpen = (HPEN) ::SelectObject((HDC)printDC, hpen); 1855 1856 if (oldpen != NULL) { 1857 DeleteObject(oldpen); 1858 } 1859 } 1860 1861 return JNI_TRUE; 1862 1863 CATCH_BAD_ALLOC_RET (0); 1864 } 1865 1866 /* 1867 * Class: sun_awt_windows_WPrinterJob 1868 * Method: setFont 1869 * Signature: (JLjava/lang/String;FZZIF)Z 1870 */ 1871 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_setFont 1872 (JNIEnv *env, jobject self, jlong printDC, jstring fontName, 1873 jfloat fontSize, jboolean isBold, jboolean isItalic, jint rotation, 1874 jfloat awScale) 1875 { 1876 jboolean didSetFont = JNI_FALSE; 1877 1878 didSetFont = jFontToWFontW(env, (HDC)printDC, 1879 fontName, 1880 fontSize, 1881 isBold, 1882 isItalic, 1883 rotation, 1884 awScale); 1885 1886 return didSetFont; 1887 } 1888 1889 /** 1890 * Try to convert a java font to a GDI font. On entry, 'printDC', 1891 * is the device context we want to draw into. 'fontName' is 1892 * the name of the font to be matched and 'fontSize' is the 1893 * size of the font in device coordinates. If there is an 1894 * equivalent GDI font then this function sets that font 1895 * into 'printDC' and returns a 'true'. If there is no equivalent 1896 * font then 'false' is returned. 1897 */ 1898 static jboolean jFontToWFontA(JNIEnv *env, HDC printDC, jstring fontName, 1899 jfloat fontSize, jboolean isBold, jboolean isItalic, 1900 jint rotation, jfloat awScale) 1901 { 1902 LOGFONTA lf; 1903 LOGFONTA matchedLogFont; 1904 BOOL foundFont = false; // Assume we didn't find a matching GDI font. 1905 1906 memset(&matchedLogFont, 0, sizeof(matchedLogFont)); 1907 1908 LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); 1909 1910 1911 /* Some fontnames of Non-ASCII fonts like 'MS Minchou' are themselves 1912 * Non-ASCII. They are assumed to be written in Unicode. 1913 * Hereby, they are converted into platform codeset. 1914 */ 1915 int maxlen = static_cast<int>(sizeof(lf.lfFaceName)) - 1; 1916 // maxlen is int due to cbMultiByte parameter is int 1917 int destLen = WideCharToMultiByte(CP_ACP, // convert to ASCII code page 1918 0, // flags 1919 fontNameW, // Unicode string 1920 -1, // Unicode length is calculated automatically 1921 lf.lfFaceName, // Put ASCII string here 1922 maxlen, // max len 1923 NULL, // default handling of unmappables 1924 NULL); // do not care if def char is used 1925 1926 /* If WideCharToMultiByte succeeded then the number 1927 * of bytes it copied into the face name buffer will 1928 * be creater than zero and we just need to NULL terminate 1929 * the string. If there was an error then the number of 1930 * bytes copied is zero and we can not match the font. 1931 */ 1932 if (destLen > 0) { 1933 1934 DASSERT(destLen < sizeof(lf.lfFaceName)); 1935 lf.lfFaceName[destLen] = '\0'; 1936 lf.lfCharSet = DEFAULT_CHARSET; 1937 lf.lfPitchAndFamily = 0; 1938 1939 foundFont = !EnumFontFamiliesExA((HDC)printDC, &lf, 1940 (FONTENUMPROCA) fontEnumProcA, 1941 (LPARAM) &matchedLogFont, 0); 1942 } 1943 1944 1945 if (foundFont) { 1946 1947 /* Build a font of the requested size with no 1948 * width modifications. A negative font height 1949 * tells GDI that we want that values absolute 1950 * value as the font's point size. If the font 1951 * is successfully built then set it as the current 1952 * GDI font. 1953 */ 1954 matchedLogFont.lfHeight = -ROUND_TO_LONG(fontSize); 1955 matchedLogFont.lfWidth = 0; 1956 matchedLogFont.lfEscapement = rotation; 1957 matchedLogFont.lfOrientation = rotation; 1958 matchedLogFont.lfUnderline = 0; 1959 matchedLogFont.lfStrikeOut = 0; 1960 1961 /* Force bold or italic if requested. The font name 1962 such as Arial Bold may have already set a weight 1963 so here we just try to increase it. 1964 */ 1965 if (isBold) { 1966 matchedLogFont.lfWeight = embolden(matchedLogFont.lfWeight); 1967 } else { 1968 matchedLogFont.lfWeight = FW_REGULAR; 1969 } 1970 1971 if (isItalic) { 1972 matchedLogFont.lfItalic = 0xff; // TRUE 1973 } else { 1974 matchedLogFont.lfItalic = FALSE; 1975 } 1976 1977 HFONT font = CreateFontIndirectA(&matchedLogFont); 1978 if (font) { 1979 HFONT oldFont = (HFONT)::SelectObject(printDC, font); 1980 if (oldFont != NULL) { 1981 ::DeleteObject(oldFont); 1982 if (awScale != 1.0) { 1983 TEXTMETRIC tm; 1984 DWORD avgWidth; 1985 GetTextMetrics(printDC, &tm); 1986 avgWidth = tm.tmAveCharWidth; 1987 matchedLogFont.lfWidth = (LONG)((fabs)(avgWidth*awScale)); 1988 font = CreateFontIndirectA(&matchedLogFont); 1989 if (font) { 1990 oldFont = (HFONT)::SelectObject(printDC, font); 1991 if (oldFont != NULL) { 1992 ::DeleteObject(oldFont); 1993 GetTextMetrics(printDC, &tm); 1994 } else { 1995 foundFont = false; 1996 } 1997 } else { 1998 foundFont = false; 1999 } 2000 } 2001 } else { 2002 foundFont = false; 2003 } 2004 } else { 2005 foundFont = false; 2006 } 2007 } 2008 2009 JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); 2010 2011 return foundFont ? JNI_TRUE : JNI_FALSE; 2012 } 2013 2014 /** 2015 * Try to convert a java font to a GDI font. On entry, 'printDC', 2016 * is the device context we want to draw into. 'fontName' is 2017 * the name of the font to be matched and 'fontSize' is the 2018 * size of the font in device coordinates. If there is an 2019 * equivalent GDI font then this function sets that font 2020 * into 'printDC' and returns a 'true'. If there is no equivalent 2021 * font then 'false' is returned. 2022 */ 2023 static jboolean jFontToWFontW(JNIEnv *env, HDC printDC, jstring fontName, 2024 jfloat fontSize, jboolean isBold, jboolean isItalic, 2025 jint rotation, jfloat awScale) 2026 { 2027 LOGFONTW lf; 2028 LOGFONTW matchedLogFont; 2029 BOOL foundFont = false; // Assume we didn't find a matching GDI font. 2030 2031 memset(&matchedLogFont, 0, sizeof(matchedLogFont)); 2032 2033 LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); 2034 2035 /* Describe the GDI fonts we want enumerated. We 2036 * simply supply the java font name and let GDI 2037 * do the matching. If the java font name is 2038 * longer than the GDI maximum font lenght then 2039 * we can't convert the font. 2040 */ 2041 size_t nameLen = wcslen(fontNameW); 2042 if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) { 2043 2044 wcscpy(lf.lfFaceName, fontNameW); 2045 2046 lf.lfCharSet = DEFAULT_CHARSET; 2047 lf.lfPitchAndFamily = 0; 2048 2049 foundFont = !::EnumFontFamiliesEx((HDC)printDC, &lf, 2050 (FONTENUMPROCW) fontEnumProcW, 2051 (LPARAM) &matchedLogFont, 0); 2052 } 2053 2054 JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); 2055 2056 if (!foundFont) { 2057 return JNI_FALSE; 2058 } 2059 2060 /* Build a font of the requested size with no 2061 * width modifications. A negative font height 2062 * tells GDI that we want that values absolute 2063 * value as the font's point size. If the font 2064 * is successfully built then set it as the current 2065 * GDI font. 2066 */ 2067 matchedLogFont.lfHeight = -ROUND_TO_LONG(fontSize); 2068 matchedLogFont.lfWidth = 0; 2069 matchedLogFont.lfEscapement = rotation; 2070 matchedLogFont.lfOrientation = rotation; 2071 matchedLogFont.lfUnderline = 0; 2072 matchedLogFont.lfStrikeOut = 0; 2073 2074 /* Force bold or italic if requested. The font name 2075 * such as Arial Bold may have already set a weight 2076 * so here we just try to increase it. 2077 */ 2078 if (isBold) { 2079 matchedLogFont.lfWeight = embolden(matchedLogFont.lfWeight); 2080 } else { 2081 matchedLogFont.lfWeight = FW_REGULAR; 2082 } 2083 2084 if (isItalic) { 2085 matchedLogFont.lfItalic = 0xff; // TRUE 2086 } else { 2087 matchedLogFont.lfItalic = FALSE; 2088 } 2089 2090 //Debug: dumpLogFont(&matchedLogFont); 2091 2092 HFONT font = ::CreateFontIndirect(&matchedLogFont); 2093 if (font == NULL) { 2094 return JNI_FALSE; 2095 } 2096 2097 HFONT oldFont = (HFONT)::SelectObject(printDC, font); 2098 if (oldFont == NULL) { // select failed. 2099 ::DeleteObject(font); 2100 return JNI_FALSE; 2101 } 2102 ::DeleteObject(oldFont); // no longer needed. 2103 2104 /* If there is a non-uniform scale then get a new version 2105 * of the font with an average width that is condensed or 2106 * expanded to match the average width scaling factor. 2107 * This is not valid for shearing transforms. 2108 */ 2109 if (awScale != 1.0) { 2110 TEXTMETRIC tm; 2111 DWORD avgWidth; 2112 GetTextMetrics(printDC, &tm); 2113 avgWidth = tm.tmAveCharWidth; 2114 matchedLogFont.lfWidth = (LONG)((fabs)(avgWidth*awScale)); 2115 font = ::CreateFontIndirect(&matchedLogFont); 2116 if (font == NULL) { 2117 return JNI_FALSE; 2118 } 2119 oldFont = (HFONT)::SelectObject(printDC, font); 2120 if (oldFont == NULL) { 2121 ::DeleteObject(font); 2122 return JNI_FALSE; 2123 } else { 2124 ::DeleteObject(oldFont); 2125 return JNI_TRUE; 2126 } 2127 } 2128 return JNI_TRUE; 2129 } 2130 2131 /** 2132 * Invoked by GDI as a result of the EnumFontFamiliesExW 2133 * call this routine choses a GDI font that matches 2134 * a Java font. When a match is found then function 2135 * returns a zero result to terminate the EnumFontFamiliesExW 2136 * call. The information about the chosen font is copied into 2137 * the LOGFONTW structure pointed to by 'lParam'. 2138 */ 2139 static int CALLBACK fontEnumProcW(ENUMLOGFONTEXW *logfont,// logical-font data 2140 NEWTEXTMETRICEX *lpntme, // physical-font data 2141 int FontType, // type of font 2142 LPARAM lParam) 2143 { 2144 LOGFONTW *matchedLogFont = (LOGFONTW *) lParam; 2145 int stop = 0; // Take the first style found. 2146 2147 if (matchedLogFont != NULL) { 2148 *matchedLogFont = logfont->elfLogFont; 2149 } 2150 2151 return stop; 2152 } 2153 2154 /** 2155 * Invoked by GDI as a result of the EnumFontFamiliesExA 2156 * call this routine choses a GDI font that matches 2157 * a Java font. When a match is found then function 2158 * returns a zero result to terminate the EnumFontFamiliesExA 2159 * call. The information about the chosen font is copied into 2160 * the LOGFONTA structure pointed to by 'lParam'. 2161 */ 2162 static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA *logfont,// logical-font data 2163 NEWTEXTMETRICEX *lpntme, // physical-font data 2164 int FontType, // type of font 2165 LPARAM lParam) 2166 { 2167 LOGFONTA *matchedLogFont = (LOGFONTA *) lParam; 2168 int stop = 0; // Take the first style found. 2169 2170 if (matchedLogFont != NULL) { 2171 *matchedLogFont = logfont->elfLogFont; 2172 } 2173 2174 return stop; 2175 } 2176 2177 /** 2178 * Given the weight of a font from a GDI LOGFONT 2179 * structure, return a new weight indicating a 2180 * bolder font. 2181 */ 2182 static int embolden(int currentWeight) 2183 { 2184 2185 /* If the font is less than bold then make 2186 * it bold. In real life this will mean making 2187 * a FW_NORMAL font bold. 2188 */ 2189 if (currentWeight < FW_BOLD) { 2190 currentWeight = FW_BOLD; 2191 2192 /* If the font is already bold or bolder 2193 * then just increase the weight. This will 2194 * not be visible with GDI in Win95 or NT4. 2195 */ 2196 } else { 2197 currentWeight += EMBOLDEN_WEIGHT; 2198 if (currentWeight > MAX_FONT_WEIGHT) { 2199 currentWeight = MAX_FONT_WEIGHT; 2200 } 2201 } 2202 2203 return currentWeight; 2204 } 2205 2206 /* 2207 * Class: sun_awt_windows_WPrinterJob 2208 * Method: setTextColor 2209 * Signature: (JIII)V 2210 */ 2211 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setTextColor 2212 (JNIEnv *env, jobject self, jlong printDC, jint red, jint green, jint blue) { 2213 2214 (void) ::SetTextColor( (HDC)printDC, RGB(red, green, blue)); 2215 2216 } 2217 2218 JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getGDIAdvance 2219 (JNIEnv *env, jobject self, jlong printDC, jstring text) 2220 { 2221 SIZE size; 2222 LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); 2223 size_t strLen = wcslen(wText); 2224 BOOL ok = GetTextExtentPoint32((HDC)printDC, wText, (int)strLen, &size); 2225 JNU_ReleaseStringPlatformChars(env, text, wText); 2226 return ok ? size.cx : 0; 2227 } 2228 2229 2230 2231 /* 2232 * ETO_PDY is conditionally defined in wingdi.h as it is available 2233 * only on Windows 2000 and later. ie it requires the application 2234 * define that it is targeting these APIS by placing 2235 * #define _WIN32_WINNT 0x0500 2236 * and perhaps 2237 * #define WINVER 0x5000 2238 * before including the headers 2239 * But this causes many problems for AWT headers subsequently included. 2240 * So instead hard code the value of the flag as our own macro 2241 * If for any reason this code is executed on Win 9x then this will 2242 * not be understood and the advances array will be misinterpreted. 2243 * So we don't use that it in that case and restrict ourselves to x advances. 2244 * Its possible in some cases that text would then not print as expected. 2245 * However we will not normally supply y advances so this is a less likely 2246 * code path and its not worth worrying about in we will not in future 2247 * support win9x - and definitely not to this extent. 2248 */ 2249 #define J2D_ETO_PDY 0x2000 2250 2251 /* 2252 * Class: sun_awt_windows_WPrinterJob 2253 * Method: textOut 2254 * Signature: (JLjava/lang/String;BFF[F)V 2255 * 2256 * Generate GDI text calls for the unicode string 2257 * <code>text</code> into the device context 2258 * <code>printDC</code>. The text string is 2259 * positioned at <code>x</code>, <code>y</code>. 2260 * The positioning of each glyph in the string 2261 * is determined by windows. 2262 * If 'glyphCodes' is true then the string is 16 bit glyph indices 2263 * into the font, not character codes. 2264 * strLen needs to be passed in for the glyphCodes case since its possible 2265 * the missing glyph code may be present, and that is always zero, which 2266 * would be misinterpreted by GDI and the string functions as null termination 2267 * of the string. 2268 */ 2269 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_textOut 2270 (JNIEnv *env, jobject self, jlong printDC, jstring text, jint strLen, 2271 boolean glyphCodes, jfloat x, jfloat y, jfloatArray positions) 2272 { 2273 2274 long posX = ROUND_TO_LONG(x); 2275 long posY = ROUND_TO_LONG(y); 2276 int flags = (glyphCodes !=0) ? ETO_GLYPH_INDEX : 0; 2277 LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); 2278 2279 int *advances = NULL, *xadvances = NULL, *xyadvances = NULL; 2280 BOOL useYAdvances = FALSE; 2281 jfloat *glyphPos = NULL; 2282 if (positions != NULL) { 2283 glyphPos = env->GetFloatArrayElements(positions, NULL); 2284 } 2285 2286 /* We need to convert positions relative to the origin of the text 2287 * into advances relative to the previous glyph. 2288 * We expect to be able to allocate these small arrays. 2289 * If we fail then we'll print the glyphs using their built-in advances. 2290 * Because the array is of inter-character advances we only need 2291 * strLen - 1 entries but Windows looks at the advance between 2292 * the last character and the non-existent character we allocate 2293 * space for that as well. 2294 * We supply only the advances that are needed 2295 * - Default advances (ie none) if GDI advances are what we want 2296 * - Only X advances if the Y advances are all zero. 2297 * We allocate two arrays so we can figure out on the fly which 2298 * we need. 2299 * Note that we have to add the 'error' or difference between the 2300 * rounded advance and the floating point advance back into the 2301 * calculation of the next advance else the sum of the integer- 2302 * rounded advances will drift away from the true advance. 2303 */ 2304 if (glyphPos != NULL && strLen > 0) { 2305 xadvances = (int*)safe_Malloc(strLen * sizeof(int)); 2306 xyadvances = (int*)safe_Malloc(strLen * sizeof(int) * 2); 2307 } 2308 if (xadvances != NULL && xyadvances != NULL) { 2309 int *inxAdvances = xadvances; 2310 int *inxyAdvances = xyadvances; 2311 jfloat *inGlyphPos = glyphPos; 2312 jfloat lastX = *inGlyphPos++; 2313 jfloat lastY = *inGlyphPos++; 2314 jfloat errorX = 0, errorY = 0; 2315 for (int i = 1; i < strLen; i++) { 2316 2317 jfloat thisX = *inGlyphPos++; 2318 jfloat thisY = *inGlyphPos++; 2319 2320 jfloat xAdvance = thisX - lastX + errorX; 2321 jfloat yAdvance = thisY - lastY + errorY; 2322 2323 int xadv = ROUND_TO_INT(xAdvance); 2324 errorX = xAdvance - xadv; 2325 int yadv = ROUND_TO_INT(yAdvance); 2326 errorY = yAdvance - yadv; 2327 if (yadv != 0) { 2328 useYAdvances = TRUE; 2329 } 2330 *inxAdvances++ = xadv; 2331 *inxyAdvances++ = xadv; 2332 *inxyAdvances++ = yadv; 2333 2334 lastX = thisX; 2335 lastY = thisY; 2336 } 2337 /* This is the advance from the last character. 2338 * It is not technically needed, but the raster 2339 * drivers, as opposed to the PostScript driver 2340 * will fail to print the entire string if this 2341 * value is absurdly large or absurdly negative. 2342 */ 2343 *inxAdvances = 0; 2344 *inxyAdvances++ = 0; 2345 *inxyAdvances = 0; 2346 } 2347 2348 if (useYAdvances) { 2349 advances = xyadvances; 2350 flags |= J2D_ETO_PDY; 2351 } else { 2352 advances = xadvances; 2353 } 2354 2355 /* Done with the float array parameter, so release it. */ 2356 if (glyphPos != NULL) { 2357 env->ReleaseFloatArrayElements(positions, glyphPos, JNI_ABORT); 2358 } 2359 2360 BOOL drawn = ::ExtTextOut((HDC)printDC, 2361 posX, posY, // starting position for the text 2362 flags, // glyphCodes?, y advances? 2363 NULL, // optional clipping-opaquing rectangle 2364 wText, // the Unicode text to draw 2365 static_cast<UINT>(strLen), 2366 advances); // intercharacter advances or NULL 2367 2368 if (xadvances != NULL) { 2369 free(xadvances); 2370 } 2371 if (xyadvances != NULL) { 2372 free(xyadvances); 2373 } 2374 2375 JNU_ReleaseStringPlatformChars(env, text, wText); 2376 } 2377 2378 /** 2379 * Scans a 24 bit RGB DIB image looking for the first non-white line. 2380 * On entry, if scanLineStride is negative, 'image' points at the 2381 * bottom of the DIB, which is where the first scan line is. 2382 * Alternatively, if scanLineStride is positive, it's a top-down 2383 * DIB and 'image' points to the top scan line. 2384 * 'numLinesP', on entry, is the number of scan lines in the image while 2385 * 'width' is the number of 24 bit pixels on each line. If a non-white 2386 * line is found in the DIB, then a pointer to the first, 2387 * working from the bottom, non-white scan line is returned. 2388 * and the number of remaining scan lines is returned in *'numLinesP'. 2389 * Pixels are 3 byte BGR triples, so any byte that is not 0xff indicates 2390 * its a component of a non-white pixel. So we don't need to combine bytes 2391 * into pixels. Simply scan the image looking for any byte that is not 0xff 2392 */ 2393 static jbyte *findNonWhite(jbyte *image, long sy, long width, long height, 2394 long scanLineStride, long *numLinesP) { 2395 2396 long found = -1; 2397 long numLines = 0; 2398 jbyte *startLine = image; 2399 unsigned char *inLine; 2400 const unsigned char cc = (unsigned char)0xff; 2401 2402 assert(image != NULL); 2403 assert(0 <= sy && sy < height); 2404 assert(0 < width); 2405 assert(0 < height); 2406 assert(numLinesP != NULL); 2407 2408 for (numLines = 0; sy < height; numLines++, sy++) { 2409 2410 inLine = (unsigned char*)startLine; 2411 2412 for (long colcomp = 0; colcomp < abs(scanLineStride); colcomp++) { 2413 if (*inLine++ != cc) { 2414 found = sy; 2415 break; 2416 } 2417 } 2418 2419 if(found != -1) { 2420 break; 2421 } 2422 2423 startLine += scanLineStride; 2424 } 2425 2426 *numLinesP = numLines; 2427 2428 return found == -1 ? NULL : startLine; 2429 } 2430 2431 /* Find the 1st scanline that's entirely white. 2432 * The starting scanline pointed to by 'image' may be part way through the DIB. 2433 * If an all white scanline is found, the return value points to the beginning 2434 * of the last scanline with a non-white pixel. If no all white scanlines 2435 * are found, the starting scanline is returned. 2436 * '*numLinesP' returns the number of non-white scan lines. 2437 * Skip the 1st scanline as its always non-white. 2438 * If passed scanLineStride is negative, the DIB is bottom-up, 2439 * otherwise it's top-down. 2440 */ 2441 static jbyte *findWhite(jbyte *image, long sy, long width, long height, 2442 long scanLineStride, long *numLinesP) { 2443 2444 long numLines; 2445 jbyte *startLine = image; 2446 unsigned char *inLine; 2447 jbyte *found = NULL; 2448 long white; 2449 const unsigned char cc = (unsigned char)0xff; 2450 2451 assert(image != NULL); 2452 assert(0 <= sy); 2453 assert(0 < width); 2454 assert(0 < height); 2455 assert(numLinesP != NULL); 2456 2457 ++sy; 2458 for(numLines = 1; sy < height; numLines++, sy++) { 2459 2460 startLine += scanLineStride; 2461 inLine = (unsigned char*)startLine; 2462 white = 1; 2463 2464 for (long colcomp = 0; colcomp < abs(scanLineStride); colcomp++) { 2465 if (*inLine++ != cc) { 2466 white = 0; 2467 break; 2468 } 2469 } 2470 2471 if (white != 0) { 2472 found = startLine - scanLineStride; 2473 break; 2474 } 2475 } 2476 2477 *numLinesP = numLines; 2478 2479 return found == NULL ? startLine : found; 2480 2481 } 2482 2483 /* 2484 * Reverses the bitmap. 2485 * Returns pointer to reversed bitmap (DWORD aligned). 2486 * Returns NULL if unsuccessful. 2487 * NOTE: Caller must free the pointer returned by calling free. 2488 */ 2489 static jbyte* reverseDIB(jbyte* imageBits, long srcWidth, long srcHeight, 2490 int bitsperpixel) { 2491 2492 /* get width in bytes. 2493 * If the image is 24bpp, its srcWidth*3 2494 * If the image is 8bpp, its just srcWidth 2495 * If the image is 1bpp or 4bpp one then its rounded up to the next byte. 2496 */ 2497 long imgWidthByteSz; 2498 switch (bitsperpixel) { 2499 case 24 : imgWidthByteSz = srcWidth * 3; 2500 break; 2501 case 8 : imgWidthByteSz = srcWidth; 2502 break; 2503 case 1 : imgWidthByteSz = (srcWidth + 7) / 8 ; 2504 break; 2505 case 4 : imgWidthByteSz = (srcWidth + 1) / 2 ; 2506 break; 2507 default : /* not expected but this is OK for any exact multiple of 8 */ 2508 imgWidthByteSz = srcWidth * bitsperpixel / 8; 2509 } 2510 2511 int padBytes = 0; 2512 /* make it DWORD aligned */ 2513 if ((imgWidthByteSz % sizeof(DWORD)) != 0) 2514 padBytes = sizeof(DWORD) - (imgWidthByteSz % sizeof(DWORD)); 2515 2516 long newImgSize = (imgWidthByteSz+padBytes) * ROUND_TO_LONG(srcHeight); 2517 jbyte* alignedImage = (jbyte*) safe_Malloc(newImgSize); 2518 2519 if (alignedImage != NULL) { 2520 memset(alignedImage, 0xff, newImgSize); 2521 2522 jbyte* imgLinePtr = alignedImage; 2523 for (long i=ROUND_TO_LONG(srcHeight)-1; i>=0; i--) { 2524 memcpy(imgLinePtr, imageBits+(i*imgWidthByteSz), 2525 imgWidthByteSz); 2526 imgLinePtr += (imgWidthByteSz + padBytes); 2527 } 2528 2529 return alignedImage; 2530 } 2531 return NULL; 2532 } 2533 2534 #if 0 2535 2536 /* 2537 * Class: sun_awt_windows_WPrinterJob 2538 * Method: drawImageIntRGB 2539 * Signature: (J[IFFFFFFFFII)V 2540 */ 2541 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_drawImageIntRGB 2542 (JNIEnv *env, jobject self, 2543 jlong printDC, jintArray image, 2544 jfloat destX, jfloat destY, 2545 jfloat destWidth, jfloat destHeight, 2546 jfloat srcX, jfloat srcY, 2547 jfloat srcWidth, jfloat srcHeight, 2548 jint srcBitMapWidth, jint srcBitMapHeight) { 2549 2550 int result = 0; 2551 2552 assert(printDC != NULL); 2553 assert(image != NULL); 2554 assert(srcX >= 0); 2555 assert(srcY >= 0); 2556 assert(srcWidth > 0); 2557 assert(srcHeight > 0); 2558 assert(srcBitMapWidth > 0); 2559 assert(srcBitMapHeight > 0); 2560 2561 2562 static int alphaMask = 0xff000000; 2563 static int redMask = 0x00ff0000; 2564 static int greenMask = 0x0000ff00; 2565 static int blueMask = 0x000000ff; 2566 2567 struct { 2568 BITMAPV4HEADER header; 2569 DWORD masks[256]; 2570 } dib; 2571 2572 2573 2574 memset(&dib,0,sizeof(dib)); 2575 dib.header.bV4Size = sizeof(dib.header); 2576 dib.header.bV4Width = srcBitMapWidth; 2577 dib.header.bV4Height = -srcBitMapHeight; // Top down DIB 2578 dib.header.bV4Planes = 1; 2579 dib.header.bV4BitCount = 32; 2580 dib.header.bV4V4Compression = BI_BITFIELDS; 2581 dib.header.bV4SizeImage = 0; // It's the default size. 2582 dib.header.bV4XPelsPerMeter = 0; 2583 dib.header.bV4YPelsPerMeter = 0; 2584 dib.header.bV4ClrUsed = 0; 2585 dib.header.bV4ClrImportant = 0; 2586 dib.header.bV4RedMask = redMask; 2587 dib.header.bV4GreenMask = greenMask; 2588 dib.header.bV4BlueMask = blueMask; 2589 dib.header.bV4AlphaMask = alphaMask; 2590 dib.masks[0] = redMask; 2591 dib.masks[1] = greenMask; 2592 dib.masks[2] = blueMask; 2593 dib.masks[3] = alphaMask; 2594 2595 jint *imageBits = NULL; 2596 2597 try { 2598 imageBits = (jint *)env->GetPrimitiveArrayCritical(image, 0); 2599 2600 if (printDC){ 2601 result = ::StretchDIBits( (HDC)printDC, 2602 ROUND_TO_LONG(destX), 2603 ROUND_TO_LONG(destY), 2604 ROUND_TO_LONG(destWidth), 2605 ROUND_TO_LONG(destHeight), 2606 ROUND_TO_LONG(srcX), 2607 ROUND_TO_LONG(srcY), 2608 ROUND_TO_LONG(srcWidth), 2609 ROUND_TO_LONG(srcHeight), 2610 imageBits, 2611 (BITMAPINFO *)&dib, 2612 DIB_RGB_COLORS, 2613 SRCCOPY); 2614 2615 } 2616 } catch (...) { 2617 if (imageBits != NULL) { 2618 env->ReleasePrimitiveArrayCritical(image, imageBits, 0); 2619 } 2620 throw; 2621 } 2622 2623 env->ReleasePrimitiveArrayCritical(image, imageBits, 0); 2624 2625 } 2626 #else 2627 2628 /* 2629 * Class: sun_awt_windows_WPrinterJob 2630 * Method: drawDIBImage 2631 * Signature: (J[BFFFFFFFFI[B)V 2632 */ 2633 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_drawDIBImage 2634 (JNIEnv *env, jobject self, 2635 jlong printDC, jbyteArray image, 2636 jfloat destX, jfloat destY, 2637 jfloat destWidth, jfloat destHeight, 2638 jfloat srcX, jfloat srcY, 2639 jfloat srcWidth, jfloat srcHeight, 2640 jint bitCount, jbyteArray bmiColorsArray) { 2641 2642 int result = 0; 2643 2644 assert(printDC != NULL); 2645 assert(image != NULL); 2646 assert(srcX >= 0); 2647 assert(srcY >= 0); 2648 assert(srcWidth > 0); 2649 assert(srcHeight > 0); 2650 2651 #define MAXCOLS 256 2652 struct { 2653 BITMAPINFOHEADER bmiHeader; 2654 RGBQUAD bmiColors[MAXCOLS]; 2655 } bmi; 2656 2657 memset(&bmi, 0, sizeof(bmi)); 2658 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 2659 bmi.bmiHeader.biWidth = ROUND_TO_LONG(srcWidth); 2660 bmi.bmiHeader.biHeight = ROUND_TO_LONG(srcHeight); 2661 bmi.bmiHeader.biPlanes = 1; 2662 bmi.bmiHeader.biBitCount = (WORD)bitCount; 2663 bmi.bmiHeader.biCompression = BI_RGB; 2664 bmi.bmiHeader.biSizeImage = 0; // It's the default size. 2665 bmi.bmiHeader.biXPelsPerMeter = 0; 2666 bmi.bmiHeader.biYPelsPerMeter = 0; 2667 bmi.bmiHeader.biClrUsed = 0; 2668 bmi.bmiHeader.biClrImportant = 0; 2669 2670 jint *imageBits = NULL; 2671 try { 2672 2673 if (bmiColorsArray != NULL) { 2674 BYTE* bmiCols; 2675 int numCols = 1<<bitCount; 2676 if (numCols > MAXCOLS) { 2677 numCols = MAXCOLS; /* don't write past end of struct */ 2678 } 2679 bmiCols = (BYTE*)env->GetPrimitiveArrayCritical(bmiColorsArray, 0); 2680 memcpy(&(bmi.bmiColors[0]), bmiCols, (numCols*4)); 2681 env->ReleasePrimitiveArrayCritical(bmiColorsArray, bmiCols, 0); 2682 } 2683 imageBits = (jint *)env->GetPrimitiveArrayCritical(image, 0); 2684 2685 // Workaround for drivers/apps that do not support top-down. 2686 // Because we don't know if they support or not, 2687 // always send bottom-up DIBs. 2688 jbyte *dibImage = reverseDIB((jbyte*)imageBits, 2689 (long)srcWidth, (long)srcHeight, 2690 bitCount); 2691 if (dibImage != NULL) { 2692 if (printDC){ 2693 result = ::StretchDIBits( (HDC)printDC, 2694 ROUND_TO_LONG(destX), 2695 ROUND_TO_LONG(destY), 2696 ROUND_TO_LONG(destWidth), 2697 ROUND_TO_LONG(destHeight), 2698 ROUND_TO_LONG(srcX), 2699 ROUND_TO_LONG(srcY), 2700 ROUND_TO_LONG(srcWidth), 2701 ROUND_TO_LONG(srcHeight), 2702 dibImage, 2703 (BITMAPINFO*)(&bmi), 2704 DIB_RGB_COLORS, 2705 SRCCOPY); 2706 } 2707 2708 free(dibImage); 2709 } /* if (dibImage != NULL) */ 2710 } catch (...) { 2711 if (imageBits != NULL) { 2712 env->ReleasePrimitiveArrayCritical(image, imageBits, 0); 2713 } 2714 JNU_ThrowInternalError(env, "Problem in WPrinterJob_drawDIBImage"); 2715 return; 2716 } 2717 env->ReleasePrimitiveArrayCritical(image, imageBits, 0); 2718 2719 } 2720 #endif 2721 2722 /* 2723 * An utility function to print passed image byte array to 2724 * the printDC. 2725 * browserPrinting flag controls whether the image array 2726 * used as top-down (browserPrinting == JNI_TRUE) or 2727 * bottom-up (browserPrinting == JNI_FALSE) DIB. 2728 */ 2729 static void doPrintBand(JNIEnv *env, jboolean browserPrinting, 2730 HDC printDC, jbyteArray imageArray, 2731 jint x, jint y, jint width, jint height) { 2732 2733 TRY; 2734 2735 jbyte *image = NULL; 2736 try { 2737 long scanLineStride = J2DRasterBPP * width; 2738 image = (jbyte *)env->GetPrimitiveArrayCritical(imageArray, 0); 2739 jbyte *startImage; 2740 jbyte *endImage = NULL; 2741 long startY = 0; 2742 long numLines = 0; 2743 2744 if (browserPrinting) { 2745 /* for browser printing use top-down approach */ 2746 startImage = image; 2747 } else { 2748 /* when printing to a real printer dc, the dib 2749 should bottom-up */ 2750 startImage = image + (scanLineStride * (height - 1)); 2751 scanLineStride = -scanLineStride; 2752 } 2753 do { 2754 startImage = findNonWhite(startImage, startY, width, height, 2755 scanLineStride, &numLines); 2756 2757 if (startImage != NULL) { 2758 startY += numLines; 2759 endImage = findWhite(startImage, startY, width, height, 2760 scanLineStride, &numLines); 2761 if (browserPrinting) { 2762 /* passing -numLines as height to indicate that 2763 we treat the image as a top-down DIB */ 2764 bitsToDevice(printDC, startImage, x, y + startY, width, 2765 -numLines); 2766 } else { 2767 bitsToDevice(printDC, endImage, x, y + startY, width, 2768 numLines); 2769 } 2770 startImage = endImage + scanLineStride; 2771 startY += numLines; 2772 } 2773 } while (startY < height && startImage != NULL); 2774 2775 } catch (...) { 2776 if (image != NULL) { 2777 env->ReleasePrimitiveArrayCritical(imageArray, image, 0); 2778 } 2779 throw; 2780 } 2781 2782 env->ReleasePrimitiveArrayCritical(imageArray, image, 0); 2783 2784 CATCH_BAD_ALLOC; 2785 2786 } 2787 static FILE* outfile = NULL; 2788 static int bitsToDevice(HDC printDC, jbyte *image, long destX, long destY, 2789 long width, long height) { 2790 int result = 0; 2791 2792 assert(printDC != NULL); 2793 assert(image != NULL); 2794 assert(destX >= 0); 2795 assert(destY >= 0); 2796 assert(width > 0); 2797 /* height could be negative to indicate that this is a top-down DIB */ 2798 // assert(height > 0); 2799 2800 struct { 2801 BITMAPINFOHEADER bmiHeader; 2802 DWORD* bmiColors; 2803 } bitMapHeader; 2804 2805 memset(&bitMapHeader,0,sizeof(bitMapHeader)); 2806 bitMapHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 2807 bitMapHeader.bmiHeader.biWidth = width; 2808 bitMapHeader.bmiHeader.biHeight = height; // does -height work ever? 2809 bitMapHeader.bmiHeader.biPlanes = 1; 2810 bitMapHeader.bmiHeader.biBitCount = 24; 2811 bitMapHeader.bmiHeader.biCompression = BI_RGB; 2812 bitMapHeader.bmiHeader.biSizeImage = 0; // It's the default size. 2813 bitMapHeader.bmiHeader.biXPelsPerMeter = 0; 2814 bitMapHeader.bmiHeader.biYPelsPerMeter = 0; 2815 bitMapHeader.bmiHeader.biClrUsed = 0; 2816 bitMapHeader.bmiHeader.biClrImportant = 0; 2817 bitMapHeader.bmiColors = NULL; 2818 2819 height = abs(height); 2820 2821 // Workaround for drivers/apps that do not support top-down. 2822 // Because we don't know if they support or not, 2823 // always send bottom-up DIBs 2824 if (bitMapHeader.bmiHeader.biHeight < 0) { 2825 jbyte *dibImage = reverseDIB(image, width, height, 24); 2826 if (dibImage != NULL) { 2827 bitMapHeader.bmiHeader.biWidth = ROUND_TO_LONG(width); 2828 bitMapHeader.bmiHeader.biHeight = ROUND_TO_LONG(height); 2829 2830 if (printDC){ 2831 result = ::SetDIBitsToDevice(printDC, 2832 ROUND_TO_LONG(destX), // left of dest rect 2833 ROUND_TO_LONG(destY), // top of dest rect 2834 ROUND_TO_LONG(width), // width of dest rect 2835 ROUND_TO_LONG(height), // height of dest rect 2836 0, // left of source rect 2837 0, // top of source rect 2838 0, // line number of 1st source scan line 2839 ROUND_TO_LONG(height), // number of scan lines 2840 dibImage, // points to the DIB 2841 (BITMAPINFO *)&bitMapHeader, 2842 DIB_RGB_COLORS); 2843 } 2844 2845 free (dibImage); 2846 } 2847 } else { 2848 if (printDC){ 2849 result = ::SetDIBitsToDevice(printDC, 2850 destX, // left of dest rect 2851 destY, // top of dest rect 2852 width, // width of dest rect 2853 height, // height of dest rect 2854 0, // left of source rect 2855 0, // top of source rect 2856 0, // line number of 1st source scan line 2857 height, // number of source scan lines 2858 image, // points to the DIB 2859 (BITMAPINFO *)&bitMapHeader, 2860 DIB_RGB_COLORS); 2861 } 2862 } 2863 2864 return result; 2865 } 2866 2867 LRESULT CALLBACK PageDialogWndProc(HWND hWnd, UINT message, 2868 WPARAM wParam, LPARAM lParam) 2869 { 2870 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 2871 2872 switch (message) { 2873 case WM_COMMAND: { 2874 if ((LOWORD(wParam) == IDOK) || 2875 (LOWORD(wParam) == IDCANCEL)) 2876 { 2877 // If we recieve on of these two notifications, the dialog 2878 // is about to be closed. It's time to unblock all the 2879 // windows blocked by this dialog, as doing so from the 2880 // WM_DESTROY handler is too late 2881 jobject peer = (jobject)(::GetProp(hWnd, ModalDialogPeerProp)); 2882 env->CallVoidMethod(peer, AwtPrintDialog::setHWndMID, (jlong)0); 2883 } 2884 break; 2885 } 2886 } 2887 2888 WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hWnd, NativeDialogWndProcProp)); 2889 return ComCtl32Util::GetInstance().DefWindowProc(lpfnWndProc, hWnd, message, wParam, lParam); 2890 } 2891 2892 /** 2893 * Called by the Page Setup dialog this routine makes sure the 2894 * print dialog becomes the front most window. 2895 */ 2896 static UINT CALLBACK pageDlgHook(HWND hDlg, UINT msg, 2897 WPARAM wParam, LPARAM lParam) 2898 { 2899 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 2900 2901 TRY; 2902 2903 switch(msg) { 2904 case WM_INITDIALOG: { 2905 PAGESETUPDLG *psd = (PAGESETUPDLG *)lParam; 2906 jobject peer = (jobject)(psd->lCustData); 2907 env->CallVoidMethod(peer, AwtPrintDialog::setHWndMID, 2908 (jlong)hDlg); 2909 ::SetProp(hDlg, ModalDialogPeerProp, reinterpret_cast<HANDLE>(peer)); 2910 2911 SetForegroundWindow(hDlg); 2912 2913 // set appropriate icon for parentless dialogs 2914 jobject awtParent = env->GetObjectField(peer, AwtPrintDialog::parentID); 2915 if (awtParent == NULL) { 2916 ::SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_BIG, 2917 (LPARAM)AwtToolkit::GetInstance().GetAwtIcon()); 2918 } else { 2919 env->DeleteLocalRef(awtParent); 2920 } 2921 2922 // subclass dialog's parent to receive additional messages 2923 WNDPROC lpfnWndProc = ComCtl32Util::GetInstance().SubclassHWND(hDlg, 2924 PageDialogWndProc); 2925 ::SetProp(hDlg, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc)); 2926 2927 break; 2928 } 2929 case WM_DESTROY: { 2930 WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hDlg, NativeDialogWndProcProp)); 2931 ComCtl32Util::GetInstance().UnsubclassHWND(hDlg, 2932 PageDialogWndProc, 2933 lpfnWndProc); 2934 ::RemoveProp(hDlg, ModalDialogPeerProp); 2935 ::RemoveProp(hDlg, NativeDialogWndProcProp); 2936 break; 2937 } 2938 } 2939 2940 return (UINT) FALSE; 2941 2942 CATCH_BAD_ALLOC_RET(TRUE); 2943 } 2944 2945 /** 2946 * Create and return a printer device context for the 2947 * default printer. If there is no default printer then 2948 * return NULL. This fn is used when printing is invoked 2949 * and no user dialog was created. So despite its name, it 2950 * needs to return a DC which reflects all the applications 2951 * settings which the driver might support. 2952 * The number of copies is the most important setting. 2953 */ 2954 static HDC getDefaultPrinterDC(JNIEnv *env, jobject printerJob) { 2955 HDC printDC = NULL; 2956 2957 int devWillDoCopies = FALSE; 2958 PRINTDLG pd; 2959 memset(&pd, 0, sizeof(PRINTDLG)); 2960 pd.lStructSize = sizeof(PRINTDLG); 2961 pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC; 2962 2963 if (::PrintDlg(&pd)) { 2964 printDC = pd.hDC; 2965 2966 /* Find out how many copies the driver can do, and use driver's 2967 * dmCopies if requested number is within that limit 2968 */ 2969 int maxCopies = 1; 2970 int nCopies = getCopies(env, printerJob); 2971 SAVE_CONTROLWORD 2972 if (pd.hDevNames != NULL) { 2973 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(pd.hDevNames); 2974 2975 if (devnames != NULL) { 2976 LPTSTR lpdevnames = (LPTSTR)devnames; 2977 LPTSTR printer = lpdevnames+devnames->wDeviceOffset; 2978 LPTSTR port = lpdevnames+devnames->wOutputOffset; 2979 // if DeviceCapabilities fails, return value is -1 2980 maxCopies = (int)::DeviceCapabilities(printer, port, DC_COPIES, 2981 NULL, NULL); 2982 RESTORE_CONTROLWORD 2983 if (maxCopies > 1) { 2984 devWillDoCopies = TRUE; 2985 } 2986 } 2987 ::GlobalUnlock(pd.hDevNames); 2988 } 2989 2990 if ((maxCopies >= nCopies) && (pd.hDevMode != NULL)) { 2991 DEVMODE *devmode = (DEVMODE *)::GlobalLock(pd.hDevMode); 2992 2993 if (devmode != NULL) { 2994 2995 if ((devmode->dmFields & DM_COPIES) && (nCopies > 1)) { 2996 devmode->dmCopies = nCopies; 2997 HDC tmpDC = ::ResetDC(pd.hDC, devmode); 2998 RESTORE_CONTROLWORD 2999 if (tmpDC != NULL) { 3000 printDC = tmpDC; 3001 } 3002 } 3003 } 3004 ::GlobalUnlock(pd.hDevMode); 3005 } 3006 3007 /* Not pretty that this is set in a separate place then the DC */ 3008 if (pd.hDevMode != NULL) { 3009 AwtPrintControl::setPrintHDMode(env, printerJob, pd.hDevMode); 3010 } 3011 if (pd.hDevNames != NULL) { 3012 AwtPrintControl::setPrintHDName(env, printerJob, pd.hDevNames); 3013 } 3014 3015 setBooleanField(env, printerJob, DRIVER_COPIES_STR, 3016 (devWillDoCopies ? JNI_TRUE : JNI_FALSE)); 3017 setBooleanField(env, printerJob, DRIVER_COLLATE_STR, JNI_FALSE); 3018 setBooleanField(env, printerJob, USER_COLLATE_STR, JNI_FALSE); 3019 3020 } 3021 3022 return printDC; 3023 } 3024 3025 3026 /** 3027 * Move the description of the page's size and orientation 3028 * from the PageFormat object 'page' into the structure, 3029 * 'setup' used by Windows to display the Page Setup dialog. 3030 */ 3031 static void pageFormatToSetup(JNIEnv *env, jobject job, 3032 jobject page, PAGESETUPDLG *setup, HDC hDC) { 3033 RectDouble paperSize; 3034 RectDouble margins; 3035 3036 /* Move the orientation from PageFormat to Windows. 3037 */ 3038 jint orient = getPageFormatOrientation(env, page); 3039 int gdiOrientation = (orient == PAGEFORMAT_PORTRAIT) ? 3040 DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE; 3041 setOrientationInDevMode(setup->hDevMode, orient == PAGEFORMAT_PORTRAIT); 3042 3043 int units = (setup->Flags & PSD_INTHOUSANDTHSOFINCHES) 3044 ? MM_HIENGLISH 3045 : MM_HIMETRIC; 3046 jobject paper = getPaper(env, page); 3047 getPaperValues(env, paper, &paperSize, &margins); 3048 // Setting the paper size appears to be a futile exercise, as its not one 3049 // of the values you can initialise - its an out-only arg. Margins are OK. 3050 // set it into the DEVMODE if there is one .. 3051 setup->ptPaperSize.x = convertFromPoints(paperSize.width, units); 3052 setup->ptPaperSize.y = convertFromPoints(paperSize.height, units); 3053 3054 if (setup->hDevMode != NULL) { 3055 3056 double paperWidth, paperHeight; 3057 WORD dmPaperSize = getPrintPaperSize(env, job); 3058 matchPaperSize(hDC, setup->hDevMode, setup->hDevNames, 3059 paperSize.width, paperSize.height, 3060 &paperWidth, &paperHeight, &dmPaperSize); 3061 3062 DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup->hDevMode); 3063 if (devmode != NULL) { 3064 if (dmPaperSize != 0) { 3065 devmode->dmFields |= DM_PAPERSIZE; 3066 devmode->dmPaperSize = dmPaperSize; 3067 } 3068 else { 3069 devmode->dmFields |= DM_PAPERLENGTH | DM_PAPERWIDTH 3070 | DM_PAPERSIZE; 3071 devmode->dmPaperSize = DMPAPER_USER; 3072 devmode->dmPaperWidth = 3073 (short)(convertFromPoints(paperSize.width, MM_LOMETRIC)); 3074 devmode->dmPaperLength = 3075 (short)(convertFromPoints(paperSize.height, MM_LOMETRIC)); 3076 } 3077 } 3078 ::GlobalUnlock(setup->hDevMode); 3079 } 3080 3081 // When setting up these values, account for the orientation of the Paper 3082 // in the PageFormat. In the margins Rect when in portrait mode, 3083 // width is really right margin, height is really bottom margin. 3084 if (orient == PAGEFORMAT_PORTRAIT) { 3085 setup->rtMargin.left = convertFromPoints(margins.x, units); 3086 setup->rtMargin.top = convertFromPoints(margins.y, units); 3087 setup->rtMargin.right = convertFromPoints(margins.width, units); 3088 setup->rtMargin.bottom = convertFromPoints(margins.height, units); 3089 } else if (orient == PAGEFORMAT_LANDSCAPE) { 3090 setup->rtMargin.left = convertFromPoints(margins.height, units); 3091 setup->rtMargin.top = convertFromPoints(margins.x, units); 3092 setup->rtMargin.right = convertFromPoints(margins.y, units); 3093 setup->rtMargin.bottom = convertFromPoints(margins.width, units); 3094 } else { // reverse landscape 3095 setup->rtMargin.left = convertFromPoints(margins.y, units); 3096 setup->rtMargin.top = convertFromPoints(margins.width, units); 3097 setup->rtMargin.right = convertFromPoints(margins.height, units); 3098 setup->rtMargin.bottom = convertFromPoints(margins.x, units); 3099 } 3100 3101 // Set page size here. 3102 } 3103 3104 3105 /** 3106 * Return an array of POINTS describing the paper sizes supported 3107 * by the driver identified by 'deviceName' and 'portName'. 3108 * If there is an error, then NULL is returned. 3109 */ 3110 static POINT *getPaperSizeList(LPCTSTR deviceName, LPCTSTR portName) { 3111 DWORD numPaperSizes; 3112 POINT *paperSizes = NULL; 3113 3114 SAVE_CONTROLWORD 3115 numPaperSizes = DeviceCapabilities(deviceName, portName, 3116 DC_PAPERSIZE, NULL, NULL); 3117 3118 if (numPaperSizes > 0) { 3119 paperSizes = (POINT *)safe_Malloc(sizeof(*paperSizes) * numPaperSizes); 3120 3121 DWORD result = DeviceCapabilities(deviceName, portName, 3122 DC_PAPERSIZE, (LPTSTR) paperSizes, 3123 NULL); 3124 if (result == -1) { 3125 free((char *) paperSizes); 3126 paperSizes = NULL; 3127 } 3128 } 3129 RESTORE_CONTROLWORD 3130 3131 return paperSizes; 3132 } 3133 3134 static WORD getOrientationFromDevMode2(HGLOBAL hDevMode) { 3135 3136 WORD orient = DMORIENT_PORTRAIT; 3137 3138 if (hDevMode != NULL) { 3139 LPDEVMODE devMode = (LPDEVMODE) GlobalLock(hDevMode); 3140 if ((devMode != NULL) && (devMode->dmFields & DM_ORIENTATION)) { 3141 orient = devMode->dmOrientation; 3142 } 3143 GlobalUnlock(hDevMode); 3144 } 3145 return orient; 3146 } 3147 3148 /** 3149 * Get the orientation of the paper described by the printer 3150 * handle to a device mode structure 'hDevMode'. 3151 */ 3152 static WORD getOrientationFromDevMode(JNIEnv *env, jobject self) { 3153 return getOrientationFromDevMode2(AwtPrintControl::getPrintHDMode(env, self)); 3154 } 3155 3156 /** 3157 * Set the orientation of the paper described by the printer 3158 * handle to a device mode structure 'hDevMode'. 3159 */ 3160 static void setOrientationInDevMode(HGLOBAL hDevMode, jboolean isPortrait) { 3161 3162 if (hDevMode != NULL) { 3163 LPDEVMODE devMode = (LPDEVMODE) GlobalLock(hDevMode); 3164 if (devMode != NULL) { 3165 devMode->dmOrientation = isPortrait 3166 ? DMORIENT_PORTRAIT 3167 : DMORIENT_LANDSCAPE; 3168 devMode->dmFields |= DM_ORIENTATION; 3169 } 3170 GlobalUnlock(hDevMode); 3171 } 3172 } 3173 3174 /** 3175 * Return the paper size and margins for the page 3176 * adjusted to take into account the portrait or 3177 * landscape orientation of the page. On entry, 3178 * 'setup' is a filled in structure as returned 3179 * by PageSetupDlg(). 'paperSize', 'margins', 3180 * and 'orientation' all point to caller allocated 3181 * space while will be filled in by this routine 3182 * with the size, in unknown Windows units, of 3183 * the paper, of the margins, and an indicator 3184 * whether the page is in portrait or landscape 3185 * orientation, respectively. 3186 */ 3187 static void retrievePaperInfo(const PAGESETUPDLG *setup, POINT *paperSize, 3188 RECT *margins, jint *orientation, HDC hdc) { 3189 int orientationKnown = FALSE; 3190 3191 *paperSize = setup->ptPaperSize; 3192 int gdiOrientation = DMORIENT_PORTRAIT; 3193 3194 /* Usually the setup dialog will tell us the 3195 * orientation of the page, but it may not. 3196 */ 3197 if (setup->hDevMode != NULL) { 3198 gdiOrientation = getOrientationFromDevMode2(setup->hDevMode); 3199 orientationKnown = TRUE; 3200 } 3201 3202 /* The driver didn't tell us the paper orientation 3203 * so we declare it landscape if the paper 3204 * is wider than it is long. Square paper is 3205 * declared to be portait. 3206 */ 3207 if (orientationKnown == FALSE && paperSize->x > paperSize->y) { 3208 gdiOrientation = DMORIENT_LANDSCAPE; 3209 } 3210 3211 *margins = setup->rtMargin; 3212 3213 // compare margin from page setup dialog with our device printable area 3214 RectDouble deviceMargin; 3215 3216 if (getPrintableArea(hdc, setup->hDevMode, &deviceMargin) == TRUE) { 3217 RECT devMargin; 3218 3219 int units = (setup->Flags & PSD_INTHOUSANDTHSOFINCHES) 3220 ? MM_HIENGLISH : MM_HIMETRIC; 3221 3222 devMargin.left = convertFromPoints(deviceMargin.x*72, units); 3223 devMargin.top = convertFromPoints(deviceMargin.y*72, units); 3224 devMargin.bottom = paperSize->y 3225 - convertFromPoints(deviceMargin.height*72, units) 3226 - devMargin.top; 3227 devMargin.right = paperSize->x 3228 - convertFromPoints(deviceMargin.width*72, units) 3229 - devMargin.left; 3230 3231 if (margins->left < devMargin.left) { 3232 margins->left = devMargin.left; 3233 } 3234 if (margins->top < devMargin.top) { 3235 margins->top = devMargin.top; 3236 } 3237 if (margins->bottom < devMargin.bottom) { 3238 margins->bottom = devMargin.bottom; 3239 } 3240 if (margins->right < devMargin.right) { 3241 margins->right = devMargin.right; 3242 } 3243 } 3244 3245 /* The Paper class expresses the page size in 3246 * portait mode while Windows returns the paper 3247 * size adjusted for the orientation. If the 3248 * orientation is landscape then we want to 3249 * flip the width and height to get a portait 3250 * description of the page. 3251 */ 3252 if (gdiOrientation != DMORIENT_PORTRAIT) { 3253 long hold = paperSize->x; 3254 paperSize->x = paperSize->y; 3255 paperSize->y = hold; 3256 3257 margins->left = setup->rtMargin.top; 3258 margins->right = setup->rtMargin.bottom; 3259 margins->top = setup->rtMargin.right; 3260 margins->bottom = setup->rtMargin.left; 3261 } 3262 3263 if (gdiOrientation == DMORIENT_PORTRAIT) { 3264 *orientation = PAGEFORMAT_PORTRAIT; 3265 } else { 3266 *orientation = PAGEFORMAT_LANDSCAPE; 3267 } 3268 } 3269 3270 /** 3271 * Return the number of copies to be printed for a printerJob. 3272 */ 3273 static jint getCopies(JNIEnv *env, jobject printerJob) 3274 { 3275 // Because this function may call client Java code, 3276 // we can't run it on the toolkit thread. 3277 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3278 3279 3280 jclass printerJobClass = env->GetObjectClass(printerJob); 3281 jmethodID getCopiesID = env->GetMethodID(printerJobClass, GETCOPIES_STR, 3282 GETCOPIES_SIG); 3283 jint copies = env->CallIntMethod(printerJob, getCopiesID); 3284 3285 return copies; 3286 } 3287 3288 /** 3289 * Return a copy of the Paper object attached to the 3290 * PageFormat object 'page.' 3291 */ 3292 static jobject getPaper(JNIEnv *env, jobject page) { 3293 // Because this function may call client Java code, 3294 // we can't run it on the toolkit thread. 3295 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3296 3297 3298 jclass pageClass = env->GetObjectClass(page); 3299 jmethodID getPaperID = env->GetMethodID(pageClass, GETPAPER_STR, 3300 GETPAPER_SIG); 3301 3302 return env->CallObjectMethod(page, getPaperID); 3303 } 3304 3305 /** 3306 * Set the Paper object for a PageFormat instance. 3307 * 'paper' is the new Paper object that must be 3308 * set into 'page'. 3309 */ 3310 static void setPaper(JNIEnv *env, jobject page, jobject paper) { 3311 // Because this function may call client Java code, 3312 // we can't run it on the toolkit thread. 3313 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3314 3315 jclass pageClass = env->GetObjectClass(page); 3316 jmethodID setPaperID = env->GetMethodID(pageClass, SETPAPER_STR, 3317 SETPAPER_SIG); 3318 env->CallVoidMethod(page, setPaperID, paper); 3319 } 3320 3321 /** 3322 * Return the integer ID for the orientation in the PageFormat. 3323 * Caution: this is the Java spec ID, not the GDI ID. 3324 */ 3325 static jint getPageFormatOrientation(JNIEnv *env, jobject page) { 3326 // Because this function may call client Java code, 3327 // we can't run it on the toolkit thread. 3328 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3329 3330 jclass pageClass = env->GetObjectClass(page); 3331 jmethodID getOrientID = env->GetMethodID(pageClass, GETORIENT_STR, 3332 GETORIENT_SIG); 3333 return env->CallIntMethod(page, getOrientID); 3334 } 3335 3336 static void setPageFormatOrientation(JNIEnv *env, 3337 jobject page, jint orientation) { 3338 // Because this function may call client Java code, 3339 // we can't run it on the toolkit thread. 3340 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3341 3342 jclass pageClass = env->GetObjectClass(page); 3343 jmethodID setOrientID = env->GetMethodID(pageClass, SETORIENT_STR, 3344 SETORIENT_SIG); 3345 env->CallVoidMethod(page, setOrientID, orientation); 3346 } 3347 3348 /** 3349 * Pull the paper size and margins out of the paper object and 3350 * return them in points. 3351 */ 3352 static void getPaperValues(JNIEnv *env, jobject paper, RectDouble *paperSize, 3353 RectDouble *margins, BOOL widthAsMargin) { 3354 // Because this function may call client Java code, 3355 // we can't run it on the toolkit thread. 3356 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3357 3358 jmethodID getID; 3359 3360 paperSize->x = 0; 3361 paperSize->y = 0; 3362 3363 jclass paperClass = env->GetObjectClass(paper); 3364 3365 getID = env->GetMethodID(paperClass, GETWIDTH_STR, GETWIDTH_SIG); 3366 paperSize->width = env->CallDoubleMethod(paper, getID); 3367 3368 getID = env->GetMethodID(paperClass, GETHEIGHT_STR, GETHEIGHT_SIG); 3369 paperSize->height = env->CallDoubleMethod(paper, getID); 3370 3371 getID = env->GetMethodID(paperClass, GETIMG_X_STR, GETIMG_X_SIG); 3372 margins->x = env->CallDoubleMethod(paper, getID); 3373 if (margins-> x < 0 ) { 3374 margins-> x = 0; 3375 } 3376 3377 getID = env->GetMethodID(paperClass, GETIMG_Y_STR, GETIMG_Y_SIG); 3378 margins->y = env->CallDoubleMethod(paper, getID); 3379 if (margins-> y < 0 ) { 3380 margins-> y = 0; 3381 } 3382 3383 getID = env->GetMethodID(paperClass, GETIMG_W_STR, GETIMG_W_SIG); 3384 if (widthAsMargin) { 3385 margins->width = paperSize->width - margins->x 3386 - env->CallDoubleMethod(paper, getID); 3387 } else { 3388 margins->width = env->CallDoubleMethod(paper, getID); 3389 } 3390 3391 if (margins->width < 0) { 3392 margins->width = 0; 3393 } 3394 3395 getID = env->GetMethodID(paperClass, GETIMG_H_STR, GETIMG_H_SIG); 3396 if (widthAsMargin) { 3397 margins->height = paperSize->height - margins->y 3398 - env->CallDoubleMethod(paper, getID); 3399 } else { 3400 margins->height = env->CallDoubleMethod(paper, getID); 3401 } 3402 3403 if (margins->height < 0) { 3404 margins->height = 0; 3405 } 3406 3407 } 3408 3409 /** 3410 * Given a RECT specifying the margins 3411 * for the page and an indication of whether 3412 * the units are 1000ths of an inch (MM_HIENGLISH) 3413 * or 100ths of a millimeter (MM_HIMETRIC), 3414 * convert the margins to 72nds of an inch 3415 * and set them into the PageFormat insance provided. 3416 */ 3417 static void setPaperValues(JNIEnv *env, jobject paper, const POINT *paperSize, 3418 const RECT *margins, int units) { 3419 // Because this function may call client Java code, 3420 // we can't run it on the toolkit thread. 3421 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3422 3423 jclass paperClass = env->GetObjectClass(paper); 3424 jmethodID setSizeID = env->GetMethodID(paperClass, 3425 SETSIZE_STR, SETSIZE_SIG); 3426 jmethodID setImageableID = env->GetMethodID(paperClass, 3427 SETIMAGEABLE_STR, SETIMAGEABLE_SIG); 3428 3429 /* Set the physical size of the paper. 3430 */ 3431 jdouble paperWidth = convertToPoints(paperSize->x, units); 3432 jdouble paperHeight = convertToPoints(paperSize->y, units); 3433 env->CallVoidMethod(paper, setSizeID, paperWidth, paperHeight); 3434 3435 /* Set the margins of the paper. In Windows' margin RECT, 3436 * the right and bottom parts of the structure are not 3437 * really the right and bottom of the imageable rectangle, 3438 * but rather the right and bottom margins. 3439 */ 3440 jdouble x = convertToPoints(margins->left, units); 3441 jdouble y = convertToPoints(margins->top, units); 3442 long intWidth = paperSize->x - margins->left - margins->right; 3443 long intHeight = paperSize->y - margins->top - margins->bottom; 3444 jdouble width = convertToPoints(intWidth, units); 3445 jdouble height = convertToPoints(intHeight, units); 3446 env->CallVoidMethod(paper, setImageableID, x, y, width, height); 3447 3448 } 3449 3450 /** 3451 * Convert 'value' a measurement in 1/72's of an inch to 3452 * the units specified by 'units' - either MM_HIENGLISH 3453 * MM_HIMETRIC, or MM_LOMETRIC. The converted value is returned as 3454 * a long. 3455 */ 3456 static long convertFromPoints(double value, int units) { 3457 double conversion = 0; 3458 3459 switch (units){ 3460 case MM_HIENGLISH: 3461 conversion = POINTS_TO_HIENGLISH; 3462 break; 3463 3464 case MM_HIMETRIC: 3465 conversion = POINTS_TO_HIMETRIC; 3466 break; 3467 3468 case MM_LOMETRIC: 3469 conversion = POINTS_TO_LOMETRIC; 3470 break; 3471 3472 default: 3473 assert(FALSE); // Unsupported unit. 3474 } 3475 3476 // Adding 0.5 ensures that the integer portion has the expected magnitude 3477 // before truncation occurs as result of converting from double to long. 3478 return (long) ((value * conversion) + 0.5); 3479 } 3480 3481 /** 3482 * Convert a measurement, 'value', from the units 3483 * specified by 'units', either MM_HIENGLISH or 3484 * MM_HIMETRIC to 1/72's of an inch and returned 3485 * as a double. 3486 */ 3487 static double convertToPoints(long value, int units) { 3488 double convertedValue = (double)value; 3489 3490 switch (units){ 3491 case MM_HIENGLISH: 3492 //convertedValue *= HIENGLISH_TO_POINTS; 3493 // this order of calculation is for bug 4191615 3494 convertedValue = (convertedValue*72.0) / 1000.0; 3495 break; 3496 3497 case MM_HIMETRIC: 3498 convertedValue *= HIMETRIC_TO_POINTS; 3499 break; 3500 3501 case MM_LOMETRIC: 3502 convertedValue *= LOMETRIC_TO_POINTS; 3503 break; 3504 3505 default: 3506 assert(FALSE); // Unsupported unit. 3507 } 3508 3509 //Need to round off to the precision of the initial value. FIX. 3510 3511 return convertedValue; 3512 } 3513 3514 /** 3515 * Ask the printer device context, 'printDC' about 3516 * its capabilities and set these into the WPrintJob2D 3517 * object 'self'. 3518 */ 3519 void setCapabilities(JNIEnv *env, jobject self, HDC printDC) { 3520 3521 // width of page in pixels 3522 jint pageWid = GetDeviceCaps(printDC, PHYSICALWIDTH); 3523 setIntField(env, self, PAGEW_STR, pageWid); 3524 3525 // height of page in pixels 3526 jint pageHgt = GetDeviceCaps(printDC, PHYSICALHEIGHT); 3527 setIntField(env, self, PAGEH_STR, pageHgt); 3528 3529 // x scaling factor of printer 3530 jint xsf = GetDeviceCaps(printDC, SCALINGFACTORX); 3531 3532 // x scaling factor of printer 3533 jint ysf = GetDeviceCaps(printDC, SCALINGFACTORY); 3534 3535 if (getOrientationFromDevMode(env, self) == DMORIENT_LANDSCAPE) { 3536 // because we do our own rotation, we should force 3537 // orientation to portrait so we will get correct page dimensions. 3538 3539 HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, self); 3540 if (hDevMode != NULL) { 3541 DEVMODE *devmode = (DEVMODE*)::GlobalLock(hDevMode); 3542 if (devmode != NULL) { 3543 devmode->dmFields |= DM_ORIENTATION; 3544 devmode->dmOrientation = DMORIENT_PORTRAIT; 3545 SAVE_CONTROLWORD 3546 ::ResetDC(printDC, devmode); 3547 RESTORE_CONTROLWORD 3548 } 3549 GlobalUnlock(hDevMode); 3550 } 3551 } 3552 3553 // pixels per inch in x direction 3554 jint xRes = GetDeviceCaps(printDC, LOGPIXELSX); 3555 setIntField(env, self, XRES_STR, xRes); 3556 3557 // pixels per inch in y direction 3558 jint yRes = GetDeviceCaps(printDC, LOGPIXELSY); 3559 setIntField(env, self, YRES_STR, yRes); 3560 3561 // x coord of printable area in pixels 3562 jint xOrg = GetDeviceCaps(printDC, PHYSICALOFFSETX); 3563 setIntField(env, self, PHYSX_STR, xOrg); 3564 3565 // y coord of printable area in pixels 3566 jint yOrg = GetDeviceCaps(printDC, PHYSICALOFFSETY); 3567 setIntField(env, self, PHYSY_STR, yOrg); 3568 3569 // width of printable area in pixels 3570 jint printWid = GetDeviceCaps(printDC, HORZRES); 3571 setIntField(env, self, PHYSW_STR, printWid); 3572 3573 // height of printable area in pixels 3574 jint printHgt = GetDeviceCaps(printDC, VERTRES); 3575 setIntField(env, self, PHYSH_STR, printHgt); 3576 3577 } 3578 3579 3580 static inline WORD getPrintPaperSize(JNIEnv *env, jobject self) { 3581 return (WORD)getIntField(env, self, PRINTPAPERSIZE_STR); 3582 } 3583 3584 static inline void setPrintPaperSize(JNIEnv *env, jobject self, WORD sz) { 3585 setIntField(env, self, PRINTPAPERSIZE_STR, (jint)sz); 3586 } 3587 3588 /** 3589 * Return the java int value of the field 'fieldName' in the 3590 * java instance 'self'. 3591 */ 3592 static jint getIntField(JNIEnv *env, jobject self, const char *fieldName) { 3593 jfieldID fieldId = getIdOfIntField(env, self, fieldName); 3594 return env->GetIntField(self, fieldId); 3595 } 3596 3597 /** 3598 * Return the java long value of the field 'fieldName' in the 3599 * java instance 'self'. 3600 */ 3601 static jlong getLongField(JNIEnv *env, jobject self, const char *fieldName) { 3602 jfieldID fieldId = getIdOfLongField(env, self, fieldName); 3603 return env->GetLongField(self, fieldId); 3604 } 3605 3606 /** 3607 * Set the int field named 'fieldName' of the java instance 3608 * 'self' to the value 'value'. 3609 */ 3610 static void setIntField(JNIEnv *env, jobject self, const char *fieldName, 3611 jint value) { 3612 jfieldID fieldId = getIdOfIntField(env, self, fieldName); 3613 env->SetIntField(self, fieldId, value); 3614 } 3615 3616 /** 3617 * Set the long field named 'fieldName' of the java instance 3618 * 'self' to the value 'value'. 3619 */ 3620 static void setLongField(JNIEnv *env, jobject self, const char *fieldName, 3621 jlong value) { 3622 jfieldID fieldId = getIdOfLongField(env, self, fieldName); 3623 env->SetLongField(self, fieldId, value); 3624 } 3625 3626 /** 3627 * Return the field id of the java instance 'self' of the 3628 * java int field named 'fieldName'. 3629 */ 3630 static jfieldID getIdOfIntField(JNIEnv *env, jobject self, 3631 const char *fieldName) { 3632 jclass myClass = env->GetObjectClass(self); 3633 jfieldID fieldId = env->GetFieldID(myClass, fieldName, kJavaIntStr); 3634 DASSERT(fieldId != 0); 3635 3636 return fieldId; 3637 3638 } 3639 3640 /** 3641 * Return the field id of the java instance 'self' of the 3642 * java long field named 'fieldName'. 3643 */ 3644 static jfieldID getIdOfLongField(JNIEnv *env, jobject self, 3645 const char *fieldName) { 3646 jclass myClass = env->GetObjectClass(self); 3647 jfieldID fieldId = env->GetFieldID(myClass, fieldName, kJavaLongStr); 3648 DASSERT(fieldId != 0); 3649 3650 return fieldId; 3651 3652 } 3653 3654 static void setBooleanField(JNIEnv *env, jobject self, const char *fieldName, 3655 jboolean value) { 3656 jclass myClass = env->GetObjectClass(self); 3657 jfieldID fieldId = env->GetFieldID(myClass, fieldName, "Z"); 3658 DASSERT(fieldId != 0); 3659 env->SetBooleanField(self, fieldId, value); 3660 } 3661 3662 /** 3663 * Throw a PrinterException with a string describing 3664 * the Window's system error 'err'. 3665 */ 3666 static void throwPrinterException(JNIEnv *env, DWORD err) { 3667 char errStr[256]; 3668 TCHAR t_errStr[256]; 3669 jclass printerException = env->FindClass(PRINTEREXCEPTION_STR); 3670 3671 errStr[0] = '\0'; 3672 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 3673 NULL, 3674 err, 3675 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 3676 t_errStr, 3677 sizeof(t_errStr), 3678 NULL ); 3679 3680 WideCharToMultiByte(CP_UTF8, 0, t_errStr, -1, 3681 errStr, sizeof(errStr), NULL, NULL); 3682 env->ThrowNew(printerException, errStr); 3683 } 3684 3685 3686 /* 3687 * Finds the closest matching paper size for the printer. 3688 * Parameters are in 72ndths of an inch. 3689 * paperSize is the win32 integer identifier for a paper size. 3690 * Requires an initialised set of printer device structures. 3691 * Updates the printDC to specify the matched paper size. 3692 * If the passed in paper size is non-zero, its taken to be a windows 3693 * paper size "name", and we check that paper size against the paper 3694 * we are matching and prefer that name over other names which also match 3695 * the size. 3696 */ 3697 static void matchPaperSize(HDC printDC, HGLOBAL hDevMode, HGLOBAL hDevNames, 3698 double origWid, double origHgt, 3699 double* newWid, double *newHgt, 3700 WORD* paperSize) { 3701 3702 // Tolerated differences in comparing page dimensions between passed in 3703 // "orig" media with that of Windows' device. 3704 const double epsilon = 3.6; // (1/72) of an inch 3705 const double tolerance = (1.0 * 72.0); // # inches * 72 3706 3707 *newWid = origWid; 3708 *newHgt = origHgt; 3709 3710 /* 1st check if the DC/Devmode has as its current papersize a paper 3711 * which matches the paper specified. If yes, then we can skip hunting 3712 * for the match and in the process we avoid finding a "name" for 3713 * the paper size which isn't the one the user specified in the page 3714 * setup dialog. For example "11x17" is also "Ledger". 3715 */ 3716 if (printDC != NULL) { 3717 // pixels per inch in x and y direction 3718 jint xPixelRes = GetDeviceCaps(printDC, LOGPIXELSX); 3719 jint yPixelRes = GetDeviceCaps(printDC, LOGPIXELSY); 3720 3721 // width and height of page in pixels 3722 jint pagePixelWid = GetDeviceCaps(printDC, PHYSICALWIDTH); 3723 jint pagePixelHgt = GetDeviceCaps(printDC, PHYSICALHEIGHT); 3724 3725 // page size in 1/72" 3726 jdouble paperWidth = (jdouble)((pagePixelWid * 72)/(jdouble)xPixelRes); 3727 jdouble paperHeight = (jdouble)((pagePixelHgt * 72)/(jdouble)yPixelRes); 3728 3729 if ((fabs(origWid - paperWidth) < epsilon) && 3730 (fabs(origHgt - paperHeight) < epsilon) && 3731 (*paperSize == 0)) { 3732 3733 *newWid = origWid; 3734 *newHgt = origHgt; 3735 3736 if (hDevMode != NULL) { 3737 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 3738 if (devmode != NULL && (devmode->dmFields & DM_PAPERSIZE)) { 3739 *paperSize = devmode->dmPaperSize; 3740 } 3741 ::GlobalUnlock(hDevMode); 3742 } 3743 return; 3744 } 3745 } 3746 3747 /* begin trying to match papers */ 3748 3749 LPTSTR printer = NULL, port = NULL; 3750 if (hDevNames != NULL) { 3751 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); 3752 if (devnames != NULL) { 3753 LPTSTR lpdevnames = (LPTSTR)devnames; 3754 printer = _tcsdup(lpdevnames+devnames->wDeviceOffset); 3755 port = _tcsdup(lpdevnames+devnames->wOutputOffset); 3756 } 3757 ::GlobalUnlock(hDevNames); 3758 } 3759 3760 //REMIND: code duplicated in AwtPrintControl::getNearestMatchingPaper 3761 int numPaperSizes = 0; 3762 WORD *papers = NULL; 3763 POINT *paperSizes = NULL; 3764 3765 SAVE_CONTROLWORD 3766 numPaperSizes = (int)DeviceCapabilities(printer, port, DC_PAPERSIZE, 3767 NULL, NULL); 3768 if (numPaperSizes > 0) { 3769 papers = (WORD*)safe_Malloc(sizeof(WORD) * numPaperSizes); 3770 paperSizes = (POINT *)safe_Malloc(sizeof(*paperSizes) * numPaperSizes); 3771 3772 DWORD result1 = DeviceCapabilities(printer, port, 3773 DC_PAPERS, (LPTSTR) papers, NULL); 3774 DWORD result2 = DeviceCapabilities(printer, port, 3775 DC_PAPERSIZE, (LPTSTR) paperSizes, 3776 NULL); 3777 3778 if (result1 == -1 || result2 == -1 ) { 3779 free((char *) papers); 3780 papers = NULL; 3781 free((char *) paperSizes); 3782 paperSizes = NULL; 3783 } 3784 } 3785 3786 RESTORE_CONTROLWORD 3787 double closestWid = 0.0; 3788 double closestHgt = 0.0; 3789 WORD closestMatch = 0; 3790 3791 if (paperSizes != NULL) { 3792 3793 /* Paper sizes are in 0.1mm units. Convert to 1/72" 3794 * For each paper size, compute the difference from the paper size 3795 * passed in. Use a least-squares difference, so paper much different 3796 * in x or y should score poorly 3797 */ 3798 double diffw = origWid; 3799 double diffh = origHgt; 3800 double least_square = diffw * diffw + diffh * diffh; 3801 double tmp_ls; 3802 double widpts, hgtpts; 3803 3804 for (int i=0;i<numPaperSizes;i++) { 3805 widpts = paperSizes[i].x * LOMETRIC_TO_POINTS; 3806 hgtpts = paperSizes[i].y * LOMETRIC_TO_POINTS; 3807 3808 if ((fabs(origWid - widpts) < epsilon) && 3809 (fabs(origHgt - hgtpts) < epsilon)) { 3810 3811 if ((*paperSize == 0) || ((*paperSize !=0) && 3812 (papers[i]==*paperSize))) { 3813 closestWid = origWid; 3814 closestHgt = origHgt; 3815 closestMatch = papers[i]; 3816 break; 3817 } 3818 } 3819 3820 diffw = fabs(widpts - origWid); 3821 diffh = fabs(hgtpts - origHgt); 3822 tmp_ls = diffw * diffw + diffh * diffh; 3823 if ((diffw < tolerance) && (diffh < tolerance) && 3824 (tmp_ls < least_square)) { 3825 least_square = tmp_ls; 3826 closestWid = widpts; 3827 closestHgt = hgtpts; 3828 closestMatch = papers[i]; 3829 } 3830 } 3831 } 3832 3833 if (closestWid > 0) { 3834 *newWid = closestWid; 3835 } 3836 if (closestHgt > 0) { 3837 *newHgt = closestHgt; 3838 } 3839 3840 *paperSize = closestMatch; 3841 3842 /* At this point we have the paper which is the closest match 3843 * We now need to select the paper into the DEVMODE, and 3844 * get a DC which matches so we can get the margins. 3845 */ 3846 3847 if ((printDC != NULL) && (hDevMode != NULL) && (closestMatch != 0)) { 3848 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 3849 if ((devmode != NULL) && (closestMatch != devmode->dmPaperSize)) { 3850 devmode->dmFields |= DM_PAPERSIZE; 3851 devmode->dmPaperSize = closestMatch; 3852 ::ResetDC(printDC, devmode); 3853 RESTORE_CONTROLWORD 3854 } 3855 ::GlobalUnlock(hDevMode); 3856 } 3857 3858 if (printer != NULL) { 3859 free((char *)printer); 3860 } 3861 if (port != NULL) { 3862 free((char *)port); 3863 } 3864 if (papers != NULL) { 3865 free((char *)papers); 3866 } 3867 if (paperSizes != NULL) { 3868 free((char *)paperSizes); 3869 } 3870 3871 } 3872 3873 3874 static BOOL SetPrinterDevice(LPTSTR pszDeviceName, HGLOBAL* p_hDevMode, 3875 HGLOBAL* p_hDevNames) 3876 { 3877 // Open printer and obtain PRINTER_INFO_2 structure. 3878 HANDLE hPrinter; 3879 if (::OpenPrinter(pszDeviceName, &hPrinter, NULL) == FALSE) 3880 return FALSE; 3881 3882 DWORD dwBytesReturned, dwBytesNeeded; 3883 ::GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded); 3884 PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)::GlobalAlloc(GPTR, 3885 dwBytesNeeded); 3886 if (p2 == NULL) { 3887 ::ClosePrinter(hPrinter); 3888 return FALSE; 3889 } 3890 3891 if (::GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded, 3892 &dwBytesReturned) == 0) { 3893 ::GlobalFree(p2); 3894 ::ClosePrinter(hPrinter); 3895 return FALSE; 3896 } 3897 3898 DEVMODE *pDevMode = NULL; 3899 HGLOBAL hDevMode = NULL; 3900 /* If GetPrinter didn't fill in the DEVMODE, try to get it by calling 3901 DocumentProperties... 3902 */ 3903 if (p2->pDevMode == NULL){ 3904 SAVE_CONTROLWORD 3905 LONG bytesNeeded = ::DocumentProperties(NULL, hPrinter, 3906 pszDeviceName, 3907 NULL, NULL, 0); 3908 RESTORE_CONTROLWORD 3909 3910 if (bytesNeeded <= 0) { 3911 ::GlobalFree(p2); 3912 ::ClosePrinter(hPrinter); 3913 return FALSE; 3914 } 3915 3916 hDevMode = ::GlobalAlloc(GHND, bytesNeeded); 3917 if (hDevMode == NULL) { 3918 ::GlobalFree(p2); 3919 ::ClosePrinter(hPrinter); 3920 return FALSE; 3921 } 3922 3923 pDevMode = (DEVMODE*)::GlobalLock(hDevMode); 3924 if (pDevMode == NULL) { 3925 ::GlobalFree(hDevMode); 3926 ::GlobalFree(p2); 3927 ::ClosePrinter(hPrinter); 3928 return FALSE; 3929 } 3930 3931 LONG lFlag = ::DocumentProperties(NULL, hPrinter, 3932 pszDeviceName, 3933 pDevMode, NULL, 3934 DM_OUT_BUFFER); 3935 RESTORE_CONTROLWORD 3936 if (lFlag != IDOK) { 3937 ::GlobalUnlock(hDevMode); 3938 ::GlobalFree(hDevMode); 3939 ::GlobalFree(p2); 3940 ::ClosePrinter(hPrinter); 3941 return FALSE; 3942 } 3943 3944 } else { 3945 // Allocate a global handle for DEVMODE and copy DEVMODE data. 3946 hDevMode = ::GlobalAlloc(GHND, 3947 (sizeof(*p2->pDevMode) + p2->pDevMode->dmDriverExtra)); 3948 if (hDevMode == NULL) { 3949 ::GlobalFree(p2); 3950 ::ClosePrinter(hPrinter); 3951 return FALSE; 3952 } 3953 3954 pDevMode = (DEVMODE*)::GlobalLock(hDevMode); 3955 if (pDevMode == NULL) { 3956 ::GlobalFree(hDevMode); 3957 ::GlobalFree(p2); 3958 ::ClosePrinter(hPrinter); 3959 return FALSE; 3960 } 3961 3962 memcpy(pDevMode, p2->pDevMode, 3963 sizeof(*p2->pDevMode) + p2->pDevMode->dmDriverExtra); 3964 } 3965 3966 ::GlobalUnlock(hDevMode); 3967 ::ClosePrinter(hPrinter); 3968 3969 // Compute size of DEVNAMES structure you'll need. 3970 // All sizes are WORD as in DEVNAMES structure 3971 // All offsets are in characters, not in bytes 3972 WORD drvNameLen = static_cast<WORD>(_tcslen(p2->pDriverName)); // driver name 3973 WORD ptrNameLen = static_cast<WORD>(_tcslen(p2->pPrinterName)); // printer name 3974 WORD porNameLen = static_cast<WORD>(_tcslen(p2->pPortName)); // port name 3975 WORD devNameSize = static_cast<WORD>(sizeof(DEVNAMES)) + 3976 (ptrNameLen + porNameLen + drvNameLen + 3)*sizeof(TCHAR); 3977 3978 // Allocate a global handle big enough to hold DEVNAMES. 3979 HGLOBAL hDevNames = ::GlobalAlloc(GHND, devNameSize); 3980 DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); 3981 3982 // Copy the DEVNAMES information from PRINTER_INFO_2 structure. 3983 pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(TCHAR); 3984 memcpy((LPTSTR)pDevNames + pDevNames->wDriverOffset, 3985 p2->pDriverName, drvNameLen*sizeof(TCHAR)); 3986 3987 pDevNames->wDeviceOffset = static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR)) + 3988 drvNameLen + 1; 3989 memcpy((LPTSTR)pDevNames + pDevNames->wDeviceOffset, 3990 p2->pPrinterName, ptrNameLen*sizeof(TCHAR)); 3991 3992 pDevNames->wOutputOffset = static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR)) + 3993 drvNameLen + ptrNameLen + 2; 3994 memcpy((LPTSTR)pDevNames + pDevNames->wOutputOffset, 3995 p2->pPortName, porNameLen*sizeof(TCHAR)); 3996 3997 pDevNames->wDefault = 0; 3998 3999 ::GlobalUnlock(hDevNames); 4000 ::GlobalFree(p2); // free PRINTER_INFO_2 4001 4002 *p_hDevMode = hDevMode; 4003 *p_hDevNames = hDevNames; 4004 4005 return TRUE; 4006 } 4007 4008 4009 JNIEXPORT void JNICALL 4010 Java_sun_awt_windows_WPrinterJob_setNativePrintService(JNIEnv *env, 4011 jobject name, 4012 jstring printer) 4013 { 4014 TRY; 4015 LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, 4016 printer, NULL); 4017 HDC hDC = AwtPrintControl::getPrintDC(env, name); 4018 if (hDC != NULL) { 4019 DeletePrintDC(hDC); 4020 hDC = NULL; 4021 } 4022 4023 SAVE_CONTROLWORD 4024 hDC = ::CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL); 4025 RESTORE_CONTROLWORD 4026 if (hDC == NULL) { 4027 jclass printerException = env->FindClass(PRINTEREXCEPTION_STR); 4028 env->ThrowNew(printerException, "Invalid name of PrintService."); 4029 JNU_ReleaseStringPlatformChars(env, printer, printerName); 4030 return; 4031 } 4032 AwtPrintControl::setPrintDC(env, name, hDC); 4033 4034 HANDLE hDevMode = AwtPrintControl::getPrintHDMode(env, name); 4035 if (hDevMode != NULL) { 4036 ::GlobalFree(hDevMode); 4037 hDevMode = NULL; 4038 } 4039 4040 HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, name);; 4041 if (hDevNames != NULL) { 4042 ::GlobalFree(hDevNames); 4043 hDevNames = NULL; 4044 } 4045 4046 SetPrinterDevice(printerName, &hDevMode, &hDevNames); 4047 4048 AwtPrintControl::setPrintHDMode(env, name, hDevMode); 4049 AwtPrintControl::setPrintHDName(env, name, hDevNames); 4050 4051 // Driver capability for copies & collation are not set 4052 // when printDialog and getDefaultPrinterDC are not called. 4053 // set DRIVER_COPIES_STR and DRIVER_COLLATE_STR 4054 DEVMODE *devmode = NULL; 4055 if (hDevMode != NULL) { 4056 devmode = (DEVMODE *)::GlobalLock(hDevMode); 4057 DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE))); 4058 } 4059 4060 if (devmode != NULL) { 4061 if (devmode->dmFields & DM_COPIES) { 4062 setBooleanField(env, name, DRIVER_COPIES_STR, JNI_TRUE); 4063 } 4064 4065 if (devmode->dmFields & DM_COLLATE) { 4066 setBooleanField(env, name, DRIVER_COLLATE_STR, JNI_TRUE); 4067 } 4068 4069 ::GlobalUnlock(hDevMode); 4070 } 4071 4072 setCapabilities(env, name, hDC); 4073 4074 JNU_ReleaseStringPlatformChars(env, printer, printerName); 4075 CATCH_BAD_ALLOC; 4076 4077 } 4078 4079 4080 JNIEXPORT jstring JNICALL 4081 Java_sun_awt_windows_WPrinterJob_getNativePrintService(JNIEnv *env, 4082 jobject name) 4083 { 4084 TRY; 4085 jstring printer; 4086 HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, name); 4087 if (hDevNames == NULL) { 4088 return NULL; 4089 } 4090 DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); 4091 4092 printer = JNU_NewStringPlatform(env, 4093 (LPTSTR)pDevNames+pDevNames->wDeviceOffset); 4094 ::GlobalUnlock(hDevNames); 4095 return printer; 4096 4097 CATCH_BAD_ALLOC_RET(0); 4098 } 4099 4100 static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin) 4101 { 4102 if (pdc == NULL) { 4103 return FALSE; 4104 } 4105 4106 DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(hDevMode); 4107 if (pDevMode == NULL) { 4108 return FALSE; 4109 } 4110 4111 SAVE_CONTROLWORD 4112 ::ResetDC(pdc, pDevMode); 4113 RESTORE_CONTROLWORD 4114 4115 int left = GetDeviceCaps(pdc, PHYSICALOFFSETX); 4116 int top = GetDeviceCaps(pdc, PHYSICALOFFSETY); 4117 int width = GetDeviceCaps(pdc, HORZRES); 4118 int height = GetDeviceCaps(pdc, VERTRES); 4119 int resx = GetDeviceCaps(pdc, LOGPIXELSX); 4120 int resy = GetDeviceCaps(pdc, LOGPIXELSY); 4121 4122 4123 margin->x = (jdouble)left/resx; 4124 margin->y =(jdouble)top/resy; 4125 margin->width = (jdouble)width/resx; 4126 margin->height = (jdouble)height/resy; 4127 4128 ::GlobalUnlock(hDevMode); 4129 4130 return TRUE; 4131 } 4132 4133 JNIEXPORT void JNICALL 4134 Java_sun_awt_windows_WPrinterJob_initIDs(JNIEnv *env, jclass cls) 4135 { 4136 TRY; 4137 4138 AwtPrintDialog::controlID = 4139 env->GetFieldID(cls, "pjob", "Ljava/awt/print/PrinterJob;"); 4140 jclass printDialogPeerClass = env->FindClass("Lsun/awt/windows/WPrintDialogPeer;"); 4141 AwtPrintDialog::setHWndMID = 4142 env->GetMethodID(printDialogPeerClass, "setHWnd", "(J)V"); 4143 4144 DASSERT(AwtPrintDialog::controlID != NULL); 4145 DASSERT(AwtPrintDialog::setHWndMID != NULL); 4146 4147 AwtPrintControl::initIDs(env, cls); 4148 CATCH_BAD_ALLOC; 4149 } 4150 4151 } /* extern "C" */