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