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 && ::IsWindow(parentID)) { 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 /* This code is rarely used now. It used to be invoked by Java plugin browser 1743 * printing. Today embedded frames are used only when a toolkit such as SWT 1744 * needs to embed 1745 */ 1746 TRY; 1747 jbyte *image = NULL; 1748 try { 1749 int length = env->GetArrayLength(imageArray); 1750 image = new jbyte[length]; 1751 CHECK_NULL(image); 1752 env->GetByteArrayRegion(imageArray, 0, length, image); 1753 1754 struct { 1755 BITMAPINFOHEADER bmiHeader; 1756 DWORD* bmiColors; 1757 } bitMapHeader; 1758 1759 memset(&bitMapHeader,0,sizeof(bitMapHeader)); 1760 bitMapHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 1761 bitMapHeader.bmiHeader.biWidth = srcWidth; 1762 bitMapHeader.bmiHeader.biHeight = srcHeight; 1763 bitMapHeader.bmiHeader.biPlanes = 1; 1764 bitMapHeader.bmiHeader.biBitCount = 24; 1765 bitMapHeader.bmiHeader.biCompression = BI_RGB; 1766 1767 int result = 1768 ::StretchDIBits(hDC, 1769 destX, // left of dest rect 1770 destY, // top of dest rect 1771 destWidth, // width of dest rect 1772 destHeight, // height of dest rect 1773 srcX, // left of source rect 1774 srcY, // top of source rect 1775 srcWidth, // number of 1st source scan line 1776 srcHeight, // number of source scan lines 1777 image+offset, // points to the DIB 1778 (BITMAPINFO *)&bitMapHeader, 1779 DIB_RGB_COLORS, 1780 SRCCOPY); 1781 #if DEBUG_PRINTING 1782 FILE *file = fopen("c:\\plog.txt", "a"); 1783 fprintf(file,"sh=%d dh=%d sy=%d dy=%d result=%d\n", srcHeight, destHeight, srcY, destY, result); 1784 fclose(file); 1785 #endif //DEBUG_PRINTING 1786 } catch (...) { 1787 delete[] image; 1788 throw; 1789 } 1790 1791 delete[] image; 1792 1793 CATCH_BAD_ALLOC; 1794 } 1795 1796 /* 1797 * Class: sun_awt_windows_WPrinterJob 1798 * Method: printBand 1799 * Signature: ([BIIII)V 1800 */ 1801 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_printBand 1802 (JNIEnv *env, jobject self, jbyteArray imageArray, jint x, jint y, 1803 jint width, jint height) { 1804 1805 HDC printDC = AwtPrintControl::getPrintDC(env, self); 1806 doPrintBand(env, JNI_FALSE, printDC, imageArray, x, y, width, height); 1807 } 1808 1809 /* 1810 * Class: sun_awt_windows_WPrinterJob 1811 * Method: beginPath 1812 * Signature: (J)V 1813 */ 1814 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_beginPath 1815 (JNIEnv *env , jobject self, jlong printDC) { 1816 TRY; 1817 1818 (void) ::BeginPath((HDC)printDC); 1819 1820 CATCH_BAD_ALLOC; 1821 } 1822 1823 /* 1824 * Class: sun_awt_windows_WPrinterJob 1825 * Method: endPath 1826 * Signature: (J)V 1827 */ 1828 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_endPath 1829 (JNIEnv *env, jobject self, jlong printDC) { 1830 TRY; 1831 1832 (void) ::EndPath((HDC)printDC); 1833 1834 CATCH_BAD_ALLOC; 1835 } 1836 1837 /* 1838 * Class: sun_awt_windows_WPrinterJob 1839 * Method: fillPath 1840 * Signature: (J)V 1841 */ 1842 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_fillPath 1843 (JNIEnv *env, jobject self, jlong printDC) { 1844 TRY; 1845 1846 (void) ::FillPath((HDC)printDC); 1847 1848 CATCH_BAD_ALLOC; 1849 } 1850 1851 /* 1852 * Class: sun_awt_windows_WPrinterJob 1853 * Method: closeFigure 1854 * Signature: (J)V 1855 */ 1856 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_closeFigure 1857 (JNIEnv *env, jobject self, jlong printDC) { 1858 TRY; 1859 1860 (void) ::CloseFigure((HDC)printDC); 1861 1862 CATCH_BAD_ALLOC; 1863 } 1864 1865 /* 1866 * Class: sun_awt_windows_WPrinterJob 1867 * Method: lineTo 1868 * Signature: (JFF)V 1869 */ 1870 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_lineTo 1871 (JNIEnv *env, jobject self, jlong printDC, jfloat x, jfloat y) { 1872 TRY; 1873 1874 (void) ::LineTo((HDC)printDC, ROUND_TO_LONG(x), ROUND_TO_LONG(y)); 1875 1876 CATCH_BAD_ALLOC; 1877 } 1878 1879 1880 /* 1881 * Class: sun_awt_windows_WPrinterJob 1882 * Method: moveTo 1883 * Signature: (JFF)V 1884 */ 1885 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_moveTo 1886 (JNIEnv *env, jobject self, jlong printDC, jfloat x, jfloat y) { 1887 TRY; 1888 1889 (void) ::MoveToEx((HDC)printDC, ROUND_TO_LONG(x), ROUND_TO_LONG(y), NULL); 1890 1891 CATCH_BAD_ALLOC; 1892 } 1893 1894 /* 1895 * Class: sun_awt_windows_WPrinterJob 1896 * Method: polyBezierTo 1897 * Signature: (JFFFFFF)V 1898 */ 1899 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_polyBezierTo 1900 (JNIEnv *env, jobject self, jlong printDC, 1901 jfloat control1x, jfloat control1y, 1902 jfloat control2x, jfloat control2y, 1903 jfloat endX, jfloat endY) { 1904 1905 TRY; 1906 1907 POINT points[3]; 1908 1909 points[0].x = ROUND_TO_LONG(control1x); 1910 points[0].y = ROUND_TO_LONG(control1y); 1911 points[1].x = ROUND_TO_LONG(control2x); 1912 points[1].y = ROUND_TO_LONG(control2y); 1913 points[2].x = ROUND_TO_LONG(endX); 1914 points[2].y = ROUND_TO_LONG(endY); 1915 1916 (void) ::PolyBezierTo((HDC)printDC, points, 3); 1917 1918 CATCH_BAD_ALLOC; 1919 } 1920 1921 /* 1922 * Class: sun_awt_windows_WPrinterJob 1923 * Method: setPolyFillMode 1924 * Signature: (JI)V 1925 */ 1926 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setPolyFillMode 1927 (JNIEnv *env, jobject self, jlong printDC, jint fillRule) { 1928 TRY; 1929 1930 (void) ::SetPolyFillMode((HDC)printDC, fillRule); 1931 1932 CATCH_BAD_ALLOC; 1933 } 1934 1935 /* 1936 * Class: sun_awt_windows_WPrinterJob 1937 * Method: selectSolidBrush 1938 * Signature: (JIII)V 1939 */ 1940 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectSolidBrush 1941 (JNIEnv *env, jobject self, jlong printDC, jint red, jint green, jint blue) { 1942 1943 TRY; 1944 1945 HBRUSH colorBrush = ::CreateSolidBrush(RGB(red, green, blue)); 1946 HBRUSH oldBrush = (HBRUSH)::SelectObject((HDC)printDC, colorBrush); 1947 DeleteObject(oldBrush); 1948 1949 CATCH_BAD_ALLOC; 1950 } 1951 1952 /* 1953 * Class: sun_awt_windows_WPrinterJob 1954 * Method: getPenX 1955 * Signature: (J)I 1956 */ 1957 JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getPenX 1958 (JNIEnv *env, jobject self, jlong printDC) { 1959 1960 TRY; 1961 1962 POINT where; 1963 ::GetCurrentPositionEx((HDC)printDC, &where); 1964 1965 return (jint) where.x; 1966 1967 CATCH_BAD_ALLOC_RET(0); 1968 } 1969 1970 /* 1971 * Class: sun_awt_windows_WPrinterJob 1972 * Method: getPenY 1973 * Signature: (J)I 1974 */ 1975 JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getPenY 1976 (JNIEnv *env, jobject self, jlong printDC) { 1977 1978 TRY; 1979 1980 POINT where; 1981 ::GetCurrentPositionEx((HDC)printDC, &where); 1982 1983 return (jint) where.y; 1984 1985 CATCH_BAD_ALLOC_RET(0); 1986 } 1987 1988 /* 1989 * Class: sun_awt_windows_WPrinterJob 1990 * Method: selectClipPath 1991 * Signature: (J)V 1992 */ 1993 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectClipPath 1994 (JNIEnv *env, jobject self, jlong printDC) { 1995 1996 TRY; 1997 1998 ::SelectClipPath((HDC)printDC, RGN_COPY); 1999 2000 CATCH_BAD_ALLOC; 2001 } 2002 2003 2004 /* 2005 * Class: sun_awt_windows_WPrinterJob 2006 * Method: frameRect 2007 * Signature: (JFFFF)V 2008 */ 2009 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_frameRect 2010 (JNIEnv *env, jobject self, jlong printDC, 2011 jfloat x, jfloat y, jfloat width, jfloat height) { 2012 2013 TRY; 2014 2015 POINT points[5]; 2016 2017 points[0].x = ROUND_TO_LONG(x); 2018 points[0].y = ROUND_TO_LONG(y); 2019 points[1].x = ROUND_TO_LONG(x+width); 2020 points[1].y = ROUND_TO_LONG(y); 2021 points[2].x = ROUND_TO_LONG(x+width); 2022 points[2].y = ROUND_TO_LONG(y+height); 2023 points[3].x = ROUND_TO_LONG(x); 2024 points[3].y = ROUND_TO_LONG(y+height); 2025 points[4].x = ROUND_TO_LONG(x); 2026 points[4].y = ROUND_TO_LONG(y); 2027 2028 ::Polyline((HDC)printDC, points, sizeof(points)/sizeof(points[0])); 2029 2030 CATCH_BAD_ALLOC; 2031 } 2032 2033 /* 2034 * Class: sun_awt_windows_WPrinterJob 2035 * Method: fillRect 2036 * Signature: (JFFFFIII)V 2037 */ 2038 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_fillRect 2039 (JNIEnv *env, jobject self, jlong printDC, 2040 jfloat x, jfloat y, jfloat width, jfloat height, 2041 jint red, jint green, jint blue) { 2042 2043 TRY; 2044 2045 RECT rect; 2046 rect.left = ROUND_TO_LONG(x); 2047 rect.top = ROUND_TO_LONG(y); 2048 rect.right = ROUND_TO_LONG(x+width); 2049 rect.bottom = ROUND_TO_LONG(y+height); 2050 2051 HBRUSH brush = ::CreateSolidBrush(RGB(red, green, blue)); 2052 2053 if (brush != NULL) { 2054 ::FillRect((HDC)printDC, (LPRECT) &rect, brush); 2055 DeleteObject(brush); 2056 } 2057 2058 CATCH_BAD_ALLOC; 2059 } 2060 2061 2062 /* 2063 * Class: sun_awt_windows_WPrinterJob 2064 * Method: selectPen 2065 * Signature: (JFIII)V 2066 */ 2067 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_selectPen 2068 (JNIEnv *env, jobject self, jlong printDC, jfloat width, 2069 jint red, jint green, jint blue) { 2070 2071 TRY; 2072 2073 HPEN hpen = ::CreatePen(PS_SOLID, ROUND_TO_LONG(width), 2074 RGB(red, green, blue)); 2075 2076 if (hpen != NULL) { 2077 HPEN oldpen = (HPEN) ::SelectObject((HDC)printDC, hpen); 2078 2079 if (oldpen != NULL) { 2080 DeleteObject(oldpen); 2081 } 2082 } 2083 2084 CATCH_BAD_ALLOC; 2085 } 2086 2087 2088 /* 2089 * Class: sun_awt_windows_WPrinterJob 2090 * Method: selectStylePen 2091 * Signature: (JJJFIII)Z 2092 */ 2093 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_selectStylePen 2094 (JNIEnv *env, jobject self, jlong printDC, jlong cap, jlong join, jfloat width, 2095 jint red, jint green, jint blue) { 2096 2097 TRY; 2098 2099 LOGBRUSH logBrush; 2100 2101 logBrush.lbStyle = PS_SOLID ; 2102 logBrush.lbColor = RGB(red, green, blue); 2103 logBrush.lbHatch = 0 ; 2104 2105 HPEN hpen = ::ExtCreatePen(PS_GEOMETRIC | PS_SOLID | (DWORD)cap 2106 | (DWORD)join, ROUND_TO_LONG(width), 2107 &logBrush, 0, NULL); 2108 2109 if (hpen != NULL) { 2110 HPEN oldpen = (HPEN) ::SelectObject((HDC)printDC, hpen); 2111 2112 if (oldpen != NULL) { 2113 DeleteObject(oldpen); 2114 } 2115 } 2116 2117 return JNI_TRUE; 2118 2119 CATCH_BAD_ALLOC_RET (0); 2120 } 2121 2122 /* 2123 * Class: sun_awt_windows_WPrinterJob 2124 * Method: setFont 2125 * Signature: (JLjava/lang/String;FZZIF)Z 2126 */ 2127 JNIEXPORT jboolean JNICALL Java_sun_awt_windows_WPrinterJob_setFont 2128 (JNIEnv *env, jobject self, jlong printDC, jstring fontName, 2129 jfloat fontSize, jboolean isBold, jboolean isItalic, jint rotation, 2130 jfloat awScale) 2131 { 2132 jboolean didSetFont = JNI_FALSE; 2133 2134 didSetFont = jFontToWFontW(env, (HDC)printDC, 2135 fontName, 2136 fontSize, 2137 isBold, 2138 isItalic, 2139 rotation, 2140 awScale); 2141 2142 return didSetFont; 2143 } 2144 2145 /** 2146 * Try to convert a java font to a GDI font. On entry, 'printDC', 2147 * is the device context we want to draw into. 'fontName' is 2148 * the name of the font to be matched and 'fontSize' is the 2149 * size of the font in device coordinates. If there is an 2150 * equivalent GDI font then this function sets that font 2151 * into 'printDC' and returns a 'true'. If there is no equivalent 2152 * font then 'false' is returned. 2153 */ 2154 static jboolean jFontToWFontA(JNIEnv *env, HDC printDC, jstring fontName, 2155 jfloat fontSize, jboolean isBold, jboolean isItalic, 2156 jint rotation, jfloat awScale) 2157 { 2158 LOGFONTA lf; 2159 LOGFONTA matchedLogFont; 2160 BOOL foundFont = false; // Assume we didn't find a matching GDI font. 2161 2162 memset(&matchedLogFont, 0, sizeof(matchedLogFont)); 2163 2164 LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); 2165 2166 2167 /* Some fontnames of Non-ASCII fonts like 'MS Minchou' are themselves 2168 * Non-ASCII. They are assumed to be written in Unicode. 2169 * Hereby, they are converted into platform codeset. 2170 */ 2171 int maxlen = static_cast<int>(sizeof(lf.lfFaceName)) - 1; 2172 // maxlen is int due to cbMultiByte parameter is int 2173 int destLen = WideCharToMultiByte(CP_ACP, // convert to ASCII code page 2174 0, // flags 2175 fontNameW, // Unicode string 2176 -1, // Unicode length is calculated automatically 2177 lf.lfFaceName, // Put ASCII string here 2178 maxlen, // max len 2179 NULL, // default handling of unmappables 2180 NULL); // do not care if def char is used 2181 2182 /* If WideCharToMultiByte succeeded then the number 2183 * of bytes it copied into the face name buffer will 2184 * be creater than zero and we just need to NULL terminate 2185 * the string. If there was an error then the number of 2186 * bytes copied is zero and we can not match the font. 2187 */ 2188 if (destLen > 0) { 2189 2190 DASSERT(destLen < sizeof(lf.lfFaceName)); 2191 lf.lfFaceName[destLen] = '\0'; 2192 lf.lfCharSet = DEFAULT_CHARSET; 2193 lf.lfPitchAndFamily = 0; 2194 2195 foundFont = !EnumFontFamiliesExA((HDC)printDC, &lf, 2196 (FONTENUMPROCA) fontEnumProcA, 2197 (LPARAM) &matchedLogFont, 0); 2198 } 2199 2200 2201 if (foundFont) { 2202 2203 /* Build a font of the requested size with no 2204 * width modifications. A negative font height 2205 * tells GDI that we want that values absolute 2206 * value as the font's point size. If the font 2207 * is successfully built then set it as the current 2208 * GDI font. 2209 */ 2210 matchedLogFont.lfHeight = -ROUND_TO_LONG(fontSize); 2211 matchedLogFont.lfWidth = 0; 2212 matchedLogFont.lfEscapement = rotation; 2213 matchedLogFont.lfOrientation = rotation; 2214 matchedLogFont.lfUnderline = 0; 2215 matchedLogFont.lfStrikeOut = 0; 2216 2217 /* Force bold or italic if requested. The font name 2218 such as Arial Bold may have already set a weight 2219 so here we just try to increase it. 2220 */ 2221 if (isBold) { 2222 matchedLogFont.lfWeight = embolden(matchedLogFont.lfWeight); 2223 } else { 2224 matchedLogFont.lfWeight = FW_REGULAR; 2225 } 2226 2227 if (isItalic) { 2228 matchedLogFont.lfItalic = 0xff; // TRUE 2229 } else { 2230 matchedLogFont.lfItalic = FALSE; 2231 } 2232 2233 HFONT font = CreateFontIndirectA(&matchedLogFont); 2234 if (font) { 2235 HFONT oldFont = (HFONT)::SelectObject(printDC, font); 2236 if (oldFont != NULL) { 2237 ::DeleteObject(oldFont); 2238 if (awScale != 1.0) { 2239 TEXTMETRIC tm; 2240 DWORD avgWidth; 2241 GetTextMetrics(printDC, &tm); 2242 avgWidth = tm.tmAveCharWidth; 2243 matchedLogFont.lfWidth = (LONG)((fabs)(avgWidth*awScale)); 2244 font = CreateFontIndirectA(&matchedLogFont); 2245 if (font) { 2246 oldFont = (HFONT)::SelectObject(printDC, font); 2247 if (oldFont != NULL) { 2248 ::DeleteObject(oldFont); 2249 GetTextMetrics(printDC, &tm); 2250 } else { 2251 foundFont = false; 2252 } 2253 } else { 2254 foundFont = false; 2255 } 2256 } 2257 } else { 2258 foundFont = false; 2259 } 2260 } else { 2261 foundFont = false; 2262 } 2263 } 2264 2265 JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); 2266 2267 return foundFont ? JNI_TRUE : JNI_FALSE; 2268 } 2269 2270 /** 2271 * Try to convert a java font to a GDI font. On entry, 'printDC', 2272 * is the device context we want to draw into. 'fontName' is 2273 * the name of the font to be matched and 'fontSize' is the 2274 * size of the font in device coordinates. If there is an 2275 * equivalent GDI font then this function sets that font 2276 * into 'printDC' and returns a 'true'. If there is no equivalent 2277 * font then 'false' is returned. 2278 */ 2279 static jboolean jFontToWFontW(JNIEnv *env, HDC printDC, jstring fontName, 2280 jfloat fontSize, jboolean isBold, jboolean isItalic, 2281 jint rotation, jfloat awScale) 2282 { 2283 LOGFONTW lf; 2284 LOGFONTW matchedLogFont; 2285 BOOL foundFont = false; // Assume we didn't find a matching GDI font. 2286 2287 memset(&matchedLogFont, 0, sizeof(matchedLogFont)); 2288 2289 LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); 2290 CHECK_NULL_RETURN(fontNameW, JNI_FALSE); 2291 2292 /* Describe the GDI fonts we want enumerated. We 2293 * simply supply the java font name and let GDI 2294 * do the matching. If the java font name is 2295 * longer than the GDI maximum font lenght then 2296 * we can't convert the font. 2297 */ 2298 size_t nameLen = wcslen(fontNameW); 2299 if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) { 2300 2301 wcscpy(lf.lfFaceName, fontNameW); 2302 2303 lf.lfCharSet = DEFAULT_CHARSET; 2304 lf.lfPitchAndFamily = 0; 2305 2306 foundFont = !::EnumFontFamiliesEx((HDC)printDC, &lf, 2307 (FONTENUMPROCW) fontEnumProcW, 2308 (LPARAM) &matchedLogFont, 0); 2309 } 2310 2311 JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); 2312 2313 if (!foundFont) { 2314 return JNI_FALSE; 2315 } 2316 2317 /* Build a font of the requested size with no 2318 * width modifications. A negative font height 2319 * tells GDI that we want that values absolute 2320 * value as the font's point size. If the font 2321 * is successfully built then set it as the current 2322 * GDI font. 2323 */ 2324 matchedLogFont.lfHeight = -ROUND_TO_LONG(fontSize); 2325 matchedLogFont.lfWidth = 0; 2326 matchedLogFont.lfEscapement = rotation; 2327 matchedLogFont.lfOrientation = rotation; 2328 matchedLogFont.lfUnderline = 0; 2329 matchedLogFont.lfStrikeOut = 0; 2330 2331 /* Force bold or italic if requested. The font name 2332 * such as Arial Bold may have already set a weight 2333 * so here we just try to increase it. 2334 */ 2335 if (isBold) { 2336 matchedLogFont.lfWeight = embolden(matchedLogFont.lfWeight); 2337 } else { 2338 matchedLogFont.lfWeight = FW_REGULAR; 2339 } 2340 2341 if (isItalic) { 2342 matchedLogFont.lfItalic = 0xff; // TRUE 2343 } else { 2344 matchedLogFont.lfItalic = FALSE; 2345 } 2346 2347 //Debug: dumpLogFont(&matchedLogFont); 2348 2349 HFONT font = ::CreateFontIndirect(&matchedLogFont); 2350 if (font == NULL) { 2351 return JNI_FALSE; 2352 } 2353 2354 HFONT oldFont = (HFONT)::SelectObject(printDC, font); 2355 if (oldFont == NULL) { // select failed. 2356 ::DeleteObject(font); 2357 return JNI_FALSE; 2358 } 2359 ::DeleteObject(oldFont); // no longer needed. 2360 2361 /* If there is a non-uniform scale then get a new version 2362 * of the font with an average width that is condensed or 2363 * expanded to match the average width scaling factor. 2364 * This is not valid for shearing transforms. 2365 */ 2366 if (awScale != 1.0) { 2367 TEXTMETRIC tm; 2368 DWORD avgWidth; 2369 GetTextMetrics(printDC, &tm); 2370 avgWidth = tm.tmAveCharWidth; 2371 matchedLogFont.lfWidth = (LONG)((fabs)(avgWidth*awScale)); 2372 font = ::CreateFontIndirect(&matchedLogFont); 2373 if (font == NULL) { 2374 return JNI_FALSE; 2375 } 2376 oldFont = (HFONT)::SelectObject(printDC, font); 2377 if (oldFont == NULL) { 2378 ::DeleteObject(font); 2379 return JNI_FALSE; 2380 } else { 2381 ::DeleteObject(oldFont); 2382 return JNI_TRUE; 2383 } 2384 } 2385 return JNI_TRUE; 2386 } 2387 2388 /** 2389 * Invoked by GDI as a result of the EnumFontFamiliesExW 2390 * call this routine choses a GDI font that matches 2391 * a Java font. When a match is found then function 2392 * returns a zero result to terminate the EnumFontFamiliesExW 2393 * call. The information about the chosen font is copied into 2394 * the LOGFONTW structure pointed to by 'lParam'. 2395 */ 2396 static int CALLBACK fontEnumProcW(ENUMLOGFONTEXW *logfont,// logical-font data 2397 NEWTEXTMETRICEX *lpntme, // physical-font data 2398 int FontType, // type of font 2399 LPARAM lParam) 2400 { 2401 LOGFONTW *matchedLogFont = (LOGFONTW *) lParam; 2402 int stop = 0; // Take the first style found. 2403 2404 if (matchedLogFont != NULL) { 2405 *matchedLogFont = logfont->elfLogFont; 2406 } 2407 2408 return stop; 2409 } 2410 2411 /** 2412 * Invoked by GDI as a result of the EnumFontFamiliesExA 2413 * call this routine choses a GDI font that matches 2414 * a Java font. When a match is found then function 2415 * returns a zero result to terminate the EnumFontFamiliesExA 2416 * call. The information about the chosen font is copied into 2417 * the LOGFONTA structure pointed to by 'lParam'. 2418 */ 2419 static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA *logfont,// logical-font data 2420 NEWTEXTMETRICEX *lpntme, // physical-font data 2421 int FontType, // type of font 2422 LPARAM lParam) 2423 { 2424 LOGFONTA *matchedLogFont = (LOGFONTA *) lParam; 2425 int stop = 0; // Take the first style found. 2426 2427 if (matchedLogFont != NULL) { 2428 *matchedLogFont = logfont->elfLogFont; 2429 } 2430 2431 return stop; 2432 } 2433 2434 /** 2435 * Given the weight of a font from a GDI LOGFONT 2436 * structure, return a new weight indicating a 2437 * bolder font. 2438 */ 2439 static int embolden(int currentWeight) 2440 { 2441 2442 /* If the font is less than bold then make 2443 * it bold. In real life this will mean making 2444 * a FW_NORMAL font bold. 2445 */ 2446 if (currentWeight < FW_BOLD) { 2447 currentWeight = FW_BOLD; 2448 2449 /* If the font is already bold or bolder 2450 * then just increase the weight. This will 2451 * not be visible with GDI in Win95 or NT4. 2452 */ 2453 } else { 2454 currentWeight += EMBOLDEN_WEIGHT; 2455 if (currentWeight > MAX_FONT_WEIGHT) { 2456 currentWeight = MAX_FONT_WEIGHT; 2457 } 2458 } 2459 2460 return currentWeight; 2461 } 2462 2463 /* 2464 * Class: sun_awt_windows_WPrinterJob 2465 * Method: setTextColor 2466 * Signature: (JIII)V 2467 */ 2468 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_setTextColor 2469 (JNIEnv *env, jobject self, jlong printDC, jint red, jint green, jint blue) { 2470 2471 (void) ::SetTextColor( (HDC)printDC, RGB(red, green, blue)); 2472 2473 } 2474 2475 JNIEXPORT jint JNICALL Java_sun_awt_windows_WPrinterJob_getGDIAdvance 2476 (JNIEnv *env, jobject self, jlong printDC, jstring text) 2477 { 2478 SIZE size; 2479 LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); 2480 CHECK_NULL_RETURN(wText, 0); 2481 size_t strLen = wcslen(wText); 2482 BOOL ok = GetTextExtentPoint32((HDC)printDC, wText, (int)strLen, &size); 2483 JNU_ReleaseStringPlatformChars(env, text, wText); 2484 return ok ? size.cx : 0; 2485 } 2486 2487 2488 2489 /* 2490 * ETO_PDY is conditionally defined in wingdi.h as it is available 2491 * only on Windows 2000 and later. ie it requires the application 2492 * define that it is targeting these APIS by placing 2493 * #define _WIN32_WINNT 0x0500 2494 * and perhaps 2495 * #define WINVER 0x5000 2496 * before including the headers 2497 * But this causes many problems for AWT headers subsequently included. 2498 * So instead hard code the value of the flag as our own macro 2499 * If for any reason this code is executed on Win 9x then this will 2500 * not be understood and the advances array will be misinterpreted. 2501 * So we don't use that it in that case and restrict ourselves to x advances. 2502 * Its possible in some cases that text would then not print as expected. 2503 * However we will not normally supply y advances so this is a less likely 2504 * code path and its not worth worrying about in we will not in future 2505 * support win9x - and definitely not to this extent. 2506 */ 2507 #define J2D_ETO_PDY 0x2000 2508 2509 /* 2510 * Class: sun_awt_windows_WPrinterJob 2511 * Method: textOut 2512 * Signature: (JLjava/lang/String;BFF[F)V 2513 * 2514 * Generate GDI text calls for the unicode string 2515 * <code>text</code> into the device context 2516 * <code>printDC</code>. The text string is 2517 * positioned at <code>x</code>, <code>y</code>. 2518 * The positioning of each glyph in the string 2519 * is determined by windows. 2520 * If 'glyphCodes' is true then the string is 16 bit glyph indices 2521 * into the font, not character codes. 2522 * strLen needs to be passed in for the glyphCodes case since its possible 2523 * the missing glyph code may be present, and that is always zero, which 2524 * would be misinterpreted by GDI and the string functions as null termination 2525 * of the string. 2526 */ 2527 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_textOut 2528 (JNIEnv *env, jobject self, jlong printDC, jstring text, jint strLen, 2529 boolean glyphCodes, jfloat x, jfloat y, jfloatArray positions) 2530 { 2531 2532 long posX = ROUND_TO_LONG(x); 2533 long posY = ROUND_TO_LONG(y); 2534 int flags = (glyphCodes !=0) ? ETO_GLYPH_INDEX : 0; 2535 LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); 2536 CHECK_NULL(wText); 2537 2538 int *advances = NULL, *xadvances = NULL, *xyadvances = NULL; 2539 BOOL useYAdvances = FALSE; 2540 jfloat *glyphPos = NULL; 2541 if (positions != NULL) { 2542 glyphPos = env->GetFloatArrayElements(positions, NULL); 2543 } 2544 2545 /* We need to convert positions relative to the origin of the text 2546 * into advances relative to the previous glyph. 2547 * We expect to be able to allocate these small arrays. 2548 * If we fail then we'll print the glyphs using their built-in advances. 2549 * Because the array is of inter-character advances we only need 2550 * strLen - 1 entries but Windows looks at the advance between 2551 * the last character and the non-existent character we allocate 2552 * space for that as well. 2553 * We supply only the advances that are needed 2554 * - Default advances (ie none) if GDI advances are what we want 2555 * - Only X advances if the Y advances are all zero. 2556 * We allocate two arrays so we can figure out on the fly which 2557 * we need. 2558 * Note that we have to add the 'error' or difference between the 2559 * rounded advance and the floating point advance back into the 2560 * calculation of the next advance else the sum of the integer- 2561 * rounded advances will drift away from the true advance. 2562 */ 2563 if (glyphPos != NULL && strLen > 0) { 2564 try { 2565 xadvances = (int*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, 2566 strLen, sizeof(int)); 2567 xyadvances = (int*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, strLen, 2568 sizeof(int) * 2); 2569 } catch (std::bad_alloc&) { 2570 if (xadvances != NULL) { 2571 free(xadvances); 2572 xadvances = NULL; 2573 } 2574 if (xyadvances != NULL) { 2575 free(xyadvances); 2576 xyadvances = NULL; 2577 } 2578 } 2579 } 2580 if (xadvances != NULL && xyadvances != NULL) { 2581 int *inxAdvances = xadvances; 2582 int *inxyAdvances = xyadvances; 2583 jfloat *inGlyphPos = glyphPos; 2584 jfloat lastX = *inGlyphPos++; 2585 jfloat lastY = *inGlyphPos++; 2586 jfloat errorX = 0, errorY = 0; 2587 for (int i = 1; i < strLen; i++) { 2588 2589 jfloat thisX = *inGlyphPos++; 2590 jfloat thisY = *inGlyphPos++; 2591 2592 jfloat xAdvance = thisX - lastX + errorX; 2593 jfloat yAdvance = thisY - lastY + errorY; 2594 2595 int xadv = ROUND_TO_INT(xAdvance); 2596 errorX = xAdvance - xadv; 2597 int yadv = ROUND_TO_INT(yAdvance); 2598 errorY = yAdvance - yadv; 2599 if (yadv != 0) { 2600 useYAdvances = TRUE; 2601 } 2602 *inxAdvances++ = xadv; 2603 *inxyAdvances++ = xadv; 2604 *inxyAdvances++ = yadv; 2605 2606 lastX = thisX; 2607 lastY = thisY; 2608 } 2609 /* This is the advance from the last character. 2610 * It is not technically needed, but the raster 2611 * drivers, as opposed to the PostScript driver 2612 * will fail to print the entire string if this 2613 * value is absurdly large or absurdly negative. 2614 */ 2615 *inxAdvances = 0; 2616 *inxyAdvances++ = 0; 2617 *inxyAdvances = 0; 2618 } 2619 2620 if (useYAdvances) { 2621 advances = xyadvances; 2622 flags |= J2D_ETO_PDY; 2623 } else { 2624 advances = xadvances; 2625 } 2626 2627 /* Done with the float array parameter, so release it. */ 2628 if (glyphPos != NULL) { 2629 env->ReleaseFloatArrayElements(positions, glyphPos, JNI_ABORT); 2630 } 2631 2632 BOOL drawn = ::ExtTextOut((HDC)printDC, 2633 posX, posY, // starting position for the text 2634 flags, // glyphCodes?, y advances? 2635 NULL, // optional clipping-opaquing rectangle 2636 wText, // the Unicode text to draw 2637 static_cast<UINT>(strLen), 2638 advances); // intercharacter advances or NULL 2639 2640 if (xadvances != NULL) { 2641 free(xadvances); 2642 } 2643 if (xyadvances != NULL) { 2644 free(xyadvances); 2645 } 2646 2647 JNU_ReleaseStringPlatformChars(env, text, wText); 2648 } 2649 2650 /** 2651 * Scans a 24 bit RGB DIB image looking for the first non-white line. 2652 * On entry, if scanLineStride is negative, 'image' points at the 2653 * bottom of the DIB, which is where the first scan line is. 2654 * Alternatively, if scanLineStride is positive, it's a top-down 2655 * DIB and 'image' points to the top scan line. 2656 * 'numLinesP', on entry, is the number of scan lines in the image while 2657 * 'width' is the number of 24 bit pixels on each line. If a non-white 2658 * line is found in the DIB, then a pointer to the first, 2659 * working from the bottom, non-white scan line is returned. 2660 * and the number of remaining scan lines is returned in *'numLinesP'. 2661 * Pixels are 3 byte BGR triples, so any byte that is not 0xff indicates 2662 * its a component of a non-white pixel. So we don't need to combine bytes 2663 * into pixels. Simply scan the image looking for any byte that is not 0xff 2664 */ 2665 static jbyte *findNonWhite(jbyte *image, long sy, long width, long height, 2666 long scanLineStride, long *numLinesP) { 2667 2668 long found = -1; 2669 long numLines = 0; 2670 jbyte *startLine = image; 2671 unsigned char *inLine; 2672 const unsigned char cc = (unsigned char)0xff; 2673 2674 assert(image != NULL); 2675 assert(0 <= sy && sy < height); 2676 assert(0 < width); 2677 assert(0 < height); 2678 assert(numLinesP != NULL); 2679 2680 for (numLines = 0; sy < height; numLines++, sy++) { 2681 2682 inLine = (unsigned char*)startLine; 2683 2684 for (long colcomp = 0; colcomp < abs(scanLineStride); colcomp++) { 2685 if (*inLine++ != cc) { 2686 found = sy; 2687 break; 2688 } 2689 } 2690 2691 if(found != -1) { 2692 break; 2693 } 2694 2695 startLine += scanLineStride; 2696 } 2697 2698 *numLinesP = numLines; 2699 2700 return found == -1 ? NULL : startLine; 2701 } 2702 2703 /* Find the 1st scanline that's entirely white. 2704 * The starting scanline pointed to by 'image' may be part way through the DIB. 2705 * If an all white scanline is found, the return value points to the beginning 2706 * of the last scanline with a non-white pixel. If no all white scanlines 2707 * are found, the starting scanline is returned. 2708 * '*numLinesP' returns the number of non-white scan lines. 2709 * Skip the 1st scanline as its always non-white. 2710 * If passed scanLineStride is negative, the DIB is bottom-up, 2711 * otherwise it's top-down. 2712 */ 2713 static jbyte *findWhite(jbyte *image, long sy, long width, long height, 2714 long scanLineStride, long *numLinesP) { 2715 2716 long numLines; 2717 jbyte *startLine = image; 2718 unsigned char *inLine; 2719 jbyte *found = NULL; 2720 long white; 2721 const unsigned char cc = (unsigned char)0xff; 2722 2723 assert(image != NULL); 2724 assert(0 <= sy); 2725 assert(0 < width); 2726 assert(0 < height); 2727 assert(numLinesP != NULL); 2728 2729 ++sy; 2730 for(numLines = 1; sy < height; numLines++, sy++) { 2731 2732 startLine += scanLineStride; 2733 inLine = (unsigned char*)startLine; 2734 white = 1; 2735 2736 for (long colcomp = 0; colcomp < abs(scanLineStride); colcomp++) { 2737 if (*inLine++ != cc) { 2738 white = 0; 2739 break; 2740 } 2741 } 2742 2743 if (white != 0) { 2744 found = startLine - scanLineStride; 2745 break; 2746 } 2747 } 2748 2749 *numLinesP = numLines; 2750 2751 return found == NULL ? startLine : found; 2752 2753 } 2754 2755 /* 2756 * Reverses the bitmap. 2757 * Returns pointer to reversed bitmap (DWORD aligned). 2758 * Returns NULL if unsuccessful. 2759 * NOTE: Caller must free the pointer returned by calling free. 2760 */ 2761 static jbyte* reverseDIB(jbyte* imageBits, long srcWidth, long srcHeight, 2762 int bitsperpixel) { 2763 2764 /* get width in bytes. 2765 * If the image is 24bpp, its srcWidth*3 2766 * If the image is 8bpp, its just srcWidth 2767 * If the image is 1bpp or 4bpp one then its rounded up to the next byte. 2768 */ 2769 long imgWidthByteSz; 2770 switch (bitsperpixel) { 2771 case 24 : imgWidthByteSz = srcWidth * 3; 2772 break; 2773 case 8 : imgWidthByteSz = srcWidth; 2774 break; 2775 case 1 : imgWidthByteSz = (srcWidth + 7) / 8 ; 2776 break; 2777 case 4 : imgWidthByteSz = (srcWidth + 1) / 2 ; 2778 break; 2779 default : /* not expected but this is OK for any exact multiple of 8 */ 2780 imgWidthByteSz = srcWidth * bitsperpixel / 8; 2781 } 2782 2783 int padBytes = 0; 2784 /* make it DWORD aligned */ 2785 if ((imgWidthByteSz % sizeof(DWORD)) != 0) 2786 padBytes = sizeof(DWORD) - (imgWidthByteSz % sizeof(DWORD)); 2787 2788 jbyte* alignedImage = NULL; 2789 try { 2790 alignedImage = (jbyte*) SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, 2791 imgWidthByteSz+padBytes, ROUND_TO_LONG(srcHeight)); 2792 } catch (std::bad_alloc&) { 2793 } 2794 long newImgSize = (imgWidthByteSz+padBytes) * ROUND_TO_LONG(srcHeight); 2795 2796 if (alignedImage != NULL) { 2797 memset(alignedImage, 0xff, newImgSize); 2798 2799 jbyte* imgLinePtr = alignedImage; 2800 for (long i=ROUND_TO_LONG(srcHeight)-1; i>=0; i--) { 2801 memcpy(imgLinePtr, imageBits+(i*imgWidthByteSz), 2802 imgWidthByteSz); 2803 imgLinePtr += (imgWidthByteSz + padBytes); 2804 } 2805 2806 return alignedImage; 2807 } 2808 return NULL; 2809 } 2810 2811 /* 2812 * Class: sun_awt_windows_WPrinterJob 2813 * Method: drawDIBImage 2814 * Signature: (J[BFFFFFFFFI[B)V 2815 */ 2816 JNIEXPORT void JNICALL Java_sun_awt_windows_WPrinterJob_drawDIBImage 2817 (JNIEnv *env, jobject self, 2818 jlong printDC, jbyteArray image, 2819 jfloat destX, jfloat destY, 2820 jfloat destWidth, jfloat destHeight, 2821 jfloat srcX, jfloat srcY, 2822 jfloat srcWidth, jfloat srcHeight, 2823 jint bitCount, jbyteArray bmiColorsArray) { 2824 2825 int result = 0; 2826 2827 assert(printDC != NULL); 2828 assert(image != NULL); 2829 assert(srcX >= 0); 2830 assert(srcY >= 0); 2831 assert(srcWidth > 0); 2832 assert(srcHeight > 0); 2833 2834 #define MAXCOLS 256 2835 struct { 2836 BITMAPINFOHEADER bmiHeader; 2837 RGBQUAD bmiColors[MAXCOLS]; 2838 } bmi; 2839 2840 memset(&bmi, 0, sizeof(bmi)); 2841 bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader); 2842 bmi.bmiHeader.biWidth = ROUND_TO_LONG(srcWidth); 2843 bmi.bmiHeader.biHeight = ROUND_TO_LONG(srcHeight); 2844 bmi.bmiHeader.biPlanes = 1; 2845 bmi.bmiHeader.biBitCount = (WORD)bitCount; 2846 bmi.bmiHeader.biCompression = BI_RGB; 2847 bmi.bmiHeader.biSizeImage = 0; // It's the default size. 2848 bmi.bmiHeader.biXPelsPerMeter = 0; 2849 bmi.bmiHeader.biYPelsPerMeter = 0; 2850 bmi.bmiHeader.biClrUsed = 0; 2851 bmi.bmiHeader.biClrImportant = 0; 2852 2853 jint *imageBits = NULL; 2854 try { 2855 2856 if (bmiColorsArray != NULL) { 2857 BYTE* bmiCols; 2858 int numCols = 1<<bitCount; 2859 if (numCols > MAXCOLS) { 2860 numCols = MAXCOLS; /* don't write past end of struct */ 2861 } 2862 bmiCols = (BYTE*)env->GetPrimitiveArrayCritical(bmiColorsArray, 0); 2863 CHECK_NULL(bmiCols); 2864 memcpy(&(bmi.bmiColors[0]), bmiCols, (numCols*4)); 2865 env->ReleasePrimitiveArrayCritical(bmiColorsArray, bmiCols, 0); 2866 } 2867 imageBits = (jint *)env->GetPrimitiveArrayCritical(image, 0); 2868 CHECK_NULL(imageBits); 2869 2870 // Workaround for drivers/apps that do not support top-down. 2871 // Because we don't know if they support or not, 2872 // always send bottom-up DIBs. 2873 jbyte *dibImage = reverseDIB((jbyte*)imageBits, 2874 (long)srcWidth, (long)srcHeight, 2875 bitCount); 2876 if (dibImage != NULL) { 2877 if (printDC){ 2878 result = ::StretchDIBits( (HDC)printDC, 2879 ROUND_TO_LONG(destX), 2880 ROUND_TO_LONG(destY), 2881 ROUND_TO_LONG(destWidth), 2882 ROUND_TO_LONG(destHeight), 2883 ROUND_TO_LONG(srcX), 2884 ROUND_TO_LONG(srcY), 2885 ROUND_TO_LONG(srcWidth), 2886 ROUND_TO_LONG(srcHeight), 2887 dibImage, 2888 (BITMAPINFO*)(&bmi), 2889 DIB_RGB_COLORS, 2890 SRCCOPY); 2891 } 2892 2893 free(dibImage); 2894 } /* if (dibImage != NULL) */ 2895 } catch (...) { 2896 if (imageBits != NULL) { 2897 env->ReleasePrimitiveArrayCritical(image, imageBits, 0); 2898 } 2899 JNU_ThrowInternalError(env, "Problem in WPrinterJob_drawDIBImage"); 2900 return; 2901 } 2902 env->ReleasePrimitiveArrayCritical(image, imageBits, 0); 2903 2904 } 2905 2906 /* 2907 * An utility function to print passed image byte array to 2908 * the printDC. 2909 * browserPrinting flag controls whether the image array 2910 * used as top-down (browserPrinting == JNI_TRUE) or 2911 * bottom-up (browserPrinting == JNI_FALSE) DIB. 2912 */ 2913 static void doPrintBand(JNIEnv *env, jboolean browserPrinting, 2914 HDC printDC, jbyteArray imageArray, 2915 jint x, jint y, jint width, jint height) { 2916 2917 TRY; 2918 2919 jbyte *image = NULL; 2920 try { 2921 long scanLineStride = J2DRasterBPP * width; 2922 image = (jbyte *)env->GetPrimitiveArrayCritical(imageArray, 0); 2923 CHECK_NULL(image); 2924 jbyte *startImage; 2925 jbyte *endImage = NULL; 2926 long startY = 0; 2927 long numLines = 0; 2928 2929 if (browserPrinting) { 2930 /* for browser printing use top-down approach */ 2931 startImage = image; 2932 } else { 2933 /* when printing to a real printer dc, the dib 2934 should bottom-up */ 2935 startImage = image + (scanLineStride * (height - 1)); 2936 scanLineStride = -scanLineStride; 2937 } 2938 do { 2939 startImage = findNonWhite(startImage, startY, width, height, 2940 scanLineStride, &numLines); 2941 2942 if (startImage != NULL) { 2943 startY += numLines; 2944 endImage = findWhite(startImage, startY, width, height, 2945 scanLineStride, &numLines); 2946 if (browserPrinting) { 2947 /* passing -numLines as height to indicate that 2948 we treat the image as a top-down DIB */ 2949 bitsToDevice(printDC, startImage, x, y + startY, width, 2950 -numLines); 2951 } else { 2952 bitsToDevice(printDC, endImage, x, y + startY, width, 2953 numLines); 2954 } 2955 startImage = endImage + scanLineStride; 2956 startY += numLines; 2957 } 2958 } while (startY < height && startImage != NULL); 2959 2960 } catch (...) { 2961 if (image != NULL) { 2962 env->ReleasePrimitiveArrayCritical(imageArray, image, 0); 2963 } 2964 throw; 2965 } 2966 2967 env->ReleasePrimitiveArrayCritical(imageArray, image, 0); 2968 2969 CATCH_BAD_ALLOC; 2970 2971 } 2972 2973 static int bitsToDevice(HDC printDC, jbyte *image, long destX, long destY, 2974 long width, long height) { 2975 int result = 0; 2976 2977 assert(printDC != NULL); 2978 assert(image != NULL); 2979 assert(destX >= 0); 2980 assert(destY >= 0); 2981 assert(width > 0); 2982 /* height could be negative to indicate that this is a top-down DIB */ 2983 // assert(height > 0); 2984 2985 if (!printDC || height == 0) { 2986 return result; 2987 } 2988 struct { 2989 BITMAPINFOHEADER bmiHeader; 2990 DWORD* bmiColors; 2991 } bitMapHeader; 2992 2993 memset(&bitMapHeader,0,sizeof(bitMapHeader)); 2994 bitMapHeader.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 2995 bitMapHeader.bmiHeader.biWidth = width; 2996 bitMapHeader.bmiHeader.biHeight = height; // does -height work ever? 2997 bitMapHeader.bmiHeader.biPlanes = 1; 2998 bitMapHeader.bmiHeader.biBitCount = 24; 2999 bitMapHeader.bmiHeader.biCompression = BI_RGB; 3000 bitMapHeader.bmiHeader.biSizeImage = 0; // It's the default size. 3001 bitMapHeader.bmiHeader.biXPelsPerMeter = 0; 3002 bitMapHeader.bmiHeader.biYPelsPerMeter = 0; 3003 bitMapHeader.bmiHeader.biClrUsed = 0; 3004 bitMapHeader.bmiHeader.biClrImportant = 0; 3005 bitMapHeader.bmiColors = NULL; 3006 3007 height = abs(height); 3008 3009 // Workaround for drivers/apps that do not support top-down. 3010 // Because we don't know if they support or not, 3011 // always send bottom-up DIBs 3012 if (bitMapHeader.bmiHeader.biHeight < 0) { 3013 jbyte *dibImage = reverseDIB(image, width, height, 24); 3014 if (dibImage != NULL) { 3015 bitMapHeader.bmiHeader.biWidth = ROUND_TO_LONG(width); 3016 bitMapHeader.bmiHeader.biHeight = ROUND_TO_LONG(height); 3017 result = ::SetDIBitsToDevice(printDC, 3018 ROUND_TO_LONG(destX), // left of dest rect 3019 ROUND_TO_LONG(destY), // top of dest rect 3020 ROUND_TO_LONG(width), // width of dest rect 3021 ROUND_TO_LONG(height), // height of dest rect 3022 0, // left of source rect 3023 0, // top of source rect 3024 0, // line number of 1st source scan line 3025 ROUND_TO_LONG(height), // number of scan lines 3026 dibImage, // points to the DIB 3027 (BITMAPINFO *)&bitMapHeader, 3028 DIB_RGB_COLORS); 3029 free (dibImage); 3030 } 3031 } else { 3032 result = ::SetDIBitsToDevice(printDC, 3033 destX, // left of dest rect 3034 destY, // top of dest rect 3035 width, // width of dest rect 3036 height, // height of dest rect 3037 0, // left of source rect 3038 0, // top of source rect 3039 0, // line number of 1st source scan line 3040 height, // number of source scan lines 3041 image, // points to the DIB 3042 (BITMAPINFO *)&bitMapHeader, 3043 DIB_RGB_COLORS); 3044 if (result == 0) { 3045 size_t size = width * height * 3; // Always 24bpp, also DWORD aligned. 3046 void *imageData = NULL; 3047 try { 3048 imageData = safe_Malloc(size); 3049 } catch (std::bad_alloc&) { 3050 return result; 3051 } 3052 memcpy(imageData, image, size); 3053 result = ::SetDIBitsToDevice(printDC, 3054 destX, // left of dest rect 3055 destY, // top of dest rect 3056 width, // width of dest rect 3057 height, // height of dest rect 3058 0, // left of source rect 3059 0, // top of source rect 3060 0, // line number of 1st source scan line 3061 height, // number of source scan lines 3062 imageData, // points to the DIB 3063 (BITMAPINFO *)&bitMapHeader, 3064 DIB_RGB_COLORS); 3065 free(imageData); 3066 } 3067 } 3068 return result; 3069 } 3070 3071 LRESULT CALLBACK PageDialogWndProc(HWND hWnd, UINT message, 3072 WPARAM wParam, LPARAM lParam) 3073 { 3074 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 3075 3076 switch (message) { 3077 case WM_COMMAND: { 3078 if ((LOWORD(wParam) == IDOK) || 3079 (LOWORD(wParam) == IDCANCEL)) 3080 { 3081 // If we recieve on of these two notifications, the dialog 3082 // is about to be closed. It's time to unblock all the 3083 // windows blocked by this dialog, as doing so from the 3084 // WM_DESTROY handler is too late 3085 jobject peer = (jobject)(::GetProp(hWnd, ModalDialogPeerProp)); 3086 env->CallVoidMethod(peer, AwtPrintDialog::setHWndMID, (jlong)0); 3087 } 3088 break; 3089 } 3090 } 3091 3092 WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hWnd, NativeDialogWndProcProp)); 3093 return ComCtl32Util::GetInstance().DefWindowProc(lpfnWndProc, hWnd, message, wParam, lParam); 3094 } 3095 3096 /** 3097 * Called by the Page Setup dialog this routine makes sure the 3098 * print dialog becomes the front most window. 3099 */ 3100 static UINT CALLBACK pageDlgHook(HWND hDlg, UINT msg, 3101 WPARAM wParam, LPARAM lParam) 3102 { 3103 JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2); 3104 3105 TRY; 3106 3107 switch(msg) { 3108 case WM_INITDIALOG: { 3109 PAGESETUPDLG *psd = (PAGESETUPDLG *)lParam; 3110 jobject peer = (jobject)(psd->lCustData); 3111 env->CallVoidMethod(peer, AwtPrintDialog::setHWndMID, 3112 (jlong)hDlg); 3113 ::SetProp(hDlg, ModalDialogPeerProp, reinterpret_cast<HANDLE>(peer)); 3114 3115 SetForegroundWindow(hDlg); 3116 3117 // set appropriate icon for parentless dialogs 3118 jobject awtParent = env->GetObjectField(peer, AwtPrintDialog::parentID); 3119 if (awtParent == NULL) { 3120 ::SendMessage(hDlg, WM_SETICON, (WPARAM)ICON_BIG, 3121 (LPARAM)AwtToolkit::GetInstance().GetAwtIcon()); 3122 } else { 3123 env->DeleteLocalRef(awtParent); 3124 } 3125 3126 // subclass dialog's parent to receive additional messages 3127 WNDPROC lpfnWndProc = ComCtl32Util::GetInstance().SubclassHWND(hDlg, 3128 PageDialogWndProc); 3129 ::SetProp(hDlg, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc)); 3130 3131 break; 3132 } 3133 case WM_DESTROY: { 3134 WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hDlg, NativeDialogWndProcProp)); 3135 ComCtl32Util::GetInstance().UnsubclassHWND(hDlg, 3136 PageDialogWndProc, 3137 lpfnWndProc); 3138 ::RemoveProp(hDlg, ModalDialogPeerProp); 3139 ::RemoveProp(hDlg, NativeDialogWndProcProp); 3140 break; 3141 } 3142 } 3143 3144 return (UINT) FALSE; 3145 3146 CATCH_BAD_ALLOC_RET(TRUE); 3147 } 3148 3149 /** 3150 * Create and return a printer device context for the 3151 * default printer. If there is no default printer then 3152 * return NULL. This fn is used when printing is invoked 3153 * and no user dialog was created. So despite its name, it 3154 * needs to return a DC which reflects all the applications 3155 * settings which the driver might support. 3156 * The number of copies is the most important setting. 3157 */ 3158 static HDC getDefaultPrinterDC(JNIEnv *env, jobject printerJob) { 3159 HDC printDC = NULL; 3160 3161 int devWillDoCopies = FALSE; 3162 PRINTDLG pd; 3163 memset(&pd, 0, sizeof(PRINTDLG)); 3164 pd.lStructSize = sizeof(PRINTDLG); 3165 pd.Flags = PD_RETURNDEFAULT | PD_RETURNDC; 3166 3167 if (::PrintDlg(&pd)) { 3168 printDC = pd.hDC; 3169 3170 /* Find out how many copies the driver can do, and use driver's 3171 * dmCopies if requested number is within that limit 3172 */ 3173 int maxCopies = 1; 3174 int nCopies = getCopies(env, printerJob); 3175 if (nCopies < 0) { 3176 return NULL; 3177 } 3178 SAVE_CONTROLWORD 3179 if (pd.hDevNames != NULL) { 3180 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(pd.hDevNames); 3181 3182 if (devnames != NULL) { 3183 LPTSTR lpdevnames = (LPTSTR)devnames; 3184 LPTSTR printer = lpdevnames+devnames->wDeviceOffset; 3185 LPTSTR port = lpdevnames+devnames->wOutputOffset; 3186 // if DeviceCapabilities fails, return value is -1 3187 maxCopies = (int)::DeviceCapabilities(printer, port, DC_COPIES, 3188 NULL, NULL); 3189 RESTORE_CONTROLWORD 3190 if (maxCopies > 1) { 3191 devWillDoCopies = TRUE; 3192 } 3193 } 3194 ::GlobalUnlock(pd.hDevNames); 3195 } 3196 3197 if ((maxCopies >= nCopies) && (pd.hDevMode != NULL)) { 3198 DEVMODE *devmode = (DEVMODE *)::GlobalLock(pd.hDevMode); 3199 3200 if (devmode != NULL) { 3201 3202 if ((devmode->dmFields & DM_COPIES) && (nCopies > 1)) { 3203 devmode->dmCopies = nCopies; 3204 HDC tmpDC = ::ResetDC(pd.hDC, devmode); 3205 RESTORE_CONTROLWORD 3206 if (tmpDC != NULL) { 3207 printDC = tmpDC; 3208 } 3209 } 3210 } 3211 ::GlobalUnlock(pd.hDevMode); 3212 } 3213 3214 /* Not pretty that this is set in a separate place then the DC */ 3215 if (pd.hDevMode != NULL) { 3216 AwtPrintControl::setPrintHDMode(env, printerJob, pd.hDevMode); 3217 } 3218 if (pd.hDevNames != NULL) { 3219 AwtPrintControl::setPrintHDName(env, printerJob, pd.hDevNames); 3220 } 3221 3222 jboolean err; 3223 err = setBooleanField(env, printerJob, DRIVER_COPIES_STR, 3224 (devWillDoCopies ? JNI_TRUE : JNI_FALSE)); 3225 if (err) return NULL; 3226 err = setBooleanField(env, printerJob, DRIVER_COLLATE_STR, JNI_FALSE); 3227 if (err) return NULL; 3228 err = setBooleanField(env, printerJob, USER_COLLATE_STR, JNI_FALSE); 3229 if (err) return NULL; 3230 } 3231 3232 return printDC; 3233 } 3234 3235 3236 /** 3237 * Move the description of the page's size and orientation 3238 * from the PageFormat object 'page' into the structure, 3239 * 'setup' used by Windows to display the Page Setup dialog. 3240 */ 3241 static void pageFormatToSetup(JNIEnv *env, jobject job, 3242 jobject page, PAGESETUPDLG *setup, HDC hDC) { 3243 RectDouble paperSize; 3244 RectDouble margins; 3245 3246 /* Move the orientation from PageFormat to Windows. 3247 */ 3248 jint orient = getPageFormatOrientation(env, page); 3249 if (orient < 0) return; 3250 int gdiOrientation = (orient == PAGEFORMAT_PORTRAIT) ? 3251 DMORIENT_PORTRAIT : DMORIENT_LANDSCAPE; 3252 setOrientationInDevMode(setup->hDevMode, orient == PAGEFORMAT_PORTRAIT); 3253 3254 int units = (setup->Flags & PSD_INTHOUSANDTHSOFINCHES) 3255 ? MM_HIENGLISH 3256 : MM_HIMETRIC; 3257 jobject paper = getPaper(env, page); 3258 CHECK_NULL(paper); 3259 getPaperValues(env, paper, &paperSize, &margins); 3260 JNU_CHECK_EXCEPTION(env); 3261 // Setting the paper size appears to be a futile exercise, as its not one 3262 // of the values you can initialise - its an out-only arg. Margins are OK. 3263 // set it into the DEVMODE if there is one .. 3264 setup->ptPaperSize.x = convertFromPoints(paperSize.width, units); 3265 setup->ptPaperSize.y = convertFromPoints(paperSize.height, units); 3266 3267 if (setup->hDevMode != NULL) { 3268 3269 double paperWidth, paperHeight; 3270 jboolean err; 3271 WORD dmPaperSize = getPrintPaperSize(env, &err, job); 3272 if (err) return; 3273 matchPaperSize(hDC, setup->hDevMode, setup->hDevNames, 3274 paperSize.width, paperSize.height, 3275 &paperWidth, &paperHeight, &dmPaperSize); 3276 3277 DEVMODE *devmode = (DEVMODE *)::GlobalLock(setup->hDevMode); 3278 if (devmode != NULL) { 3279 if (dmPaperSize != 0) { 3280 devmode->dmFields |= DM_PAPERSIZE; 3281 devmode->dmPaperSize = dmPaperSize; 3282 } 3283 else { 3284 devmode->dmFields |= DM_PAPERLENGTH | DM_PAPERWIDTH 3285 | DM_PAPERSIZE; 3286 devmode->dmPaperSize = DMPAPER_USER; 3287 devmode->dmPaperWidth = 3288 (short)(convertFromPoints(paperSize.width, MM_LOMETRIC)); 3289 devmode->dmPaperLength = 3290 (short)(convertFromPoints(paperSize.height, MM_LOMETRIC)); 3291 } 3292 } 3293 ::GlobalUnlock(setup->hDevMode); 3294 } 3295 3296 // When setting up these values, account for the orientation of the Paper 3297 // in the PageFormat. In the margins Rect when in portrait mode, 3298 // width is really right margin, height is really bottom margin. 3299 if (orient == PAGEFORMAT_PORTRAIT) { 3300 setup->rtMargin.left = convertFromPoints(margins.x, units); 3301 setup->rtMargin.top = convertFromPoints(margins.y, units); 3302 setup->rtMargin.right = convertFromPoints(margins.width, units); 3303 setup->rtMargin.bottom = convertFromPoints(margins.height, units); 3304 } else if (orient == PAGEFORMAT_LANDSCAPE) { 3305 setup->rtMargin.left = convertFromPoints(margins.height, units); 3306 setup->rtMargin.top = convertFromPoints(margins.x, units); 3307 setup->rtMargin.right = convertFromPoints(margins.y, units); 3308 setup->rtMargin.bottom = convertFromPoints(margins.width, units); 3309 } else { // reverse landscape 3310 setup->rtMargin.left = convertFromPoints(margins.y, units); 3311 setup->rtMargin.top = convertFromPoints(margins.width, units); 3312 setup->rtMargin.right = convertFromPoints(margins.height, units); 3313 setup->rtMargin.bottom = convertFromPoints(margins.x, units); 3314 } 3315 3316 // Set page size here. 3317 } 3318 3319 static WORD getOrientationFromDevMode2(HGLOBAL hDevMode) { 3320 3321 WORD orient = DMORIENT_PORTRAIT; 3322 3323 if (hDevMode != NULL) { 3324 LPDEVMODE devMode = (LPDEVMODE) GlobalLock(hDevMode); 3325 if ((devMode != NULL) && (devMode->dmFields & DM_ORIENTATION)) { 3326 orient = devMode->dmOrientation; 3327 } 3328 GlobalUnlock(hDevMode); 3329 } 3330 return orient; 3331 } 3332 3333 /** 3334 * Get the orientation of the paper described by the printer 3335 * handle to a device mode structure 'hDevMode'. 3336 */ 3337 static WORD getOrientationFromDevMode(JNIEnv *env, jobject self) { 3338 return getOrientationFromDevMode2(AwtPrintControl::getPrintHDMode(env, self)); 3339 } 3340 3341 /** 3342 * Set the orientation of the paper described by the printer 3343 * handle to a device mode structure 'hDevMode'. 3344 */ 3345 static void setOrientationInDevMode(HGLOBAL hDevMode, jboolean isPortrait) { 3346 3347 if (hDevMode != NULL) { 3348 LPDEVMODE devMode = (LPDEVMODE) GlobalLock(hDevMode); 3349 if (devMode != NULL) { 3350 devMode->dmOrientation = isPortrait 3351 ? DMORIENT_PORTRAIT 3352 : DMORIENT_LANDSCAPE; 3353 devMode->dmFields |= DM_ORIENTATION; 3354 } 3355 GlobalUnlock(hDevMode); 3356 } 3357 } 3358 3359 /** 3360 * Return the paper size and margins for the page 3361 * adjusted to take into account the portrait or 3362 * landscape orientation of the page. On entry, 3363 * 'setup' is a filled in structure as returned 3364 * by PageSetupDlg(). 'paperSize', 'margins', 3365 * and 'orientation' all point to caller allocated 3366 * space while will be filled in by this routine 3367 * with the size, in unknown Windows units, of 3368 * the paper, of the margins, and an indicator 3369 * whether the page is in portrait or landscape 3370 * orientation, respectively. 3371 */ 3372 static void retrievePaperInfo(const PAGESETUPDLG *setup, POINT *paperSize, 3373 RECT *margins, jint *orientation, HDC hdc) { 3374 int orientationKnown = FALSE; 3375 3376 *paperSize = setup->ptPaperSize; 3377 int gdiOrientation = DMORIENT_PORTRAIT; 3378 3379 /* Usually the setup dialog will tell us the 3380 * orientation of the page, but it may not. 3381 */ 3382 if (setup->hDevMode != NULL) { 3383 gdiOrientation = getOrientationFromDevMode2(setup->hDevMode); 3384 orientationKnown = TRUE; 3385 } 3386 3387 /* The driver didn't tell us the paper orientation 3388 * so we declare it landscape if the paper 3389 * is wider than it is long. Square paper is 3390 * declared to be portait. 3391 */ 3392 if (orientationKnown == FALSE && paperSize->x > paperSize->y) { 3393 gdiOrientation = DMORIENT_LANDSCAPE; 3394 } 3395 3396 *margins = setup->rtMargin; 3397 3398 // compare margin from page setup dialog with our device printable area 3399 RectDouble deviceMargin; 3400 3401 if (getPrintableArea(hdc, setup->hDevMode, &deviceMargin) == TRUE) { 3402 RECT devMargin; 3403 3404 int units = (setup->Flags & PSD_INTHOUSANDTHSOFINCHES) 3405 ? MM_HIENGLISH : MM_HIMETRIC; 3406 3407 devMargin.left = convertFromPoints(deviceMargin.x*72, units); 3408 devMargin.top = convertFromPoints(deviceMargin.y*72, units); 3409 devMargin.bottom = paperSize->y 3410 - convertFromPoints(deviceMargin.height*72, units) 3411 - devMargin.top; 3412 devMargin.right = paperSize->x 3413 - convertFromPoints(deviceMargin.width*72, units) 3414 - devMargin.left; 3415 3416 if (margins->left < devMargin.left) { 3417 margins->left = devMargin.left; 3418 } 3419 if (margins->top < devMargin.top) { 3420 margins->top = devMargin.top; 3421 } 3422 if (margins->bottom < devMargin.bottom) { 3423 margins->bottom = devMargin.bottom; 3424 } 3425 if (margins->right < devMargin.right) { 3426 margins->right = devMargin.right; 3427 } 3428 } 3429 3430 /* The Paper class expresses the page size in 3431 * portait mode while Windows returns the paper 3432 * size adjusted for the orientation. If the 3433 * orientation is landscape then we want to 3434 * flip the width and height to get a portait 3435 * description of the page. 3436 */ 3437 if (gdiOrientation != DMORIENT_PORTRAIT) { 3438 long hold = paperSize->x; 3439 paperSize->x = paperSize->y; 3440 paperSize->y = hold; 3441 3442 margins->left = setup->rtMargin.top; 3443 margins->right = setup->rtMargin.bottom; 3444 margins->top = setup->rtMargin.right; 3445 margins->bottom = setup->rtMargin.left; 3446 } 3447 3448 if (gdiOrientation == DMORIENT_PORTRAIT) { 3449 *orientation = PAGEFORMAT_PORTRAIT; 3450 } else { 3451 *orientation = PAGEFORMAT_LANDSCAPE; 3452 } 3453 } 3454 3455 /** 3456 * Return the number of copies to be printed for a printerJob. 3457 */ 3458 static jint getCopies(JNIEnv *env, jobject printerJob) 3459 { 3460 // Because this function may call client Java code, 3461 // we can't run it on the toolkit thread. 3462 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3463 3464 3465 jclass printerJobClass = env->GetObjectClass(printerJob); 3466 jmethodID getCopiesID = env->GetMethodID(printerJobClass, GETCOPIES_STR, 3467 GETCOPIES_SIG); 3468 CHECK_NULL_RETURN(getCopiesID, -1); 3469 jint copies = env->CallIntMethod(printerJob, getCopiesID); 3470 3471 return copies; 3472 } 3473 3474 /** 3475 * Return a copy of the Paper object attached to the 3476 * PageFormat object 'page.' 3477 */ 3478 static jobject getPaper(JNIEnv *env, jobject page) { 3479 // Because this function may call client Java code, 3480 // we can't run it on the toolkit thread. 3481 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3482 3483 3484 jclass pageClass = env->GetObjectClass(page); 3485 jmethodID getPaperID = env->GetMethodID(pageClass, GETPAPER_STR, 3486 GETPAPER_SIG); 3487 CHECK_NULL_RETURN(getPaperID, NULL); 3488 3489 return env->CallObjectMethod(page, getPaperID); 3490 } 3491 3492 /** 3493 * Set the Paper object for a PageFormat instance. 3494 * 'paper' is the new Paper object that must be 3495 * set into 'page'. 3496 */ 3497 static void setPaper(JNIEnv *env, jobject page, jobject paper) { 3498 // Because this function may call client Java code, 3499 // we can't run it on the toolkit thread. 3500 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3501 3502 jclass pageClass = env->GetObjectClass(page); 3503 jmethodID setPaperID = env->GetMethodID(pageClass, SETPAPER_STR, 3504 SETPAPER_SIG); 3505 CHECK_NULL(setPaperID); 3506 env->CallVoidMethod(page, setPaperID, paper); 3507 } 3508 3509 /** 3510 * Return the integer ID for the orientation in the PageFormat. 3511 * Caution: this is the Java spec ID, not the GDI ID. 3512 * In case of error returns -1 3513 */ 3514 static jint getPageFormatOrientation(JNIEnv *env, jobject page) { 3515 // Because this function may call client Java code, 3516 // we can't run it on the toolkit thread. 3517 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3518 3519 jclass pageClass = env->GetObjectClass(page); 3520 jmethodID getOrientID = env->GetMethodID(pageClass, GETORIENT_STR, 3521 GETORIENT_SIG); 3522 CHECK_NULL_RETURN(getOrientID, -1); 3523 return env->CallIntMethod(page, getOrientID); 3524 } 3525 3526 static void setPageFormatOrientation(JNIEnv *env, 3527 jobject page, jint orientation) { 3528 // Because this function may call client Java code, 3529 // we can't run it on the toolkit thread. 3530 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3531 3532 jclass pageClass = env->GetObjectClass(page); 3533 jmethodID setOrientID = env->GetMethodID(pageClass, SETORIENT_STR, 3534 SETORIENT_SIG); 3535 CHECK_NULL(setOrientID); 3536 env->CallVoidMethod(page, setOrientID, orientation); 3537 } 3538 3539 /** 3540 * Pull the paper size and margins out of the paper object and 3541 * return them in points. 3542 */ 3543 static void getPaperValues(JNIEnv *env, jobject paper, RectDouble *paperSize, 3544 RectDouble *margins, BOOL widthAsMargin) { 3545 // Because this function may call client Java code, 3546 // we can't run it on the toolkit thread. 3547 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3548 3549 jmethodID getID; 3550 3551 paperSize->x = 0; 3552 paperSize->y = 0; 3553 3554 jclass paperClass = env->GetObjectClass(paper); 3555 3556 getID = env->GetMethodID(paperClass, GETWIDTH_STR, GETWIDTH_SIG); 3557 CHECK_NULL(getID); 3558 paperSize->width = env->CallDoubleMethod(paper, getID); 3559 3560 getID = env->GetMethodID(paperClass, GETHEIGHT_STR, GETHEIGHT_SIG); 3561 CHECK_NULL(getID); 3562 paperSize->height = env->CallDoubleMethod(paper, getID); 3563 3564 getID = env->GetMethodID(paperClass, GETIMG_X_STR, GETIMG_X_SIG); 3565 CHECK_NULL(getID); 3566 margins->x = env->CallDoubleMethod(paper, getID); 3567 if (margins-> x < 0 ) { 3568 margins-> x = 0; 3569 } 3570 3571 getID = env->GetMethodID(paperClass, GETIMG_Y_STR, GETIMG_Y_SIG); 3572 CHECK_NULL(getID); 3573 margins->y = env->CallDoubleMethod(paper, getID); 3574 if (margins-> y < 0 ) { 3575 margins-> y = 0; 3576 } 3577 3578 getID = env->GetMethodID(paperClass, GETIMG_W_STR, GETIMG_W_SIG); 3579 CHECK_NULL(getID); 3580 if (widthAsMargin) { 3581 margins->width = paperSize->width - margins->x 3582 - env->CallDoubleMethod(paper, getID); 3583 } else { 3584 margins->width = env->CallDoubleMethod(paper, getID); 3585 } 3586 3587 if (margins->width < 0) { 3588 margins->width = 0; 3589 } 3590 3591 getID = env->GetMethodID(paperClass, GETIMG_H_STR, GETIMG_H_SIG); 3592 CHECK_NULL(getID); 3593 if (widthAsMargin) { 3594 margins->height = paperSize->height - margins->y 3595 - env->CallDoubleMethod(paper, getID); 3596 } else { 3597 margins->height = env->CallDoubleMethod(paper, getID); 3598 } 3599 3600 if (margins->height < 0) { 3601 margins->height = 0; 3602 } 3603 } 3604 3605 /** 3606 * Given a RECT specifying the margins 3607 * for the page and an indication of whether 3608 * the units are 1000ths of an inch (MM_HIENGLISH) 3609 * or 100ths of a millimeter (MM_HIMETRIC), 3610 * convert the margins to 72nds of an inch 3611 * and set them into the PageFormat insance provided. 3612 */ 3613 static void setPaperValues(JNIEnv *env, jobject paper, const POINT *paperSize, 3614 const RECT *margins, int units) { 3615 // Because this function may call client Java code, 3616 // we can't run it on the toolkit thread. 3617 DASSERT(AwtToolkit::MainThread() != ::GetCurrentThreadId()); 3618 3619 jclass paperClass = env->GetObjectClass(paper); 3620 jmethodID setSizeID = env->GetMethodID(paperClass, 3621 SETSIZE_STR, SETSIZE_SIG); 3622 CHECK_NULL(setSizeID); 3623 jmethodID setImageableID = env->GetMethodID(paperClass, 3624 SETIMAGEABLE_STR, SETIMAGEABLE_SIG); 3625 CHECK_NULL(setImageableID); 3626 3627 /* Set the physical size of the paper. 3628 */ 3629 jdouble paperWidth = convertToPoints(paperSize->x, units); 3630 jdouble paperHeight = convertToPoints(paperSize->y, units); 3631 env->CallVoidMethod(paper, setSizeID, paperWidth, paperHeight); 3632 3633 /* Set the margins of the paper. In Windows' margin RECT, 3634 * the right and bottom parts of the structure are not 3635 * really the right and bottom of the imageable rectangle, 3636 * but rather the right and bottom margins. 3637 */ 3638 jdouble x = convertToPoints(margins->left, units); 3639 jdouble y = convertToPoints(margins->top, units); 3640 long intWidth = paperSize->x - margins->left - margins->right; 3641 long intHeight = paperSize->y - margins->top - margins->bottom; 3642 jdouble width = convertToPoints(intWidth, units); 3643 jdouble height = convertToPoints(intHeight, units); 3644 env->CallVoidMethod(paper, setImageableID, x, y, width, height); 3645 } 3646 3647 /** 3648 * Convert 'value' a measurement in 1/72's of an inch to 3649 * the units specified by 'units' - either MM_HIENGLISH 3650 * MM_HIMETRIC, or MM_LOMETRIC. The converted value is returned as 3651 * a long. 3652 */ 3653 static long convertFromPoints(double value, int units) { 3654 double conversion = 0; 3655 3656 switch (units){ 3657 case MM_HIENGLISH: 3658 conversion = POINTS_TO_HIENGLISH; 3659 break; 3660 3661 case MM_HIMETRIC: 3662 conversion = POINTS_TO_HIMETRIC; 3663 break; 3664 3665 case MM_LOMETRIC: 3666 conversion = POINTS_TO_LOMETRIC; 3667 break; 3668 3669 default: 3670 assert(FALSE); // Unsupported unit. 3671 } 3672 3673 // Adding 0.5 ensures that the integer portion has the expected magnitude 3674 // before truncation occurs as result of converting from double to long. 3675 return (long) ((value * conversion) + 0.5); 3676 } 3677 3678 /** 3679 * Convert a measurement, 'value', from the units 3680 * specified by 'units', either MM_HIENGLISH or 3681 * MM_HIMETRIC to 1/72's of an inch and returned 3682 * as a double. 3683 */ 3684 static double convertToPoints(long value, int units) { 3685 double convertedValue = (double)value; 3686 3687 switch (units){ 3688 case MM_HIENGLISH: 3689 //convertedValue *= HIENGLISH_TO_POINTS; 3690 // this order of calculation is for bug 4191615 3691 convertedValue = (convertedValue*72.0) / 1000.0; 3692 break; 3693 3694 case MM_HIMETRIC: 3695 convertedValue *= HIMETRIC_TO_POINTS; 3696 break; 3697 3698 case MM_LOMETRIC: 3699 convertedValue *= LOMETRIC_TO_POINTS; 3700 break; 3701 3702 default: 3703 assert(FALSE); // Unsupported unit. 3704 } 3705 3706 //Need to round off to the precision of the initial value. FIX. 3707 3708 return convertedValue; 3709 } 3710 3711 /** 3712 * Ask the printer device context, 'printDC' about 3713 * its capabilities and set these into the WPrintJob2D 3714 * object 'self'. 3715 */ 3716 void setCapabilities(JNIEnv *env, jobject self, HDC printDC) { 3717 3718 jboolean err; 3719 // width of page in pixels 3720 jint pageWid = GetDeviceCaps(printDC, PHYSICALWIDTH); 3721 err = setIntField(env, self, PAGEW_STR, pageWid); 3722 if (err) return; 3723 3724 // height of page in pixels 3725 jint pageHgt = GetDeviceCaps(printDC, PHYSICALHEIGHT); 3726 err = setIntField(env, self, PAGEH_STR, pageHgt); 3727 if (err) return; 3728 3729 // x scaling factor of printer 3730 jint xsf = GetDeviceCaps(printDC, SCALINGFACTORX); 3731 3732 // x scaling factor of printer 3733 jint ysf = GetDeviceCaps(printDC, SCALINGFACTORY); 3734 3735 if (getOrientationFromDevMode(env, self) == DMORIENT_LANDSCAPE) { 3736 // because we do our own rotation, we should force 3737 // orientation to portrait so we will get correct page dimensions. 3738 3739 HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, self); 3740 if (hDevMode != NULL) { 3741 DEVMODE *devmode = (DEVMODE*)::GlobalLock(hDevMode); 3742 if (devmode != NULL) { 3743 devmode->dmFields |= DM_ORIENTATION; 3744 devmode->dmOrientation = DMORIENT_PORTRAIT; 3745 SAVE_CONTROLWORD 3746 ::ResetDC(printDC, devmode); 3747 RESTORE_CONTROLWORD 3748 } 3749 GlobalUnlock(hDevMode); 3750 } 3751 } 3752 3753 // pixels per inch in x direction 3754 jint xRes = GetDeviceCaps(printDC, LOGPIXELSX); 3755 err = setIntField(env, self, XRES_STR, xRes); 3756 if (err) return; 3757 3758 // pixels per inch in y direction 3759 jint yRes = GetDeviceCaps(printDC, LOGPIXELSY); 3760 err = setIntField(env, self, YRES_STR, yRes); 3761 if (err) return; 3762 3763 // x coord of printable area in pixels 3764 jint xOrg = GetDeviceCaps(printDC, PHYSICALOFFSETX); 3765 err = setIntField(env, self, PHYSX_STR, xOrg); 3766 if (err) return; 3767 3768 // y coord of printable area in pixels 3769 jint yOrg = GetDeviceCaps(printDC, PHYSICALOFFSETY); 3770 err = setIntField(env, self, PHYSY_STR, yOrg); 3771 if (err) return; 3772 3773 // width of printable area in pixels 3774 jint printWid = GetDeviceCaps(printDC, HORZRES); 3775 err = setIntField(env, self, PHYSW_STR, printWid); 3776 if (err) return; 3777 3778 // height of printable area in pixels 3779 jint printHgt = GetDeviceCaps(printDC, VERTRES); 3780 setIntField(env, self, PHYSH_STR, printHgt); 3781 } 3782 3783 static inline WORD getPrintPaperSize(JNIEnv *env, jboolean* err, jobject self) { 3784 return (WORD)getIntField(env, err, self, PRINTPAPERSIZE_STR); 3785 } 3786 3787 static inline jboolean setPrintPaperSize(JNIEnv *env, jobject self, WORD sz) { 3788 return setIntField(env, self, PRINTPAPERSIZE_STR, (jint)sz); 3789 } 3790 3791 /** 3792 * Return the java int value of the field 'fieldName' in the 3793 * java instance 'self'. 3794 */ 3795 static jint getIntField(JNIEnv *env, jboolean* err, jobject self, const char *fieldName) { 3796 return JNU_GetFieldByName(env, err, self, fieldName, "I").i; 3797 } 3798 3799 /** 3800 * Set the int field named 'fieldName' of the java instance 3801 * 'self' to the value 'value'. 3802 */ 3803 static jboolean setIntField(JNIEnv *env, jobject self, const char *fieldName, jint value) { 3804 jboolean err; 3805 JNU_SetFieldByName(env, &err, self, fieldName, "I", value); 3806 return err; 3807 } 3808 3809 static jboolean getBooleanField(JNIEnv *env, jboolean* err, jobject self, const char *fieldName) { 3810 return JNU_GetFieldByName(env, err, self, fieldName, "Z").z; 3811 } 3812 3813 static jboolean setBooleanField(JNIEnv *env, jobject self, const char *fieldName, jboolean value) { 3814 jboolean err; 3815 JNU_SetFieldByName(env, &err, self, fieldName, "Z", value); 3816 return err; 3817 } 3818 3819 /** 3820 * Throw a PrinterException with a string describing 3821 * the Window's system error 'err'. 3822 */ 3823 static void throwPrinterException(JNIEnv *env, DWORD err) { 3824 char errStr[256]; 3825 TCHAR t_errStr[256]; 3826 errStr[0] = '\0'; 3827 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 3828 NULL, 3829 err, 3830 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 3831 t_errStr, 3832 sizeof(t_errStr), 3833 NULL ); 3834 3835 WideCharToMultiByte(CP_UTF8, 0, t_errStr, -1, 3836 errStr, sizeof(errStr), NULL, NULL); 3837 JNU_ThrowByName(env, PRINTEREXCEPTION_STR, errStr); 3838 } 3839 3840 3841 /* 3842 * Finds the closest matching paper size for the printer. 3843 * Parameters are in 72ndths of an inch. 3844 * paperSize is the win32 integer identifier for a paper size. 3845 * Requires an initialised set of printer device structures. 3846 * Updates the printDC to specify the matched paper size. 3847 * If the passed in paper size is non-zero, its taken to be a windows 3848 * paper size "name", and we check that paper size against the paper 3849 * we are matching and prefer that name over other names which also match 3850 * the size. 3851 */ 3852 static void matchPaperSize(HDC printDC, HGLOBAL hDevMode, HGLOBAL hDevNames, 3853 double origWid, double origHgt, 3854 double* newWid, double *newHgt, 3855 WORD* paperSize) { 3856 3857 // Tolerated differences in comparing page dimensions between passed in 3858 // "orig" media with that of Windows' device. 3859 const double epsilon = 3.6; // (1/72) of an inch 3860 const double tolerance = (1.0 * 72.0); // # inches * 72 3861 3862 *newWid = origWid; 3863 *newHgt = origHgt; 3864 3865 /* 1st check if the DC/Devmode has as its current papersize a paper 3866 * which matches the paper specified. If yes, then we can skip hunting 3867 * for the match and in the process we avoid finding a "name" for 3868 * the paper size which isn't the one the user specified in the page 3869 * setup dialog. For example "11x17" is also "Ledger". 3870 */ 3871 if (printDC != NULL) { 3872 // pixels per inch in x and y direction 3873 jint xPixelRes = GetDeviceCaps(printDC, LOGPIXELSX); 3874 jint yPixelRes = GetDeviceCaps(printDC, LOGPIXELSY); 3875 3876 // width and height of page in pixels 3877 jint pagePixelWid = GetDeviceCaps(printDC, PHYSICALWIDTH); 3878 jint pagePixelHgt = GetDeviceCaps(printDC, PHYSICALHEIGHT); 3879 3880 // page size in 1/72" 3881 jdouble paperWidth = (jdouble)((pagePixelWid * 72)/(jdouble)xPixelRes); 3882 jdouble paperHeight = (jdouble)((pagePixelHgt * 72)/(jdouble)yPixelRes); 3883 3884 if ((fabs(origWid - paperWidth) < epsilon) && 3885 (fabs(origHgt - paperHeight) < epsilon) && 3886 (*paperSize == 0)) { 3887 3888 *newWid = origWid; 3889 *newHgt = origHgt; 3890 3891 if (hDevMode != NULL) { 3892 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 3893 if (devmode != NULL && (devmode->dmFields & DM_PAPERSIZE)) { 3894 *paperSize = devmode->dmPaperSize; 3895 } 3896 ::GlobalUnlock(hDevMode); 3897 } 3898 return; 3899 } 3900 } 3901 3902 /* begin trying to match papers */ 3903 3904 LPTSTR printer = NULL, port = NULL; 3905 if (hDevNames != NULL) { 3906 DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); 3907 if (devnames != NULL) { 3908 LPTSTR lpdevnames = (LPTSTR)devnames; 3909 printer = _tcsdup(lpdevnames+devnames->wDeviceOffset); 3910 port = _tcsdup(lpdevnames+devnames->wOutputOffset); 3911 } 3912 ::GlobalUnlock(hDevNames); 3913 } 3914 3915 //REMIND: code duplicated in AwtPrintControl::getNearestMatchingPaper 3916 int numPaperSizes = 0; 3917 WORD *papers = NULL; 3918 POINT *paperSizes = NULL; 3919 3920 SAVE_CONTROLWORD 3921 numPaperSizes = (int)DeviceCapabilities(printer, port, DC_PAPERSIZE, 3922 NULL, NULL); 3923 if (numPaperSizes > 0) { 3924 try { 3925 papers = (WORD*)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(WORD), numPaperSizes); 3926 paperSizes = (POINT *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, sizeof(*paperSizes), numPaperSizes); 3927 } catch (std::bad_alloc&) { 3928 if (papers != NULL) { 3929 free((char*)papers); 3930 papers = NULL; 3931 } 3932 if (paperSizes != NULL) { 3933 free((char *)paperSizes); 3934 paperSizes = NULL; 3935 } 3936 } 3937 3938 if (papers != NULL && paperSizes != NULL) { 3939 DWORD result1 = DeviceCapabilities(printer, port, 3940 DC_PAPERS, (LPTSTR) papers, NULL); 3941 DWORD result2 = DeviceCapabilities(printer, port, 3942 DC_PAPERSIZE, (LPTSTR) paperSizes, 3943 NULL); 3944 3945 if (result1 == -1 || result2 == -1 ) { 3946 free((char *) papers); 3947 papers = NULL; 3948 free((char *) paperSizes); 3949 paperSizes = NULL; 3950 } 3951 } 3952 } 3953 3954 RESTORE_CONTROLWORD 3955 double closestWid = 0.0; 3956 double closestHgt = 0.0; 3957 WORD closestMatch = 0; 3958 3959 if (paperSizes != NULL) { 3960 3961 /* Paper sizes are in 0.1mm units. Convert to 1/72" 3962 * For each paper size, compute the difference from the paper size 3963 * passed in. Use a least-squares difference, so paper much different 3964 * in x or y should score poorly 3965 */ 3966 double diffw = origWid; 3967 double diffh = origHgt; 3968 double least_square = diffw * diffw + diffh * diffh; 3969 double tmp_ls; 3970 double widpts, hgtpts; 3971 3972 for (int i=0;i<numPaperSizes;i++) { 3973 widpts = paperSizes[i].x * LOMETRIC_TO_POINTS; 3974 hgtpts = paperSizes[i].y * LOMETRIC_TO_POINTS; 3975 3976 if ((fabs(origWid - widpts) < epsilon) && 3977 (fabs(origHgt - hgtpts) < epsilon)) { 3978 3979 if ((*paperSize == 0) || ((*paperSize !=0) && 3980 (papers[i]==*paperSize))) { 3981 closestWid = origWid; 3982 closestHgt = origHgt; 3983 closestMatch = papers[i]; 3984 break; 3985 } 3986 } 3987 3988 diffw = fabs(widpts - origWid); 3989 diffh = fabs(hgtpts - origHgt); 3990 tmp_ls = diffw * diffw + diffh * diffh; 3991 if ((diffw < tolerance) && (diffh < tolerance) && 3992 (tmp_ls < least_square)) { 3993 least_square = tmp_ls; 3994 closestWid = widpts; 3995 closestHgt = hgtpts; 3996 closestMatch = papers[i]; 3997 } 3998 } 3999 } 4000 4001 if (closestWid > 0) { 4002 *newWid = closestWid; 4003 } 4004 if (closestHgt > 0) { 4005 *newHgt = closestHgt; 4006 } 4007 4008 *paperSize = closestMatch; 4009 4010 /* At this point we have the paper which is the closest match 4011 * We now need to select the paper into the DEVMODE, and 4012 * get a DC which matches so we can get the margins. 4013 */ 4014 4015 if ((printDC != NULL) && (hDevMode != NULL) && (closestMatch != 0)) { 4016 DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); 4017 if ((devmode != NULL) && (closestMatch != devmode->dmPaperSize)) { 4018 devmode->dmFields |= DM_PAPERSIZE; 4019 devmode->dmPaperSize = closestMatch; 4020 ::ResetDC(printDC, devmode); 4021 RESTORE_CONTROLWORD 4022 } 4023 ::GlobalUnlock(hDevMode); 4024 } 4025 4026 if (printer != NULL) { 4027 free((char *)printer); 4028 } 4029 if (port != NULL) { 4030 free((char *)port); 4031 } 4032 if (papers != NULL) { 4033 free((char *)papers); 4034 } 4035 if (paperSizes != NULL) { 4036 free((char *)paperSizes); 4037 } 4038 4039 } 4040 4041 4042 static BOOL SetPrinterDevice(LPTSTR pszDeviceName, HGLOBAL* p_hDevMode, 4043 HGLOBAL* p_hDevNames) 4044 { 4045 // Open printer and obtain PRINTER_INFO_2 structure. 4046 HANDLE hPrinter; 4047 if (::OpenPrinter(pszDeviceName, &hPrinter, NULL) == FALSE) 4048 return FALSE; 4049 4050 DWORD dwBytesReturned, dwBytesNeeded; 4051 ::GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded); 4052 PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)::GlobalAlloc(GPTR, 4053 dwBytesNeeded); 4054 if (p2 == NULL) { 4055 ::ClosePrinter(hPrinter); 4056 return FALSE; 4057 } 4058 4059 if (::GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded, 4060 &dwBytesReturned) == 0) { 4061 ::GlobalFree(p2); 4062 ::ClosePrinter(hPrinter); 4063 return FALSE; 4064 } 4065 4066 DEVMODE *pDevMode = NULL; 4067 HGLOBAL hDevMode = NULL; 4068 /* If GetPrinter didn't fill in the DEVMODE, try to get it by calling 4069 DocumentProperties... 4070 */ 4071 if (p2->pDevMode == NULL){ 4072 SAVE_CONTROLWORD 4073 LONG bytesNeeded = ::DocumentProperties(NULL, hPrinter, 4074 pszDeviceName, 4075 NULL, NULL, 0); 4076 RESTORE_CONTROLWORD 4077 4078 if (bytesNeeded <= 0) { 4079 ::GlobalFree(p2); 4080 ::ClosePrinter(hPrinter); 4081 return FALSE; 4082 } 4083 4084 hDevMode = ::GlobalAlloc(GHND, bytesNeeded); 4085 if (hDevMode == NULL) { 4086 ::GlobalFree(p2); 4087 ::ClosePrinter(hPrinter); 4088 return FALSE; 4089 } 4090 4091 pDevMode = (DEVMODE*)::GlobalLock(hDevMode); 4092 if (pDevMode == NULL) { 4093 ::GlobalFree(hDevMode); 4094 ::GlobalFree(p2); 4095 ::ClosePrinter(hPrinter); 4096 return FALSE; 4097 } 4098 4099 LONG lFlag = ::DocumentProperties(NULL, hPrinter, 4100 pszDeviceName, 4101 pDevMode, NULL, 4102 DM_OUT_BUFFER); 4103 RESTORE_CONTROLWORD 4104 if (lFlag != IDOK) { 4105 ::GlobalUnlock(hDevMode); 4106 ::GlobalFree(hDevMode); 4107 ::GlobalFree(p2); 4108 ::ClosePrinter(hPrinter); 4109 return FALSE; 4110 } 4111 4112 } else { 4113 // Allocate a global handle for DEVMODE and copy DEVMODE data. 4114 hDevMode = ::GlobalAlloc(GHND, 4115 (sizeof(*p2->pDevMode) + p2->pDevMode->dmDriverExtra)); 4116 if (hDevMode == NULL) { 4117 ::GlobalFree(p2); 4118 ::ClosePrinter(hPrinter); 4119 return FALSE; 4120 } 4121 4122 pDevMode = (DEVMODE*)::GlobalLock(hDevMode); 4123 if (pDevMode == NULL) { 4124 ::GlobalFree(hDevMode); 4125 ::GlobalFree(p2); 4126 ::ClosePrinter(hPrinter); 4127 return FALSE; 4128 } 4129 4130 memcpy(pDevMode, p2->pDevMode, 4131 sizeof(*p2->pDevMode) + p2->pDevMode->dmDriverExtra); 4132 } 4133 4134 ::GlobalUnlock(hDevMode); 4135 ::ClosePrinter(hPrinter); 4136 4137 // Compute size of DEVNAMES structure you'll need. 4138 // All sizes are WORD as in DEVNAMES structure 4139 // All offsets are in characters, not in bytes 4140 WORD drvNameLen = static_cast<WORD>(_tcslen(p2->pDriverName)); // driver name 4141 WORD ptrNameLen = static_cast<WORD>(_tcslen(p2->pPrinterName)); // printer name 4142 WORD porNameLen = static_cast<WORD>(_tcslen(p2->pPortName)); // port name 4143 WORD devNameSize = static_cast<WORD>(sizeof(DEVNAMES)) + 4144 (ptrNameLen + porNameLen + drvNameLen + 3)*sizeof(TCHAR); 4145 4146 // Allocate a global handle big enough to hold DEVNAMES. 4147 HGLOBAL hDevNames = ::GlobalAlloc(GHND, devNameSize); 4148 DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); 4149 4150 // Copy the DEVNAMES information from PRINTER_INFO_2 structure. 4151 pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(TCHAR); 4152 memcpy((LPTSTR)pDevNames + pDevNames->wDriverOffset, 4153 p2->pDriverName, drvNameLen*sizeof(TCHAR)); 4154 4155 pDevNames->wDeviceOffset = static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR)) + 4156 drvNameLen + 1; 4157 memcpy((LPTSTR)pDevNames + pDevNames->wDeviceOffset, 4158 p2->pPrinterName, ptrNameLen*sizeof(TCHAR)); 4159 4160 pDevNames->wOutputOffset = static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR)) + 4161 drvNameLen + ptrNameLen + 2; 4162 memcpy((LPTSTR)pDevNames + pDevNames->wOutputOffset, 4163 p2->pPortName, porNameLen*sizeof(TCHAR)); 4164 4165 pDevNames->wDefault = 0; 4166 4167 ::GlobalUnlock(hDevNames); 4168 ::GlobalFree(p2); // free PRINTER_INFO_2 4169 4170 *p_hDevMode = hDevMode; 4171 *p_hDevNames = hDevNames; 4172 4173 return TRUE; 4174 } 4175 4176 4177 JNIEXPORT void JNICALL 4178 Java_sun_awt_windows_WPrinterJob_setNativePrintService(JNIEnv *env, 4179 jobject name, 4180 jstring printer) 4181 { 4182 TRY; 4183 LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, printer, NULL); 4184 CHECK_NULL(printerName); 4185 4186 HDC hDC = AwtPrintControl::getPrintDC(env, name); 4187 if (hDC != NULL) { 4188 DeletePrintDC(hDC); 4189 hDC = NULL; 4190 } 4191 4192 SAVE_CONTROLWORD 4193 hDC = ::CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL); 4194 RESTORE_CONTROLWORD 4195 if (hDC == NULL) { 4196 JNU_ThrowByName(env, PRINTEREXCEPTION_STR, "Invalid name of PrintService."); 4197 JNU_ReleaseStringPlatformChars(env, printer, printerName); 4198 return; 4199 } 4200 AwtPrintControl::setPrintDC(env, name, hDC); 4201 4202 HANDLE hDevMode = AwtPrintControl::getPrintHDMode(env, name); 4203 if (hDevMode != NULL) { 4204 ::GlobalFree(hDevMode); 4205 hDevMode = NULL; 4206 } 4207 4208 HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, name);; 4209 if (hDevNames != NULL) { 4210 ::GlobalFree(hDevNames); 4211 hDevNames = NULL; 4212 } 4213 4214 SetPrinterDevice(printerName, &hDevMode, &hDevNames); 4215 4216 AwtPrintControl::setPrintHDMode(env, name, hDevMode); 4217 AwtPrintControl::setPrintHDName(env, name, hDevNames); 4218 4219 // Driver capability for copies & collation are not set 4220 // when printDialog and getDefaultPrinterDC are not called. 4221 // set DRIVER_COPIES_STR and DRIVER_COLLATE_STR 4222 DEVMODE *devmode = NULL; 4223 if (hDevMode != NULL) { 4224 devmode = (DEVMODE *)::GlobalLock(hDevMode); 4225 DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE))); 4226 } 4227 4228 if (devmode != NULL) { 4229 if (devmode->dmFields & DM_COPIES) { 4230 jboolean err = setBooleanField(env, name, DRIVER_COPIES_STR, JNI_TRUE); 4231 if (err) { 4232 JNU_ReleaseStringPlatformChars(env, printer, printerName); 4233 return; 4234 } 4235 } 4236 4237 if (devmode->dmFields & DM_COLLATE) { 4238 jboolean err = setBooleanField(env, name, DRIVER_COLLATE_STR, JNI_TRUE); 4239 if (err) { 4240 JNU_ReleaseStringPlatformChars(env, printer, printerName); 4241 return; 4242 } 4243 } 4244 4245 ::GlobalUnlock(hDevMode); 4246 } 4247 4248 setCapabilities(env, name, hDC); 4249 4250 JNU_ReleaseStringPlatformChars(env, printer, printerName); 4251 CATCH_BAD_ALLOC; 4252 } 4253 4254 4255 JNIEXPORT jstring JNICALL 4256 Java_sun_awt_windows_WPrinterJob_getNativePrintService(JNIEnv *env, 4257 jobject name) 4258 { 4259 TRY; 4260 jstring printer; 4261 HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, name); 4262 if (hDevNames == NULL) { 4263 return NULL; 4264 } 4265 DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); 4266 4267 printer = JNU_NewStringPlatform(env, 4268 (LPTSTR)pDevNames+pDevNames->wDeviceOffset); 4269 ::GlobalUnlock(hDevNames); 4270 return printer; 4271 4272 CATCH_BAD_ALLOC_RET(0); 4273 } 4274 4275 static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin) 4276 { 4277 if (pdc == NULL) { 4278 return FALSE; 4279 } 4280 4281 DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(hDevMode); 4282 if (pDevMode == NULL) { 4283 return FALSE; 4284 } 4285 4286 SAVE_CONTROLWORD 4287 ::ResetDC(pdc, pDevMode); 4288 RESTORE_CONTROLWORD 4289 4290 int left = GetDeviceCaps(pdc, PHYSICALOFFSETX); 4291 int top = GetDeviceCaps(pdc, PHYSICALOFFSETY); 4292 int width = GetDeviceCaps(pdc, HORZRES); 4293 int height = GetDeviceCaps(pdc, VERTRES); 4294 int resx = GetDeviceCaps(pdc, LOGPIXELSX); 4295 int resy = GetDeviceCaps(pdc, LOGPIXELSY); 4296 4297 4298 margin->x = (jdouble)left/resx; 4299 margin->y =(jdouble)top/resy; 4300 margin->width = (jdouble)width/resx; 4301 margin->height = (jdouble)height/resy; 4302 4303 ::GlobalUnlock(hDevMode); 4304 4305 return TRUE; 4306 } 4307 4308 JNIEXPORT void JNICALL 4309 Java_sun_awt_windows_WPrinterJob_initIDs(JNIEnv *env, jclass cls) 4310 { 4311 TRY; 4312 4313 AwtPrintDialog::controlID = env->GetFieldID(cls, "pjob", "Ljava/awt/print/PrinterJob;"); 4314 DASSERT(AwtPrintDialog::controlID != NULL); 4315 CHECK_NULL(AwtPrintDialog::controlID); 4316 4317 jclass printDialogPeerClass = env->FindClass("sun/awt/windows/WPrintDialogPeer"); 4318 CHECK_NULL(printDialogPeerClass); 4319 AwtPrintDialog::setHWndMID = env->GetMethodID(printDialogPeerClass, "setHWnd", "(J)V"); 4320 DASSERT(AwtPrintDialog::setHWndMID != NULL); 4321 CHECK_NULL(AwtPrintDialog::setHWndMID); 4322 4323 AwtPrintControl::initIDs(env, cls); 4324 CATCH_BAD_ALLOC; 4325 } 4326 4327 } /* extern "C" */