author | ohair |
Tue, 28 Dec 2010 15:53:50 -0800 | |
changeset 7668 | d4a77089c587 |
parent 6825 | 795e9fe949d3 |
child 8744 | 5f8a7e06e9a7 |
permissions | -rw-r--r-- |
2 | 1 |
/* |
7668 | 2 |
* Copyright (c) 1996, 2010, Oracle and/or its affiliates. All rights reserved. |
2 | 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 |
|
5506 | 7 |
* published by the Free Software Foundation. Oracle designates this |
2 | 8 |
* particular file as subject to the "Classpath" exception as provided |
5506 | 9 |
* by Oracle in the LICENSE file that accompanied this code. |
2 | 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 |
* |
|
5506 | 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. |
|
2 | 24 |
*/ |
25 |
||
1954 | 26 |
#include "awt.h" |
2 | 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" |
|
1954 | 36 |
#include "awt_Dialog.h" |
2 | 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) { |
|
1954 | 425 |
(void)::PageSetupDlg(&setup); |
2 | 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 |
||
1954 | 463 |
BOOL ret = ::PageSetupDlg(&setup); |
2 | 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 |
||
885
cdf589db9213
6708509: print dialog is not displayed when default paper is custom
jgodinez
parents:
2
diff
changeset
|
635 |
if ((pDevMode->dmFields & DM_PAPERSIZE) || |
cdf589db9213
6708509: print dialog is not displayed when default paper is custom
jgodinez
parents:
2
diff
changeset
|
636 |
(pDevMode->dmFields & DM_PAPERWIDTH) || |
cdf589db9213
6708509: print dialog is not displayed when default paper is custom
jgodinez
parents:
2
diff
changeset
|
637 |
(pDevMode->dmFields & DM_PAPERLENGTH)) { |
2 | 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 |
||
1954 | 736 |
if (::PrintDlg(&pd)) { |
2 | 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 |
||
6825 | 1053 |
LPTSTR port = _wcsdup(info2->pPortName); |
2 | 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 |
||
1954 | 1878 |
didSetFont = jFontToWFontW(env, (HDC)printDC, |
2 | 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 |
||
1954 | 1908 |
LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); |
2 | 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 |
|
1954 | 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 |
|
2 | 1921 |
lf.lfFaceName, // Put ASCII string here |
1954 | 1922 |
maxlen, // max len |
1923 |
NULL, // default handling of unmappables |
|
1924 |
NULL); // do not care if def char is used |
|
2 | 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 |
||
1954 | 2009 |
JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); |
2010 |
||
2 | 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 |
||
1954 | 2033 |
LPCWSTR fontNameW = JNU_GetStringPlatformChars(env, fontName, NULL); |
2034 |
||
2 | 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 |
*/ |
|
1954 | 2041 |
size_t nameLen = wcslen(fontNameW); |
2 | 2042 |
if (nameLen < (sizeof(lf.lfFaceName) / sizeof(lf.lfFaceName[0]))) { |
2043 |
||
1954 | 2044 |
wcscpy(lf.lfFaceName, fontNameW); |
2 | 2045 |
|
2046 |
lf.lfCharSet = DEFAULT_CHARSET; |
|
2047 |
lf.lfPitchAndFamily = 0; |
|
2048 |
||
1954 | 2049 |
foundFont = !::EnumFontFamiliesEx((HDC)printDC, &lf, |
2 | 2050 |
(FONTENUMPROCW) fontEnumProcW, |
2051 |
(LPARAM) &matchedLogFont, 0); |
|
2052 |
} |
|
2053 |
||
1954 | 2054 |
JNU_ReleaseStringPlatformChars(env, fontName, fontNameW); |
2055 |
||
2 | 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 |
||
1954 | 2092 |
HFONT font = ::CreateFontIndirect(&matchedLogFont); |
2 | 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)); |
|
1954 | 2115 |
font = ::CreateFontIndirect(&matchedLogFont); |
2 | 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; |
|
1954 | 2222 |
LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); |
2 | 2223 |
size_t strLen = wcslen(wText); |
2224 |
BOOL ok = GetTextExtentPoint32((HDC)printDC, wText, (int)strLen, &size); |
|
1954 | 2225 |
JNU_ReleaseStringPlatformChars(env, text, wText); |
2226 |
return ok ? size.cx : 0; |
|
2 | 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; |
|
1954 | 2277 |
LPCWSTR wText = JNU_GetStringPlatformChars(env, text, NULL); |
2 | 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 |
||
1954 | 2348 |
if (useYAdvances) { |
2 | 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 |
||
1954 | 2360 |
BOOL drawn = ::ExtTextOut((HDC)printDC, |
2 | 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 |
} |
|
1954 | 2374 |
|
2375 |
JNU_ReleaseStringPlatformChars(env, text, wText); |
|
2 | 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 |
||
2456
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2888 |
WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hWnd, NativeDialogWndProcProp)); |
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2889 |
return ComCtl32Util::GetInstance().DefWindowProc(lpfnWndProc, hWnd, message, wParam, lParam); |
2 | 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 |
|
2456
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2923 |
WNDPROC lpfnWndProc = ComCtl32Util::GetInstance().SubclassHWND(hDlg, |
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2924 |
PageDialogWndProc); |
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2925 |
::SetProp(hDlg, NativeDialogWndProcProp, reinterpret_cast<HANDLE>(lpfnWndProc)); |
2 | 2926 |
|
2927 |
break; |
|
2928 |
} |
|
2929 |
case WM_DESTROY: { |
|
2456
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2930 |
WNDPROC lpfnWndProc = (WNDPROC)(::GetProp(hDlg, NativeDialogWndProcProp)); |
2 | 2931 |
ComCtl32Util::GetInstance().UnsubclassHWND(hDlg, |
2932 |
PageDialogWndProc, |
|
2456
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2933 |
lpfnWndProc); |
2 | 2934 |
::RemoveProp(hDlg, ModalDialogPeerProp); |
2456
45ee87a35349
6792023: Print suspends on Windows 2000 Pro since 6u12 b01
dcherepanov
parents:
1954
diff
changeset
|
2935 |
::RemoveProp(hDlg, NativeDialogWndProcProp); |
2 | 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 |
||
1954 | 2963 |
if (::PrintDlg(&pd)) { |
2 | 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 |
const double epsilon = 0.50; |
|
3703 |
const double tolerance = (1.0 * 72.0); // # inches * 72 |
|
3704 |
||
3705 |
*newWid = origWid; |
|
3706 |
*newHgt = origHgt; |
|
3707 |
||
3708 |
/* 1st check if the DC/Devmode has as its current papersize a paper |
|
3709 |
* which matches the paper specified. If yes, then we can skip hunting |
|
3710 |
* for the match and in the process we avoid finding a "name" for |
|
3711 |
* the paper size which isn't the one the user specified in the page |
|
3712 |
* setup dialog. For example "11x17" is also "Ledger". |
|
3713 |
*/ |
|
3714 |
if (printDC != NULL) { |
|
3715 |
// pixels per inch in x and y direction |
|
3716 |
jint xPixelRes = GetDeviceCaps(printDC, LOGPIXELSX); |
|
3717 |
jint yPixelRes = GetDeviceCaps(printDC, LOGPIXELSY); |
|
3718 |
||
3719 |
// width and height of page in pixels |
|
3720 |
jint pagePixelWid = GetDeviceCaps(printDC, PHYSICALWIDTH); |
|
3721 |
jint pagePixelHgt = GetDeviceCaps(printDC, PHYSICALHEIGHT); |
|
3722 |
||
3723 |
// page size in 1/72" |
|
3724 |
jdouble paperWidth = (jdouble)((pagePixelWid * 72)/(jdouble)xPixelRes); |
|
3725 |
jdouble paperHeight = (jdouble)((pagePixelHgt * 72)/(jdouble)yPixelRes); |
|
3726 |
||
3727 |
if ((fabs(origWid - paperWidth) < epsilon) && |
|
3728 |
(fabs(origHgt - paperHeight) < epsilon) && |
|
3729 |
(*paperSize == 0)) { |
|
3730 |
||
3731 |
*newWid = origWid; |
|
3732 |
*newHgt = origHgt; |
|
3733 |
||
3734 |
if (hDevMode != NULL) { |
|
3735 |
DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); |
|
3736 |
if (devmode != NULL && (devmode->dmFields & DM_PAPERSIZE)) { |
|
3737 |
*paperSize = devmode->dmPaperSize; |
|
3738 |
} |
|
3739 |
::GlobalUnlock(hDevMode); |
|
3740 |
} |
|
3741 |
return; |
|
3742 |
} |
|
3743 |
} |
|
3744 |
||
3745 |
/* begin trying to match papers */ |
|
3746 |
||
3747 |
LPTSTR printer = NULL, port = NULL; |
|
3748 |
if (hDevNames != NULL) { |
|
3749 |
DEVNAMES *devnames = (DEVNAMES *)::GlobalLock(hDevNames); |
|
3750 |
if (devnames != NULL) { |
|
3751 |
LPTSTR lpdevnames = (LPTSTR)devnames; |
|
3752 |
printer = _tcsdup(lpdevnames+devnames->wDeviceOffset); |
|
3753 |
port = _tcsdup(lpdevnames+devnames->wOutputOffset); |
|
3754 |
} |
|
3755 |
::GlobalUnlock(hDevNames); |
|
3756 |
} |
|
3757 |
||
3758 |
//REMIND: code duplicated in AwtPrintControl::getNearestMatchingPaper |
|
3759 |
int numPaperSizes = 0; |
|
3760 |
WORD *papers = NULL; |
|
3761 |
POINT *paperSizes = NULL; |
|
3762 |
||
3763 |
SAVE_CONTROLWORD |
|
3764 |
numPaperSizes = (int)DeviceCapabilities(printer, port, DC_PAPERSIZE, |
|
3765 |
NULL, NULL); |
|
3766 |
if (numPaperSizes > 0) { |
|
3767 |
papers = (WORD*)safe_Malloc(sizeof(WORD) * numPaperSizes); |
|
3768 |
paperSizes = (POINT *)safe_Malloc(sizeof(*paperSizes) * numPaperSizes); |
|
3769 |
||
3770 |
DWORD result1 = DeviceCapabilities(printer, port, |
|
3771 |
DC_PAPERS, (LPTSTR) papers, NULL); |
|
3772 |
DWORD result2 = DeviceCapabilities(printer, port, |
|
3773 |
DC_PAPERSIZE, (LPTSTR) paperSizes, |
|
3774 |
NULL); |
|
3775 |
||
3776 |
if (result1 == -1 || result2 == -1 ) { |
|
3777 |
free((char *) papers); |
|
3778 |
papers = NULL; |
|
3779 |
free((char *) paperSizes); |
|
3780 |
paperSizes = NULL; |
|
3781 |
} |
|
3782 |
} |
|
3783 |
||
3784 |
RESTORE_CONTROLWORD |
|
3785 |
double closestWid = 0.0; |
|
3786 |
double closestHgt = 0.0; |
|
3787 |
WORD closestMatch = 0; |
|
3788 |
||
3789 |
if (paperSizes != NULL) { |
|
3790 |
||
3791 |
/* Paper sizes are in 0.1mm units. Convert to 1/72" |
|
3792 |
* For each paper size, compute the difference from the paper size |
|
3793 |
* passed in. Use a least-squares difference, so paper much different |
|
3794 |
* in x or y should score poorly |
|
3795 |
*/ |
|
3796 |
double diffw = origWid; |
|
3797 |
double diffh = origHgt; |
|
3798 |
double least_square = diffw * diffw + diffh * diffh; |
|
3799 |
double tmp_ls; |
|
3800 |
double widpts, hgtpts; |
|
3801 |
||
3802 |
for (int i=0;i<numPaperSizes;i++) { |
|
3803 |
widpts = paperSizes[i].x * LOMETRIC_TO_POINTS; |
|
3804 |
hgtpts = paperSizes[i].y * LOMETRIC_TO_POINTS; |
|
3805 |
||
3806 |
if ((fabs(origWid - widpts) < epsilon) && |
|
3807 |
(fabs(origHgt - hgtpts) < epsilon)) { |
|
3808 |
||
3809 |
if ((*paperSize == 0) || ((*paperSize !=0) && |
|
3810 |
(papers[i]==*paperSize))) { |
|
3811 |
closestWid = origWid; |
|
3812 |
closestHgt = origHgt; |
|
3813 |
closestMatch = papers[i]; |
|
3814 |
break; |
|
3815 |
} |
|
3816 |
} |
|
3817 |
||
3818 |
diffw = fabs(widpts - origWid); |
|
3819 |
diffh = fabs(hgtpts - origHgt); |
|
3820 |
tmp_ls = diffw * diffw + diffh * diffh; |
|
3821 |
if ((diffw < tolerance) && (diffh < tolerance) && |
|
3822 |
(tmp_ls < least_square)) { |
|
3823 |
least_square = tmp_ls; |
|
3824 |
closestWid = widpts; |
|
3825 |
closestHgt = hgtpts; |
|
3826 |
closestMatch = papers[i]; |
|
3827 |
} |
|
3828 |
} |
|
3829 |
} |
|
3830 |
||
3831 |
if (closestWid > 0) { |
|
3832 |
*newWid = closestWid; |
|
3833 |
} |
|
3834 |
if (closestHgt > 0) { |
|
3835 |
*newHgt = closestHgt; |
|
3836 |
} |
|
3837 |
||
3838 |
*paperSize = closestMatch; |
|
3839 |
||
3840 |
/* At this point we have the paper which is the closest match |
|
3841 |
* We now need to select the paper into the DEVMODE, and |
|
3842 |
* get a DC which matches so we can get the margins. |
|
3843 |
*/ |
|
3844 |
||
3845 |
if ((printDC != NULL) && (hDevMode != NULL) && (closestMatch != 0)) { |
|
3846 |
DEVMODE *devmode = (DEVMODE *)::GlobalLock(hDevMode); |
|
3847 |
if ((devmode != NULL) && (closestMatch != devmode->dmPaperSize)) { |
|
3848 |
devmode->dmFields |= DM_PAPERSIZE; |
|
3849 |
devmode->dmPaperSize = closestMatch; |
|
3850 |
::ResetDC(printDC, devmode); |
|
3851 |
RESTORE_CONTROLWORD |
|
3852 |
} |
|
3853 |
::GlobalUnlock(hDevMode); |
|
3854 |
} |
|
3855 |
||
3856 |
if (printer != NULL) { |
|
3857 |
free((char *)printer); |
|
3858 |
} |
|
3859 |
if (port != NULL) { |
|
3860 |
free((char *)port); |
|
3861 |
} |
|
3862 |
if (papers != NULL) { |
|
3863 |
free((char *)papers); |
|
3864 |
} |
|
3865 |
if (paperSizes != NULL) { |
|
3866 |
free((char *)paperSizes); |
|
3867 |
} |
|
3868 |
||
3869 |
} |
|
3870 |
||
3871 |
||
3872 |
static BOOL SetPrinterDevice(LPTSTR pszDeviceName, HGLOBAL* p_hDevMode, |
|
3873 |
HGLOBAL* p_hDevNames) |
|
3874 |
{ |
|
3875 |
// Open printer and obtain PRINTER_INFO_2 structure. |
|
3876 |
HANDLE hPrinter; |
|
3877 |
if (::OpenPrinter(pszDeviceName, &hPrinter, NULL) == FALSE) |
|
3878 |
return FALSE; |
|
3879 |
||
3880 |
DWORD dwBytesReturned, dwBytesNeeded; |
|
3881 |
::GetPrinter(hPrinter, 2, NULL, 0, &dwBytesNeeded); |
|
3882 |
PRINTER_INFO_2* p2 = (PRINTER_INFO_2*)::GlobalAlloc(GPTR, |
|
3883 |
dwBytesNeeded); |
|
3884 |
if (p2 == NULL) { |
|
3885 |
::ClosePrinter(hPrinter); |
|
3886 |
return FALSE; |
|
3887 |
} |
|
3888 |
||
3889 |
if (::GetPrinter(hPrinter, 2, (LPBYTE)p2, dwBytesNeeded, |
|
3890 |
&dwBytesReturned) == 0) { |
|
3891 |
::GlobalFree(p2); |
|
3892 |
::ClosePrinter(hPrinter); |
|
3893 |
return FALSE; |
|
3894 |
} |
|
3895 |
||
3896 |
DEVMODE *pDevMode = NULL; |
|
3897 |
HGLOBAL hDevMode = NULL; |
|
3898 |
/* If GetPrinter didn't fill in the DEVMODE, try to get it by calling |
|
3899 |
DocumentProperties... |
|
3900 |
*/ |
|
3901 |
if (p2->pDevMode == NULL){ |
|
3902 |
SAVE_CONTROLWORD |
|
3903 |
LONG bytesNeeded = ::DocumentProperties(NULL, hPrinter, |
|
3904 |
pszDeviceName, |
|
3905 |
NULL, NULL, 0); |
|
3906 |
RESTORE_CONTROLWORD |
|
3907 |
||
3908 |
if (bytesNeeded <= 0) { |
|
3909 |
::GlobalFree(p2); |
|
3910 |
::ClosePrinter(hPrinter); |
|
3911 |
return FALSE; |
|
3912 |
} |
|
3913 |
||
3914 |
hDevMode = ::GlobalAlloc(GHND, bytesNeeded); |
|
3915 |
if (hDevMode == NULL) { |
|
3916 |
::GlobalFree(p2); |
|
3917 |
::ClosePrinter(hPrinter); |
|
3918 |
return FALSE; |
|
3919 |
} |
|
3920 |
||
3921 |
pDevMode = (DEVMODE*)::GlobalLock(hDevMode); |
|
3922 |
if (pDevMode == NULL) { |
|
3923 |
::GlobalFree(hDevMode); |
|
3924 |
::GlobalFree(p2); |
|
3925 |
::ClosePrinter(hPrinter); |
|
3926 |
return FALSE; |
|
3927 |
} |
|
3928 |
||
3929 |
LONG lFlag = ::DocumentProperties(NULL, hPrinter, |
|
3930 |
pszDeviceName, |
|
3931 |
pDevMode, NULL, |
|
3932 |
DM_OUT_BUFFER); |
|
3933 |
RESTORE_CONTROLWORD |
|
3934 |
if (lFlag != IDOK) { |
|
3935 |
::GlobalUnlock(hDevMode); |
|
3936 |
::GlobalFree(hDevMode); |
|
3937 |
::GlobalFree(p2); |
|
3938 |
::ClosePrinter(hPrinter); |
|
3939 |
return FALSE; |
|
3940 |
} |
|
3941 |
||
3942 |
} else { |
|
3943 |
// Allocate a global handle for DEVMODE and copy DEVMODE data. |
|
3944 |
hDevMode = ::GlobalAlloc(GHND, |
|
3945 |
(sizeof(*p2->pDevMode) + p2->pDevMode->dmDriverExtra)); |
|
3946 |
if (hDevMode == NULL) { |
|
3947 |
::GlobalFree(p2); |
|
3948 |
::ClosePrinter(hPrinter); |
|
3949 |
return FALSE; |
|
3950 |
} |
|
3951 |
||
3952 |
pDevMode = (DEVMODE*)::GlobalLock(hDevMode); |
|
3953 |
if (pDevMode == NULL) { |
|
3954 |
::GlobalFree(hDevMode); |
|
3955 |
::GlobalFree(p2); |
|
3956 |
::ClosePrinter(hPrinter); |
|
3957 |
return FALSE; |
|
3958 |
} |
|
3959 |
||
3960 |
memcpy(pDevMode, p2->pDevMode, |
|
3961 |
sizeof(*p2->pDevMode) + p2->pDevMode->dmDriverExtra); |
|
3962 |
} |
|
3963 |
||
3964 |
::GlobalUnlock(hDevMode); |
|
3965 |
::ClosePrinter(hPrinter); |
|
3966 |
||
3967 |
// Compute size of DEVNAMES structure you'll need. |
|
3968 |
// All sizes are WORD as in DEVNAMES structure |
|
3969 |
// All offsets are in characters, not in bytes |
|
3970 |
WORD drvNameLen = static_cast<WORD>(_tcslen(p2->pDriverName)); // driver name |
|
3971 |
WORD ptrNameLen = static_cast<WORD>(_tcslen(p2->pPrinterName)); // printer name |
|
3972 |
WORD porNameLen = static_cast<WORD>(_tcslen(p2->pPortName)); // port name |
|
3973 |
WORD devNameSize = static_cast<WORD>(sizeof(DEVNAMES)) + |
|
3974 |
(ptrNameLen + porNameLen + drvNameLen + 3)*sizeof(TCHAR); |
|
3975 |
||
3976 |
// Allocate a global handle big enough to hold DEVNAMES. |
|
3977 |
HGLOBAL hDevNames = ::GlobalAlloc(GHND, devNameSize); |
|
3978 |
DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); |
|
3979 |
||
3980 |
// Copy the DEVNAMES information from PRINTER_INFO_2 structure. |
|
3981 |
pDevNames->wDriverOffset = sizeof(DEVNAMES)/sizeof(TCHAR); |
|
3982 |
memcpy((LPTSTR)pDevNames + pDevNames->wDriverOffset, |
|
3983 |
p2->pDriverName, drvNameLen*sizeof(TCHAR)); |
|
3984 |
||
3985 |
pDevNames->wDeviceOffset = static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR)) + |
|
3986 |
drvNameLen + 1; |
|
3987 |
memcpy((LPTSTR)pDevNames + pDevNames->wDeviceOffset, |
|
3988 |
p2->pPrinterName, ptrNameLen*sizeof(TCHAR)); |
|
3989 |
||
3990 |
pDevNames->wOutputOffset = static_cast<WORD>(sizeof(DEVNAMES)/sizeof(TCHAR)) + |
|
3991 |
drvNameLen + ptrNameLen + 2; |
|
3992 |
memcpy((LPTSTR)pDevNames + pDevNames->wOutputOffset, |
|
3993 |
p2->pPortName, porNameLen*sizeof(TCHAR)); |
|
3994 |
||
3995 |
pDevNames->wDefault = 0; |
|
3996 |
||
3997 |
::GlobalUnlock(hDevNames); |
|
3998 |
::GlobalFree(p2); // free PRINTER_INFO_2 |
|
3999 |
||
4000 |
*p_hDevMode = hDevMode; |
|
4001 |
*p_hDevNames = hDevNames; |
|
4002 |
||
4003 |
return TRUE; |
|
4004 |
} |
|
4005 |
||
4006 |
||
4007 |
JNIEXPORT void JNICALL |
|
4008 |
Java_sun_awt_windows_WPrinterJob_setNativePrintService(JNIEnv *env, |
|
4009 |
jobject name, |
|
4010 |
jstring printer) |
|
4011 |
{ |
|
4012 |
TRY; |
|
4013 |
LPTSTR printerName = (LPTSTR)JNU_GetStringPlatformChars(env, |
|
4014 |
printer, NULL); |
|
4015 |
HDC hDC = AwtPrintControl::getPrintDC(env, name); |
|
4016 |
if (hDC != NULL) { |
|
4017 |
DeletePrintDC(hDC); |
|
4018 |
hDC = NULL; |
|
4019 |
} |
|
4020 |
||
4021 |
SAVE_CONTROLWORD |
|
4022 |
hDC = ::CreateDC(TEXT("WINSPOOL"), printerName, NULL, NULL); |
|
4023 |
RESTORE_CONTROLWORD |
|
4024 |
if (hDC == NULL) { |
|
4025 |
jclass printerException = env->FindClass(PRINTEREXCEPTION_STR); |
|
4026 |
env->ThrowNew(printerException, "Invalid name of PrintService."); |
|
4027 |
JNU_ReleaseStringPlatformChars(env, printer, printerName); |
|
4028 |
return; |
|
4029 |
} |
|
4030 |
AwtPrintControl::setPrintDC(env, name, hDC); |
|
4031 |
||
4032 |
HANDLE hDevMode = AwtPrintControl::getPrintHDMode(env, name); |
|
4033 |
if (hDevMode != NULL) { |
|
4034 |
::GlobalFree(hDevMode); |
|
4035 |
hDevMode = NULL; |
|
4036 |
} |
|
4037 |
||
4038 |
HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, name);; |
|
4039 |
if (hDevNames != NULL) { |
|
4040 |
::GlobalFree(hDevNames); |
|
4041 |
hDevNames = NULL; |
|
4042 |
} |
|
4043 |
||
4044 |
SetPrinterDevice(printerName, &hDevMode, &hDevNames); |
|
4045 |
||
4046 |
AwtPrintControl::setPrintHDMode(env, name, hDevMode); |
|
4047 |
AwtPrintControl::setPrintHDName(env, name, hDevNames); |
|
4048 |
||
4049 |
// Driver capability for copies & collation are not set |
|
4050 |
// when printDialog and getDefaultPrinterDC are not called. |
|
4051 |
// set DRIVER_COPIES_STR and DRIVER_COLLATE_STR |
|
4052 |
DEVMODE *devmode = NULL; |
|
4053 |
if (hDevMode != NULL) { |
|
4054 |
devmode = (DEVMODE *)::GlobalLock(hDevMode); |
|
4055 |
DASSERT(!IsBadReadPtr(devmode, sizeof(DEVMODE))); |
|
4056 |
} |
|
4057 |
||
4058 |
if (devmode != NULL) { |
|
4059 |
if (devmode->dmFields & DM_COPIES) { |
|
4060 |
setBooleanField(env, name, DRIVER_COPIES_STR, JNI_TRUE); |
|
4061 |
} |
|
4062 |
||
4063 |
if (devmode->dmFields & DM_COLLATE) { |
|
4064 |
setBooleanField(env, name, DRIVER_COLLATE_STR, JNI_TRUE); |
|
4065 |
} |
|
4066 |
||
4067 |
::GlobalUnlock(hDevMode); |
|
4068 |
} |
|
4069 |
||
4070 |
setCapabilities(env, name, hDC); |
|
4071 |
||
4072 |
JNU_ReleaseStringPlatformChars(env, printer, printerName); |
|
4073 |
CATCH_BAD_ALLOC; |
|
4074 |
||
4075 |
} |
|
4076 |
||
4077 |
||
4078 |
JNIEXPORT jstring JNICALL |
|
4079 |
Java_sun_awt_windows_WPrinterJob_getNativePrintService(JNIEnv *env, |
|
4080 |
jobject name) |
|
4081 |
{ |
|
4082 |
TRY; |
|
4083 |
jstring printer; |
|
4084 |
HANDLE hDevNames = AwtPrintControl::getPrintHDName(env, name); |
|
4085 |
if (hDevNames == NULL) { |
|
4086 |
return NULL; |
|
4087 |
} |
|
4088 |
DEVNAMES* pDevNames = (DEVNAMES*)::GlobalLock(hDevNames); |
|
4089 |
||
4090 |
printer = JNU_NewStringPlatform(env, |
|
4091 |
(LPTSTR)pDevNames+pDevNames->wDeviceOffset); |
|
4092 |
::GlobalUnlock(hDevNames); |
|
4093 |
return printer; |
|
4094 |
||
4095 |
CATCH_BAD_ALLOC_RET(0); |
|
4096 |
} |
|
4097 |
||
4098 |
static BOOL getPrintableArea(HDC pdc, HANDLE hDevMode, RectDouble *margin) |
|
4099 |
{ |
|
4100 |
if (pdc == NULL) { |
|
4101 |
return FALSE; |
|
4102 |
} |
|
4103 |
||
4104 |
DEVMODE *pDevMode = (DEVMODE*)::GlobalLock(hDevMode); |
|
4105 |
if (pDevMode == NULL) { |
|
4106 |
return FALSE; |
|
4107 |
} |
|
4108 |
||
4109 |
SAVE_CONTROLWORD |
|
4110 |
::ResetDC(pdc, pDevMode); |
|
4111 |
RESTORE_CONTROLWORD |
|
4112 |
||
4113 |
int left = GetDeviceCaps(pdc, PHYSICALOFFSETX); |
|
4114 |
int top = GetDeviceCaps(pdc, PHYSICALOFFSETY); |
|
4115 |
int width = GetDeviceCaps(pdc, HORZRES); |
|
4116 |
int height = GetDeviceCaps(pdc, VERTRES); |
|
4117 |
int resx = GetDeviceCaps(pdc, LOGPIXELSX); |
|
4118 |
int resy = GetDeviceCaps(pdc, LOGPIXELSY); |
|
4119 |
||
4120 |
||
4121 |
margin->x = (jdouble)left/resx; |
|
4122 |
margin->y =(jdouble)top/resy; |
|
4123 |
margin->width = (jdouble)width/resx; |
|
4124 |
margin->height = (jdouble)height/resy; |
|
4125 |
||
4126 |
::GlobalUnlock(hDevMode); |
|
4127 |
||
4128 |
return TRUE; |
|
4129 |
} |
|
4130 |
||
4131 |
JNIEXPORT void JNICALL |
|
4132 |
Java_sun_awt_windows_WPrinterJob_initIDs(JNIEnv *env, jclass cls) |
|
4133 |
{ |
|
4134 |
TRY; |
|
4135 |
||
4136 |
AwtPrintDialog::controlID = |
|
4137 |
env->GetFieldID(cls, "pjob", "Ljava/awt/print/PrinterJob;"); |
|
4138 |
jclass printDialogPeerClass = env->FindClass("Lsun/awt/windows/WPrintDialogPeer;"); |
|
4139 |
AwtPrintDialog::setHWndMID = |
|
4140 |
env->GetMethodID(printDialogPeerClass, "setHWnd", "(J)V"); |
|
4141 |
||
4142 |
DASSERT(AwtPrintDialog::controlID != NULL); |
|
4143 |
DASSERT(AwtPrintDialog::setHWndMID != NULL); |
|
4144 |
||
4145 |
AwtPrintControl::initIDs(env, cls); |
|
4146 |
CATCH_BAD_ALLOC; |
|
4147 |
} |
|
4148 |
||
4149 |
} /* extern "C" */ |