1 /*
   2  * Copyright (c) 1996, 2016, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 #include "awt.h"
  27 #include <math.h>
  28 #include <windef.h>
  29 #include <wtypes.h>
  30 #include <winuser.h>
  31 #include <commdlg.h>
  32 #include <winspool.h>
  33 
  34 #include "awt_Toolkit.h"
  35 #include "awt_Component.h"
  36 #include "awt_Dialog.h"
  37 #include "awt_Font.h"
  38 #include "awt_PrintDialog.h"
  39 #include "awt_PrintControl.h"
  40 #include "awt_Window.h"
  41 #include "ComCtl32Util.h"
  42 
  43 #include <sun_awt_windows_WPrinterJob.h>
  44 #include <jlong_md.h>
  45 #include <float.h>
  46 
  47 #define DEBUG_PRINTING  0
  48 
  49 /* Round 'num' to the nearest integer and return
  50  * the result as a long.
  51  */
  52 #define ROUND_TO_LONG(num)    ((long) floor((num) + 0.5))
  53 
  54 /* Round 'num' to the nearest integer and return
  55  * the result as an int.
  56  */
  57 #define ROUND_TO_INT(num)     ((int) floor((num) + 0.5))
  58 
  59 /************************************************************************
  60  * WPrintJob native methods
  61  */
  62 
  63 extern "C" {
  64 
  65 /*** Private Constants ***/
  66 
  67 static char *kJavaIntStr = "I";
  68 static char *kJavaLongStr = "J";
  69 
  70 /* 2D printing uses 3 byte BGR pixels in Raster printing */
  71 static int J2DRasterBPP = 3;
  72 
  73 /*
  74  * Class Names
  75  */
  76 static const char *PRINTEREXCEPTION_STR = "java/awt/print/PrinterException";
  77 
  78 /*
  79  * The following strings are the names of instance variables in WPrintJob2D.
  80  */
  81 static const char *PRINTPAPERSIZE_STR = "mPrintPaperSize"; // The paper size
  82 static const char *XRES_STR = "mPrintXRes";     // The x dpi.
  83 static const char *YRES_STR = "mPrintYRes";     // The y dpi.
  84 static const char *PHYSX_STR = "mPrintPhysX";   // pixel x of printable area
  85 static const char *PHYSY_STR = "mPrintPhysY";   // pixel y of printable area
  86 static const char *PHYSW_STR = "mPrintWidth";   // pixel wid of printable area
  87 static const char *PHYSH_STR = "mPrintHeight";  // pixel hgt of printable area
  88 static const char *PAGEW_STR = "mPageWidth";    // pixel wid of page
  89 static const char *PAGEH_STR = "mPageHeight";   // pixel hgt of page
  90 
  91 static const char *DRIVER_COPIES_STR = "driverDoesMultipleCopies";
  92 static const char *DRIVER_COLLATE_STR = "driverDoesCollation";
  93 static const char *USER_COLLATE_STR = "userRequestedCollation";
  94 static const char *NO_DEFAULTPRINTER_STR = "noDefaultPrinter";
  95 static const char *LANDSCAPE_270_STR = "landscapeRotates270";
  96 
  97 
  98 // public int java.awt.print.PrinterJob.getCopies()
  99 
 100 static const char *GETCOPIES_STR = "getCopies";
 101 static const char *GETCOPIES_SIG = "()I";
 102 
 103 /*
 104  * Methods and fields in awt.print.PageFormat.
 105  */
 106 
 107 // public Paper getPaper()
 108 static const char *GETPAPER_STR = "getPaper";
 109 static const char *GETPAPER_SIG = "()Ljava/awt/print/Paper;";
 110 
 111 // public void setPaper(Paper paper)
 112 static const char *SETPAPER_STR = "setPaper";
 113 static const char *SETPAPER_SIG = "(Ljava/awt/print/Paper;)V";
 114 
 115 // public int getOrientation()
 116 static const char *GETORIENT_STR = "getOrientation";
 117 static const char *GETORIENT_SIG = "()I";
 118 
 119 // public void setOrientation(int orientation)
 120 static const char *SETORIENT_STR = "setOrientation";
 121 static const char *SETORIENT_SIG = "(I)V";
 122 
 123 static const int PAGEFORMAT_LANDSCAPE = 0;
 124 static const int PAGEFORMAT_PORTRAIT = 1;
 125 //static const int PAGEFORMAT_REVERSELANDSCAPE = 2;
 126 
 127 // instance variables for PrintRequestAttribute settings
 128 static const char *ATTSIDES_STR = "mAttSides";
 129 static const char *ATTCHROMATICITY_STR = "mAttChromaticity";
 130 static const char *ATTXRES_STR = "mAttXRes";
 131 static const char *ATTYRES_STR = "mAttYRes";
 132 static const char *ATTQUALITY_STR = "mAttQuality";
 133 static const char *ATTCOLLATE_STR = "mAttCollate";
 134 static const char *ATTCOPIES_STR = "mAttCopies";
 135 static const char *ATTMEDIASZNAME_STR = "mAttMediaSizeName";
 136 static const char *ATTMEDIATRAY_STR = "mAttMediaTray";
 137 
 138 /*
 139  * Methods in awt.print.Paper.
 140  */
 141 
 142 // public void setSize(double width, double height)
 143 static const char *SETSIZE_STR = "setSize";
 144 static const char *SETSIZE_SIG = "(DD)V";
 145 
 146 // protected void setImageableArea(double x, double y, double width,
 147 //                                                  double height)
 148 static const char *SETIMAGEABLE_STR = "setImageableArea";
 149 static const char *SETIMAGEABLE_SIG = "(DDDD)V";
 150 
 151 // public double getWidth()
 152 static const char *GETWIDTH_STR = "getWidth";
 153 static const char *GETWIDTH_SIG = "()D";
 154 
 155 // public double getHeight()
 156 static const char *GETHEIGHT_STR = "getHeight";
 157 static const char *GETHEIGHT_SIG = "()D";
 158 
 159 // public double getImageableX()
 160 static const char *GETIMG_X_STR = "getImageableX";
 161 static const char *GETIMG_X_SIG = "()D";
 162 
 163 // public double getImageableY()
 164 static const char *GETIMG_Y_STR = "getImageableY";
 165 static const char *GETIMG_Y_SIG = "()D";
 166 
 167 // public double getImageableWidth()
 168 static const char *GETIMG_W_STR = "getImageableWidth";
 169 static const char *GETIMG_W_SIG = "()D";
 170 
 171 // public double getImageableHeight()
 172 static const char *GETIMG_H_STR = "getImageableHeight";
 173 static const char *GETIMG_H_SIG = "()D";
 174 
 175 /* Multiply a Window's MM_HIENGLISH value
 176  * (1000th of an inch) by this number to
 177  * get a value in 72nds of an inch.
 178  */
 179 static const double HIENGLISH_TO_POINTS = (72.0 / 1000.0);
 180 
 181 /* Multiply a Window's MM_HIMETRIC value
 182  * (100ths of a millimeter) by this
 183  * number to get a value in 72nds of an inch.
 184  */
 185 static const double HIMETRIC_TO_POINTS = (72.0 / 2540.0);
 186 
 187 /* Multiply a Window's MM_LOMETRIC value
 188  * (10ths of a millimeter) by this
 189  * number to get a value in 72nds of an inch.
 190  */
 191 static const double LOMETRIC_TO_POINTS = (72.0 / 254.0);
 192 
 193 /* Multiply a measurement in 1/72's of an inch by this
 194  * value to convert it to Window's MM_HIENGLISH
 195  * (1000th of an inch) units.
 196  */
 197 static const double POINTS_TO_HIENGLISH = (1000.0 / 72.0);
 198 
 199 /* Multiply a measurement in 1/72's of an inch by this
 200  * value to convert it to Window's MM_HIMETRIC
 201  * (100th of an millimeter) units.
 202  */
 203 static const double POINTS_TO_HIMETRIC = (2540.0 / 72.0);
 204 
 205 /* Multiply a measurement in 1/72's of an inch by this
 206  * value to convert it to Window's MM_LOMETRIC
 207  * (10th of an millimeter) units.
 208  */
 209 static const double POINTS_TO_LOMETRIC = (254.0 / 72.0);
 210 
 211 jfieldID AwtPrintDialog::pageID;
 212 
 213 
 214 /*** Private Macros ***/
 215 
 216 /* A Page Setup paint hook passes a word describing the
 217    orientation and type of page being displayed in the
 218    dialog. These macros break the word down into meaningful
 219    values.
 220 */
 221 #define PRINTER_TYPE_MASK   (0x0003)
 222 #define PORTRAIT_MASK       (0x0004)
 223 #define ENVELOPE_MASK       (0x0008)
 224 
 225 #define IS_ENVELOPE(param)  (((param) & ENVELOPE_MASK) != 0)
 226 #define IS_PORTRAIT(param)  (((param) & PORTRAIT_MASK) != 0)
 227 
 228 /*      If the Pagable does not know the number of pages in the document,
 229         then we limit the print dialog to this number of pages.
 230 */
 231 #define MAX_UNKNOWN_PAGES 9999
 232 
 233 /* When making a font that is already at least bold,
 234  * bolder then we increase the LOGFONT lfWeight field
 235  * by this amount.
 236  */
 237 #define EMBOLDEN_WEIGHT   (100)
 238 
 239 /* The lfWeight field of a GDI LOGFONT structure should not
 240  * exceed this value.
 241  */
 242 #define MAX_FONT_WEIGHT   (1000)
 243 
 244 /*** Private Variable Types ***/
 245 
 246 typedef struct {
 247     jdouble x;
 248     jdouble y;
 249     jdouble width;
 250     jdouble height;
 251 } RectDouble;
 252 
 253 /*** Private Prototypes ***/
 254 
 255 static UINT CALLBACK pageDlgHook(HWND hDlg, UINT msg,
 256                                  WPARAM wParam, LPARAM lParam);
 257 static void initPrinter(JNIEnv *env, jobject self);
 258 static HDC getDefaultPrinterDC(JNIEnv *env, jobject printerJob);
 259 static void pageFormatToSetup(JNIEnv *env, jobject job, jobject page,
 260                               PAGESETUPDLG *setup, HDC hDC);
 261 static WORD getOrientationFromDevMode2(HGLOBAL hDevMode);
 262 static WORD getOrientationFromDevMode(JNIEnv *env, jobject self);
 263 static void setOrientationInDevMode(HGLOBAL hDevMode, jboolean isPortrait);
 264 static void doPrintBand(JNIEnv *env, jboolean browserPrinting,
 265                         HDC printDC, jbyteArray imageArray,
 266                         jint x, jint y, jint width, jint height);
 267 static int bitsToDevice(HDC printDC, jbyte *image, long destX, long destY,
 268                         long width, long height);
 269 static void retrievePaperInfo(const PAGESETUPDLG *setup, POINT *paperSize,
 270                               RECT *margins, jint *orientation,
 271                               HDC hdc);
 272 static jint getCopies(JNIEnv *env, jobject printerJob);
 273 static jobject getPaper(JNIEnv *env, jobject page);
 274 static void setPaper(JNIEnv *env, jobject page, jobject paper);
 275 static jint getPageFormatOrientation(JNIEnv *env, jobject page);
 276 static void setPageFormatOrientation(JNIEnv *env, jobject page, jint orient);
 277 static void getPaperValues(JNIEnv *env, jobject paper, RectDouble *paperSize,
 278                           RectDouble *margins, BOOL widthAsMargin=TRUE);
 279 static void setPaperValues(JNIEnv *env, jobject paper, const POINT *paperSize,
 280                             const RECT *margins, int units);
 281 static long convertFromPoints(double value, int units);
 282 static double convertToPoints(long value, int units);
 283 void setCapabilities(JNIEnv *env, jobject self, HDC printDC);
 284 static inline WORD getPrintPaperSize(JNIEnv *env, jboolean* err, jobject self);
 285 static inline jboolean setPrintPaperSize(JNIEnv *env, jobject self, WORD sz);
 286 static jint getIntField(JNIEnv *env, jboolean* err, jobject self, const char *fieldName);
 287 static jboolean setIntField(JNIEnv *env, jobject self,
 288                         const char *fieldName, jint value);
 289 static jboolean getBooleanField(JNIEnv *env, jboolean* err, jobject self,
 290                             const char *fieldName);
 291 static jboolean setBooleanField(JNIEnv *env, jobject self,
 292                             const char *fieldName, jboolean value);
 293 static jbyte *findNonWhite(jbyte *image, long sy, long width, long height,
 294                            long scanLineStride, long *numLinesP);
 295 static jbyte *findWhite(jbyte *image, long sy, long width, long height,
 296                            long scanLineStride, long *numLines);
 297 static void dumpDevMode(HGLOBAL hDevMode);
 298 static void dumpPrinterCaps(HANDLE hDevNames);
 299 static void throwPrinterException(JNIEnv *env, DWORD err);
 300 static void matchPaperSize(HDC printDC, HGLOBAL hDevMode, HGLOBAL hDevNames,
 301                            double origWid, double origHgt,
 302                            double* newHgt, double *newWid,
 303                            WORD* paperSize);
 304 
 305 /***********************************************************************/
 306 
 307 static jboolean jFontToWFontW(JNIEnv *env, HDC printDC, jstring fontName,
 308                         jfloat fontSize, jboolean isBold, jboolean isItalic,
 309                         jint rotation, jfloat awScale);
 310 static jboolean jFontToWFontA(JNIEnv *env, HDC printDC, jstring fontName,
 311                         jfloat fontSize, jboolean isBold, jboolean isItalic,
 312                         jint rotation, jfloat awScale);
 313 
 314 static int CALLBACK fontEnumProcW(ENUMLOGFONTEXW  *lpelfe,
 315                                  NEWTEXTMETRICEX *lpntme,
 316                                  int FontType,
 317                                  LPARAM lParam);
 318 static int CALLBACK fontEnumProcA(ENUMLOGFONTEXA  *logfont,
 319                                   NEWTEXTMETRICEX  *lpntme,
 320                                   int FontType,
 321                                   LPARAM lParam);
 322 
 323 static int embolden(int currentWeight);
 324 static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin);
 325 
 326 
 327 
 328 /************************************************************************
 329  * DocumentProperties native support
 330  */
 331 
 332 /* Values must match those defined in WPrinterJob.java */
 333 static const DWORD SET_COLOR = 0x00000200;
 334 static const DWORD SET_ORIENTATION = 0x00004000;
 335 static const DWORD SET_COLLATED    = 0x00008000;
 336 static const DWORD SET_DUP_VERTICAL = 0x00000010;
 337 static const DWORD SET_DUP_HORIZONTAL = 0x00000020;
 338 static const DWORD SET_RES_HIGH = 0x00000040;
 339 static const DWORD SET_RES_LOW = 0x00000080;
 340 
 341 /*
 342  * Copy DEVMODE state back into JobAttributes.
 343  */
 344 
 345 static void UpdateJobAttributes(JNIEnv *env,
 346                                 jobject wJob,
 347                                 jobject attrSet,
 348                                 DEVMODE *devmode) {
 349 
 350     DWORD dmValues = 0;
 351     int xRes = 0, yRes = 0;
 352 
 353     if (devmode->dmFields & DM_COLOR) {
 354         if (devmode->dmColor == DMCOLOR_COLOR) {
 355             dmValues |= SET_COLOR;
 356         }
 357     }
 358 
 359     if (devmode->dmFields & DM_ORIENTATION) {
 360         if (devmode->dmOrientation == DMORIENT_LANDSCAPE) {
 361             dmValues |= SET_ORIENTATION;
 362         }
 363     }
 364 
 365     if (devmode->dmFields & DM_COLLATE &&
 366         devmode->dmCollate == DMCOLLATE_TRUE) {
 367             dmValues |= SET_COLLATED;
 368     }
 369 
 370     if (devmode->dmFields & DM_PRINTQUALITY) {
 371         /* value < 0 indicates quality setting.
 372          * value > 0 indicates X resolution. In that case
 373          * hopefully we will also find y-resolution specified.
 374          * If its not, assume its the same as x-res.
 375          * Maybe Java code should try to reconcile this against
 376           * the printers claimed set of supported resolutions.
 377          */
 378         if (devmode->dmPrintQuality < 0) {
 379             if (devmode->dmPrintQuality == DMRES_HIGH) {
 380                 dmValues |= SET_RES_HIGH;
 381             } else if ((devmode->dmPrintQuality == DMRES_LOW) ||
 382                        (devmode->dmPrintQuality == DMRES_DRAFT)) {
 383                 dmValues |= SET_RES_LOW;
 384             }
 385             /* else if (devmode->dmPrintQuality == DMRES_MEDIUM)
 386              * will set to NORMAL.
 387              */
 388         } else {
 389             xRes = devmode->dmPrintQuality;
 390             yRes = (devmode->dmFields & DM_YRESOLUTION) ?
 391                 devmode->dmYResolution : devmode->dmPrintQuality;
 392         }
 393     }
 394 
 395     if (devmode->dmFields & DM_DUPLEX) {
 396         if (devmode->dmDuplex == DMDUP_HORIZONTAL) {
 397             dmValues |= SET_DUP_HORIZONTAL;
 398         } else if (devmode->dmDuplex == DMDUP_VERTICAL) {
 399             dmValues |= SET_DUP_VERTICAL;
 400         }
 401     }
 402 
 403     env->CallVoidMethod(wJob, AwtPrintControl::setJobAttributesID, attrSet,
 404                         devmode->dmFields, dmValues, devmode->dmCopies,
 405                         devmode->dmPaperSize, devmode->dmPaperWidth,
 406                         devmode->dmPaperLength, devmode->dmDefaultSource,
 407                         xRes, yRes);
 408 
 409 }
 410 
 411 JNIEXPORT jboolean JNICALL
 412 Java_sun_awt_windows_WPrinterJob_showDocProperties(JNIEnv *env,
 413                                                    jobject wJob,
 414                                                    jlong hWndParent,
 415                                                    jobject attrSet,
 416                                                    jint dmFields,
 417                                                    jshort copies,
 418                                                    jshort collate,
 419                                                    jshort color,
 420                                                    jshort duplex,
 421                                                    jshort orient,
 422                                                    jshort paper,
 423                                                    jshort bin,
 424                                                    jshort xres_quality,
 425                                                    jshort yres)
 426 {
 427     TRY;
 428 
 429     HGLOBAL hDevMode = AwtPrintControl::getPrintHDMode(env, wJob);
 430     HGLOBAL hDevNames = AwtPrintControl::getPrintHDName(env, wJob);
 431     DEVMODE *devmode = NULL;
 432     DEVNAMES *devnames = NULL;
 433     LONG rval = IDCANCEL;
 434     jboolean ret = JNI_FALSE;
 435 
 436     if (hDevMode != NULL && hDevNames != NULL) {
 437         devmode = (DEVMODE *)::GlobalLock(hDevMode);
 438         devnames = (DEVNAMES *)::GlobalLock(hDevNames);
 439 
 440         LPTSTR lpdevnames = (LPTSTR)devnames;
 441         // No need to call _tcsdup as we won't unlock until we are done.
 442         LPTSTR printerName = lpdevnames+devnames->wDeviceOffset;
 443         LPTSTR portName = lpdevnames+devnames->wOutputOffset;
 444 
 445         HANDLE hPrinter;
 446         if (::OpenPrinter(printerName, &hPrinter, NULL) == TRUE) {
 447             devmode->dmFields |= dmFields;
 448             devmode->dmCopies = copies;
 449             devmode->dmCollate = collate;
 450             devmode->dmColor = color;
 451             devmode->dmDuplex = duplex;
 452             devmode->dmOrientation = orient;
 453             devmode->dmPrintQuality = xres_quality;
 454             devmode->dmYResolution = yres;
 455             devmode->dmPaperSize = paper;
 456             devmode->dmDefaultSource = bin;
 457 
 458             rval = ::DocumentProperties((HWND)hWndParent,
 459                            hPrinter, printerName, devmode, devmode,
 460                            DM_IN_BUFFER | DM_OUT_BUFFER | DM_IN_PROMPT);
 461             if (rval == IDOK) {
 462                 UpdateJobAttributes(env, wJob, attrSet, devmode);
 463                 ret = JNI_TRUE;
 464             }
 465             VERIFY(::ClosePrinter(hPrinter));
 466         }
 467         ::GlobalUnlock(hDevNames);
 468         ::GlobalUnlock(hDevMode);
 469     }
 470 
 471     return ret;
 472 
 473     CATCH_BAD_ALLOC_RET(0);
 474 }
 475 
 476 /************************************************************************
 477  * WPageDialog native methods
 478  */
 479 JNIEXPORT void JNICALL
 480 Java_sun_awt_windows_WPageDialog_initIDs(JNIEnv *env, jclass cls)
 481 {
 482     TRY;
 483 
 484     AwtPrintDialog::pageID =
 485         env->GetFieldID(cls, "page", "Ljava/awt/print/PageFormat;");
 486 
 487     DASSERT(AwtPrintDialog::pageID != NULL);
 488 
 489     CATCH_BAD_ALLOC;
 490 }
 491 
 492 /************************************************************************
 493  * WPageDialogPeer native methods
 494  */
 495 
 496 /*
 497  * Class:     sun_awt_windows_WPageDialogPeer
 498  * Method:    show
 499  * Signature: ()Z
 500  *
 501  */
 502 
 503 JNIEXPORT jboolean JNICALL
 504 Java_sun_awt_windows_WPageDialogPeer__1show(JNIEnv *env, jobject peer)
 505 {
 506     TRY;
 507 
 508     // as peer object is used later on another thread, create global ref here
 509     jobject peerGlobalRef = env->NewGlobalRef(peer);
 510     DASSERT(peerGlobalRef != NULL);
 511     jobject target = env->GetObjectField(peerGlobalRef, AwtObject::targetID);
 512 
 513     jobject parent = env->GetObjectField(peerGlobalRef, AwtPrintDialog::parentID);
 514 
 515     jobject page = env->GetObjectField(target, AwtPrintDialog::pageID);
 516     DASSERT(page != NULL);
 517 
 518     jobject self = env->GetObjectField(target, AwtPrintDialog::controlID);
 519     DASSERT(self != NULL);
 520 
 521     AwtComponent *awtParent = (parent != NULL) ? (AwtComponent *)JNI_GET_PDATA(parent) : NULL;
 522     HWND hwndOwner = awtParent ? awtParent->GetHWnd() : NULL;
 523 

 524     jboolean doIt = JNI_FALSE; // Assume the user will cancel the dialog.
 525     PAGESETUPDLG setup;
 526     memset(&setup, 0, sizeof(setup));
 527 
 528     setup.lStructSize = sizeof(setup);
 529 





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