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