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