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