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