1 /*
2  * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 
27 
28 /**
29  * This class holds the information for a particular graphics device.
30  * Since a display change can cause the creation of new devices
31  * at any time, there is no referencing of the devices array allowed.
32  * Instead, anyone wishing to reference a device in the array (e.g.,
33  * the current default device or a device for a given hWnd) must
34  * call one of the static methods of this class with the index of
35  * the device in question.  Those methods will then lock the devices
36  * array and forward the request to the current device at that
37  * array index.
38  */
39 
40 #include <awt.h>
41 #include <sun_awt_Win32GraphicsDevice.h>
42 #include "awt_Canvas.h"
43 #include "awt_Win32GraphicsDevice.h"
44 #include "awt_Window.h"
45 #include "java_awt_Transparency.h"
46 #include "java_awt_color_ColorSpace.h"
47 #include "sun_awt_Win32GraphicsDevice.h"
48 #include "java_awt_image_DataBuffer.h"
49 #include "dither.h"
50 #include "img_util_md.h"
51 #include "Devices.h"
52 #include <d2d1.h>
53 #pragma comment(lib, "d2d1")
54 #include "systemScale.h"
55 
56 uns_ordered_dither_array img_oda_alpha;
57 
58 jclass      AwtWin32GraphicsDevice::indexCMClass;
59 jclass      AwtWin32GraphicsDevice::wToolkitClass;
60 jfieldID    AwtWin32GraphicsDevice::dynamicColorModelID;
61 jfieldID    AwtWin32GraphicsDevice::indexCMrgbID;
62 jfieldID    AwtWin32GraphicsDevice::indexCMcacheID;
63 jmethodID   AwtWin32GraphicsDevice::paletteChangedMID;
64 BOOL        AwtWin32GraphicsDevice::primaryPalettized;
65 int         AwtWin32GraphicsDevice::primaryIndex = 0;
66 
67 
68 /**
69  * Construct this device.  Store the screen (index into the devices
70  * array of this object), the array (used in static references via
71  * particular device indices), the monitor/pMonitorInfo (which other
72  * classes will inquire of this device), the bits per pixel of this
73  * device, and information on whether the primary device is palettized.
74  */
AwtWin32GraphicsDevice(int screen,HMONITOR mhnd,Devices * arr)75 AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen,
76                                                HMONITOR mhnd, Devices *arr)
77 {
78     this->screen  = screen;
79     this->devicesArray = arr;
80     this->scaleX = 1;
81     this->scaleY = 1;
82     javaDevice = NULL;
83     colorData = new ImgColorData;
84     colorData->grayscale = GS_NOTGRAY;
85     palette = NULL;
86     cData = NULL;
87     gpBitmapInfo = NULL;
88     monitor = mhnd;
89     pMonitorInfo = new MONITORINFOEX;
90     pMonitorInfo->cbSize = sizeof(MONITORINFOEX);
91     ::GetMonitorInfo(monitor, pMonitorInfo);
92 
93     // Set primary device info: other devices will need to know
94     // whether the primary is palettized during the initialization
95     // process
96     HDC hDC = this->GetDC();
97     colorData->bitsperpixel = ::GetDeviceCaps(hDC, BITSPIXEL);
98     this->ReleaseDC(hDC);
99     if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
100         primaryIndex = screen;
101         if (colorData->bitsperpixel > 8) {
102             primaryPalettized = FALSE;
103         } else {
104             primaryPalettized = TRUE;
105         }
106     }
107 }
108 
~AwtWin32GraphicsDevice()109 AwtWin32GraphicsDevice::~AwtWin32GraphicsDevice()
110 {
111     delete colorData;
112     if (gpBitmapInfo) {
113         free(gpBitmapInfo);
114     }
115     if (palette) {
116         delete palette;
117     }
118     if (pMonitorInfo) {
119         delete pMonitorInfo;
120     }
121     if (javaDevice) {
122         JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
123         env->DeleteWeakGlobalRef(javaDevice);
124     }
125     if (cData != NULL) {
126         freeICMColorData(cData);
127     }
128 }
129 
MakeDCFromMonitor(HMONITOR hmMonitor)130 HDC AwtWin32GraphicsDevice::MakeDCFromMonitor(HMONITOR hmMonitor) {
131     HDC retCode = NULL;
132     if (NULL != hmMonitor) {
133         MONITORINFOEX mieInfo;
134 
135         memset((void*)(&mieInfo), 0, sizeof(MONITORINFOEX));
136         mieInfo.cbSize = sizeof(MONITORINFOEX);
137 
138         if (TRUE == ::GetMonitorInfo(hmMonitor, (LPMONITORINFOEX)(&mieInfo))) {
139             HDC hDC = CreateDC(mieInfo.szDevice, NULL, NULL, NULL);
140             if (NULL != hDC) {
141                 retCode = hDC;
142             }
143         }
144     }
145     return retCode;
146 }
147 
GetDC()148 HDC AwtWin32GraphicsDevice::GetDC()
149 {
150     return MakeDCFromMonitor(monitor);
151 }
152 
ReleaseDC(HDC hDC)153 void AwtWin32GraphicsDevice::ReleaseDC(HDC hDC)
154 {
155     if (hDC != NULL) {
156         ::DeleteDC(hDC);
157     }
158 }
159 
160 /**
161  * Init this device.  This creates the bitmap structure
162  * used to hold the device color data and initializes any
163  * appropriate palette structures.
164  */
Initialize()165 void AwtWin32GraphicsDevice::Initialize()
166 {
167     unsigned int ri, gi, bi;
168     if (colorData->bitsperpixel < 8) {
169         // REMIND: how to handle?
170     }
171 
172     // Create a BitmapInfo object for color data
173     if (!gpBitmapInfo) {
174         try {
175             gpBitmapInfo = (BITMAPINFO *)
176                 safe_Malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
177         } catch (std::bad_alloc&) {
178             throw;
179         }
180         gpBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
181     }
182     gpBitmapInfo->bmiHeader.biBitCount = 0;
183     HDC hBMDC = this->GetDC();
184     HBITMAP hBM = ::CreateCompatibleBitmap(hBMDC, 1, 1);
185     VERIFY(::GetDIBits(hBMDC, hBM, 0, 1, NULL, gpBitmapInfo, DIB_RGB_COLORS));
186 
187     if (colorData->bitsperpixel > 8) {
188         if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
189             primaryPalettized = FALSE;
190         }
191         if (colorData->bitsperpixel != 24) { // 15, 16, or 32 bpp
192             int foo;
193             gpBitmapInfo->bmiHeader.biCompression = BI_BITFIELDS;
194             if (::GetDIBits(hBMDC, hBM, 0, 1, &foo, gpBitmapInfo,
195                             DIB_RGB_COLORS) == 0)
196             {
197                 // Bug 4684966: If GetDIBits returns an error, we could
198                 // get stuck in an infinite loop setting the colorData
199                 // fields.  Hardcode bitColors to reasonable values instead.
200                 // These values are picked according to standard masks
201                 // for these bit depths on win9x, according to MSDN docs.
202                 switch (colorData->bitsperpixel) {
203                 case 15:
204                     ((int *)gpBitmapInfo->bmiColors)[0] = 0x7c00;
205                     ((int *)gpBitmapInfo->bmiColors)[1] = 0x03e0;
206                     ((int *)gpBitmapInfo->bmiColors)[2] = 0x001f;
207                     break;
208                 case 16:
209                     ((int *)gpBitmapInfo->bmiColors)[0] = 0xf800;
210                     ((int *)gpBitmapInfo->bmiColors)[1] = 0x07e0;
211                     ((int *)gpBitmapInfo->bmiColors)[2] = 0x001f;
212                     break;
213                 case 32:
214                 default:
215                     ((int *)gpBitmapInfo->bmiColors)[0] = 0xff0000;
216                     ((int *)gpBitmapInfo->bmiColors)[1] = 0x00ff00;
217                     ((int *)gpBitmapInfo->bmiColors)[2] = 0x0000ff;
218                     break;
219                 }
220             }
221             ri = ((unsigned int *)gpBitmapInfo->bmiColors)[0];
222             colorData->rOff = 0;
223             while ((ri & 1) == 0) {
224                 colorData->rOff++;
225                 ri >>= 1;
226             }
227             colorData->rScale = 0;
228             while (ri < 0x80) {
229                 colorData->rScale++;
230                 ri <<= 1;
231             }
232             gi = ((unsigned int *)gpBitmapInfo->bmiColors)[1];
233             colorData->gOff = 0;
234             while ((gi & 1) == 0) {
235                 colorData->gOff++;
236                 gi >>= 1;
237             }
238             colorData->gScale = 0;
239             while (gi < 0x80) {
240                 colorData->gScale++;
241                 gi <<= 1;
242             }
243             bi = ((unsigned int *)gpBitmapInfo->bmiColors)[2];
244             colorData->bOff = 0;
245             while ((bi & 1) == 0) {
246                 colorData->bOff++;
247                 bi >>= 1;
248             }
249             colorData->bScale = 0;
250             while (bi < 0x80) {
251                 colorData->bScale++;
252                 bi <<= 1;
253             }
254             if (   (0 == colorData->bOff)
255                 && (5 == colorData->gOff)
256                 && (10 == colorData->rOff)
257                 && (3 == colorData->bScale)
258                 && (3 == colorData->gScale)
259                 && (3 == colorData->rScale)) {
260                 colorData->bitsperpixel = 15;
261                 gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
262             }
263         } else {    // 24 bpp
264             gpBitmapInfo->bmiHeader.biBitCount = 24;
265             gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
266 
267             // Fill these values in as a convenience for the screen
268             // ColorModel construction code below (see getColorModel())
269             ((int *)gpBitmapInfo->bmiColors)[0] = 0x0000ff;
270             ((int *)gpBitmapInfo->bmiColors)[1] = 0x00ff00;
271             ((int *)gpBitmapInfo->bmiColors)[2] = 0xff0000;
272         }
273     } else {
274         if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
275             primaryPalettized = TRUE;
276         }
277         gpBitmapInfo->bmiHeader.biBitCount = 8;
278         gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
279         gpBitmapInfo->bmiHeader.biClrUsed = 256;
280         gpBitmapInfo->bmiHeader.biClrImportant = 256;
281 
282         // The initialization of cData is done prior to
283         // calling palette->Update() since we need it
284         // for calculating inverseGrayLut
285         if (cData == NULL) {
286             cData = (ColorData*)safe_Calloc(1, sizeof(ColorData));
287             memset(cData, 0, sizeof(ColorData));
288             initDitherTables(cData);
289         }
290 
291         if (!palette) {
292             palette = new AwtPalette(this);
293         } else {
294             palette->Update();
295         }
296         palette->UpdateLogical();
297     }
298     VERIFY(::DeleteObject(hBM));
299     VERIFY(::DeleteDC(hBMDC));
300 }
301 
302 /**
303  * Creates a new colorModel given the current device configuration.
304  * The dynamic flag determines whether we use the system palette
305  * (dynamic == TRUE) or our custom palette in creating a new
306  * IndexedColorModel.
307  */
GetColorModel(JNIEnv * env,jboolean dynamic)308 jobject AwtWin32GraphicsDevice::GetColorModel(JNIEnv *env, jboolean dynamic)
309 {
310     jobject awt_colormodel;
311     int i;
312     if (colorData->bitsperpixel == 24) {
313         awt_colormodel =
314             JNU_NewObjectByName(env, "sun/awt/Win32ColorModel24", "()V");
315     } else if (colorData->bitsperpixel > 8) {
316         int *masks = (int *)gpBitmapInfo->bmiColors;
317         int numbits = 0;
318         unsigned int bits = (masks[0] | masks[1] | masks[2]);
319         while (bits) {
320             numbits++;
321             bits >>= 1;
322         }
323         awt_colormodel = JNU_NewObjectByName(env,
324                                              "java/awt/image/DirectColorModel",
325                                              "(IIII)V", numbits,
326                                              masks[0], masks[1], masks[2]);
327     } else if (colorData->grayscale == GS_STATICGRAY) {
328         jclass clazz;
329         jclass clazz1;
330         jmethodID mid;
331         jobject cspace = NULL;
332         jint bits[1];
333         jintArray bitsArray;
334 
335         clazz1 = env->FindClass("java/awt/color/ColorSpace");
336         CHECK_NULL_RETURN(clazz1, NULL);
337         mid = env->GetStaticMethodID(clazz1, "getInstance",
338               "(I)Ljava/awt/color/ColorSpace;");
339         CHECK_NULL_RETURN(mid, NULL);
340         cspace = env->CallStaticObjectMethod(clazz1, mid,
341             java_awt_color_ColorSpace_CS_GRAY);
342         CHECK_NULL_RETURN(cspace, NULL);
343 
344         bits[0] = 8;
345         bitsArray = env->NewIntArray(1);
346         if (bitsArray == 0) {
347             return NULL;
348         } else {
349             env->SetIntArrayRegion(bitsArray, 0, 1, bits);
350         }
351 
352         clazz = env->FindClass("java/awt/image/ComponentColorModel");
353         CHECK_NULL_RETURN(clazz, NULL);
354         mid = env->GetMethodID(clazz,"<init>",
355             "(Ljava/awt/color/ColorSpace;[IZZII)V");
356         CHECK_NULL_RETURN(mid, NULL);
357 
358         awt_colormodel = env->NewObject(clazz, mid,
359                                         cspace,
360                                         bitsArray,
361                                         JNI_FALSE,
362                                         JNI_FALSE,
363                                         java_awt_Transparency_OPAQUE,
364                                         java_awt_image_DataBuffer_TYPE_BYTE);
365     } else {
366         jintArray hRGB = env->NewIntArray(256);
367         unsigned int *rgb = NULL, *rgbP = NULL;
368         jboolean allvalid = JNI_TRUE;
369         jbyte vbits[256/8];
370         jobject validBits = NULL;
371 
372         CHECK_NULL_RETURN(hRGB, NULL);
373         /* Create the LUT from the color map */
374         try {
375             rgb = (unsigned int *) env->GetPrimitiveArrayCritical(hRGB, 0);
376             CHECK_NULL_RETURN(rgb, NULL);
377             rgbP = rgb;
378             if (!palette) {
379                 palette = new AwtPalette(this);
380                 palette->UpdateLogical();
381             }
382             if (colorData->grayscale == GS_INDEXGRAY) {
383                 /* For IndexColorModel, pretend first 10 colors and last
384                    10 colors are transparent black.  This makes
385                    ICM.allgrayopaque true.
386                 */
387                 unsigned int *logicalEntries = palette->GetLogicalEntries();
388 
389                 for (i=0; i < 10; i++) {
390                     rgbP[i] = 0x00000000;
391                     rgbP[i+246] = 0x00000000;
392                 }
393                 memcpy(&rgbP[10], &logicalEntries[10], 236 * sizeof(RGBQUAD));
394                 // We need to specify which entries in the colormap are
395                 // valid so that the transparent black entries we have
396                 // created do not affect the Transparency setting of the
397                 // IndexColorModel.  The vbits array is used to construct
398                 // a BigInteger such that the most significant bit of vbits[0]
399                 // indicates the validity of the last color (#256) and the
400                 // least significant bit of vbits[256/8] indicates the
401                 // validity of the first color (#0).  We need to fill vbits
402                 // with all 1's and then turn off the first and last 10 bits.
403                 memset(vbits, 0xff, sizeof(vbits));
404                 vbits[0] = 0;
405                 vbits[1] = (jbyte) (0xff >> 2);
406                 vbits[sizeof(vbits)-2] = (jbyte) (0xff << 2);
407                 vbits[sizeof(vbits)-1] = 0;
408                 allvalid = JNI_FALSE;
409             } else {
410                 if (AwtPalette::UseCustomPalette() && !dynamic) {
411                     // If we plan to use our custom palette (i.e., we are
412                     // not running inside another app and we are not creating
413                     // a dynamic colorModel object), then setup ICM with
414                     // custom palette entries
415                     unsigned int *logicalEntries = palette->GetLogicalEntries();
416                     memcpy(rgbP, logicalEntries, 256 * sizeof(int));
417                 } else {
418                     // Else, use current system palette entries.
419                     // REMIND: This may not give the result we want if
420                     // we are running inside another app and that
421                     // parent app is running in the background when we
422                     // reach here.  We could at least cache an "ideal" set of
423                     // system palette entries from the first time we are
424                     // running in the foreground and then future ICM's will
425                     // use that set instead.
426                     unsigned int *systemEntries = palette->GetSystemEntries();
427                     memcpy(rgbP, systemEntries, 256 * sizeof(int));
428                 }
429             }
430         } catch (...) {
431             env->ReleasePrimitiveArrayCritical(hRGB, rgb, 0);
432             throw;
433         }
434 
435         env->ReleasePrimitiveArrayCritical(hRGB, rgb, 0);
436 
437         // Construct a new color model
438         if (!allvalid) {
439             jbyteArray bArray = env->NewByteArray(sizeof(vbits));
440             CHECK_NULL_RETURN(bArray, NULL);
441             env->SetByteArrayRegion(bArray, 0, sizeof(vbits), vbits);
442             validBits = JNU_NewObjectByName(env,
443                                             "java/math/BigInteger",
444                                             "([B)V", bArray);
445             JNU_CHECK_EXCEPTION_RETURN(env, NULL);
446         }
447         awt_colormodel =
448             JNU_NewObjectByName(env,
449                                 "java/awt/image/IndexColorModel",
450                                 "(II[IIILjava/math/BigInteger;)V",
451                                 8, 256,
452                                 hRGB, 0,
453                                 java_awt_image_DataBuffer_TYPE_BYTE,
454                                 validBits);
455     }
456     return awt_colormodel;
457 }
458 
459 /**
460  * Called from AwtPalette code when it is determined what grayscale
461  * value (if any) the current logical palette has
462  */
SetGrayness(int grayValue)463 void AwtWin32GraphicsDevice::SetGrayness(int grayValue)
464 {
465     colorData->grayscale = grayValue;
466 }
467 
468 
469 /**
470  * Update our dynamic IndexedColorModel.  This happens after
471  * a change to the system palette.  Any surfaces stored in vram
472  * (Win32OffScreenSurfaceData and GDIWindowSurfaceData objects)
473  * refer to this colorModel and use its lookup table and inverse
474  * lookup to calculate correct index values for rgb colors.  So
475  * the colorModel must always reflect the current state of the
476  * system palette.
477  */
UpdateDynamicColorModel()478 void AwtWin32GraphicsDevice::UpdateDynamicColorModel()
479 {
480     if (!javaDevice) {
481         // javaDevice may not be set yet.  If not, return.  In
482         // this situation, we probably don't need an update anyway
483         // since the colorModel will be created with the correct
484         // info when the java side is initialized.
485         return;
486     }
487     JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
488     jobject colorModel = env->GetObjectField(javaDevice,
489         dynamicColorModelID);
490     if (!colorModel) {
491         return;
492     }
493     if (env->IsInstanceOf(colorModel, indexCMClass)) {
494         // If colorModel not of type ICM then we're not in 8-bit mode and
495         // don't need to update it
496         jboolean isCopy;
497         unsigned int *newEntries = palette->GetSystemEntries();
498         jintArray rgbArray = (jintArray)env->GetObjectField(colorModel,
499             AwtWin32GraphicsDevice::indexCMrgbID);
500         jintArray cacheArray = (jintArray)env->GetObjectField(colorModel,
501             AwtWin32GraphicsDevice::indexCMcacheID);
502         if (!rgbArray || !cacheArray) {
503             JNU_ThrowInternalError(env, "rgb or lookupcache array of IndexColorModel null");
504             return;
505         }
506         int rgbLength = env->GetArrayLength(rgbArray);
507         int cacheLength = env->GetArrayLength(cacheArray);
508         jint *cmEntries = (jint *)env->GetPrimitiveArrayCritical(rgbArray, &isCopy);
509         if (!cmEntries) {
510             env->ExceptionClear();
511             JNU_ThrowInternalError(env, "Problem retrieving rgb critical array");
512             return;
513         }
514         jint *cache = (jint *)env->GetPrimitiveArrayCritical(cacheArray, &isCopy);
515         if (!cache) {
516             env->ExceptionClear();
517             env->ReleasePrimitiveArrayCritical(rgbArray, cmEntries, JNI_ABORT);
518             JNU_ThrowInternalError(env, "Problem retrieving cache critical array");
519             return;
520         }
521         // Set the new rgb values
522     int i;
523     for (i = 0; i < rgbLength; ++i) {
524             cmEntries[i] = newEntries[i];
525         }
526         // clear out the old cache
527         for (i = 0; i < cacheLength; ++i) {
528             cache[i] = 0;
529         }
530         env->ReleasePrimitiveArrayCritical(cacheArray, cache, 0);
531         env->ReleasePrimitiveArrayCritical(rgbArray, cmEntries, 0);
532 
533         // Call WToolkit::paletteChanged() method; this will invalidate
534         // the offscreen surfaces dependent on this dynamic colorModel
535         // to ensure that they get redrawn with the correct color indices
536         env->CallStaticVoidMethod(AwtWin32GraphicsDevice::wToolkitClass,
537             paletteChangedMID);
538     }
539 }
540 
GetSystemPaletteEntries()541 unsigned int *AwtWin32GraphicsDevice::GetSystemPaletteEntries()
542 {
543     // REMIND: What to do if palette NULL?  Need to throw
544     // some kind of exception?
545     return palette->GetSystemEntries();
546 }
547 
GetSystemInverseLUT()548 unsigned char *AwtWin32GraphicsDevice::GetSystemInverseLUT()
549 {
550     // REMIND: What to do if palette NULL?  Need to throw
551     // some kind of exception?
552     return palette->GetSystemInverseLUT();
553 }
554 
555 
UpdateSystemPalette()556 BOOL AwtWin32GraphicsDevice::UpdateSystemPalette()
557 {
558     if (colorData->bitsperpixel > 8) {
559         return FALSE;
560     } else {
561         return palette->Update();
562     }
563 }
564 
SelectPalette(HDC hDC)565 HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC)
566 {
567     if (palette) {
568         return palette->Select(hDC);
569     } else {
570         return NULL;
571     }
572 }
573 
RealizePalette(HDC hDC)574 void AwtWin32GraphicsDevice::RealizePalette(HDC hDC)
575 {
576     if (palette) {
577         palette->Realize(hDC);
578     }
579 }
580 
581 /**
582  * Deterine which device the HWND exists on and return the
583  * appropriate index into the devices array.
584  */
DeviceIndexForWindow(HWND hWnd)585 int AwtWin32GraphicsDevice::DeviceIndexForWindow(HWND hWnd)
586 {
587     HMONITOR mon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
588     int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(mon);
589     return screen;
590 }
591 
592 /**
593  * Get the HPALETTE associated with this device
594  */
GetPalette()595 HPALETTE AwtWin32GraphicsDevice::GetPalette()
596 {
597     if (palette) {
598         return palette->GetPalette();
599     } else {
600         return NULL;
601     }
602 }
603 
604 /**
605  * Object referring to this device is releasing that reference.
606  * This allows the array holding all devices to be released (once
607  * all references to the array have gone away).
608  */
Release()609 void AwtWin32GraphicsDevice::Release()
610 {
611     devicesArray->Release();
612 }
613 
614 /**
615  * Links this native object with its java Win32GraphicsDevice.
616  * Need this link because the colorModel of the java device
617  * may be updated from native code.
618  */
SetJavaDevice(JNIEnv * env,jobject objPtr)619 void AwtWin32GraphicsDevice::SetJavaDevice(JNIEnv *env, jobject objPtr)
620 {
621     javaDevice = env->NewWeakGlobalRef(objPtr);
622 }
623 
624 /**
625  * Sets horizontal and vertical scale factors
626  */
SetScale(float sx,float sy)627 void AwtWin32GraphicsDevice::SetScale(float sx, float sy)
628 {
629     scaleX = sx;
630     scaleY = sy;
631 }
632 
ScaleUpX(int x)633 int AwtWin32GraphicsDevice::ScaleUpX(int x)
634 {
635     return ClipRound(x * scaleX);
636 }
637 
ScaleUpY(int y)638 int AwtWin32GraphicsDevice::ScaleUpY(int y)
639 {
640     return ClipRound(y * scaleY);
641 }
642 
ScaleDownX(int x)643 int AwtWin32GraphicsDevice::ScaleDownX(int x)
644 {
645     return ClipRound(x / scaleX);
646 }
647 
ScaleDownY(int y)648 int AwtWin32GraphicsDevice::ScaleDownY(int y)
649 {
650     return ClipRound(y / scaleY);
651 }
652 
ClipRound(double value)653 int AwtWin32GraphicsDevice::ClipRound(double value)
654 {
655     value -= 0.5;
656     if (value < INT_MIN)
657     {
658         return INT_MIN;
659     }
660 
661     if (value > INT_MAX)
662     {
663         return INT_MAX;
664     }
665 
666     return (int)ceil(value);
667 }
668 
InitDesktopScales()669 void AwtWin32GraphicsDevice::InitDesktopScales()
670 {
671     float dpiX = -1.0f;
672     float dpiY = -1.0f;
673     GetScreenDpi(GetMonitor(), &dpiX, &dpiY);
674     if (dpiX > 0 && dpiY > 0) {
675         SetScale(dpiX / 96, dpiY / 96);
676     }
677 }
678 
GetScaleX()679 float AwtWin32GraphicsDevice::GetScaleX()
680 {
681     return scaleX;
682 }
683 
GetScaleY()684 float AwtWin32GraphicsDevice::GetScaleY()
685 {
686     return scaleY;
687 }
688 
689 /**
690  * Disables offscreen acceleration for this device.  This
691  * sets a flag in the java object that is used to determine
692  * whether offscreen surfaces can be created on the device.
693  */
DisableOffscreenAcceleration()694 void AwtWin32GraphicsDevice::DisableOffscreenAcceleration()
695 {
696     // REMIND: noop for now
697 }
698 
699 /**
700  * Invalidates the GraphicsDevice object associated with this
701  * device by disabling offscreen acceleration and calling
702  * invalidate(defIndex) on the java object.
703  */
Invalidate(JNIEnv * env)704 void AwtWin32GraphicsDevice::Invalidate(JNIEnv *env)
705 {
706     int defIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
707     DisableOffscreenAcceleration();
708     jobject javaDevice = GetJavaDevice();
709     if (!JNU_IsNull(env, javaDevice)) {
710         JNU_CallMethodByName(env, NULL, javaDevice, "invalidate",
711                              "(I)V", defIndex);
712     }
713 }
714 
715 /**
716  * Static deviceIndex-based methods
717  *
718  * The following methods take a deviceIndex for the list of devices
719  * and perform the appropriate action on that device.  This way of
720  * dereferencing the list of devices allows us to do appropriate
721  * locks around the list to ensure multi-threaded safety.
722  */
723 
724 
GetColorModel(JNIEnv * env,jboolean dynamic,int deviceIndex)725 jobject AwtWin32GraphicsDevice::GetColorModel(JNIEnv *env, jboolean dynamic,
726                                               int deviceIndex)
727 {
728     Devices::InstanceAccess devices;
729     return devices->GetDevice(deviceIndex)->GetColorModel(env, dynamic);
730 }
731 
GetMonitorInfo(int deviceIndex)732 LPMONITORINFO AwtWin32GraphicsDevice::GetMonitorInfo(int deviceIndex)
733 {
734     Devices::InstanceAccess devices;
735     return devices->GetDevice(deviceIndex)->GetMonitorInfo();
736 }
737 
738 /**
739  * This function updates the data in the MONITORINFOEX structure pointed to by
740  * pMonitorInfo for all monitors on the system.  Added for 4654713.
741  */
ResetAllMonitorInfo()742 void AwtWin32GraphicsDevice::ResetAllMonitorInfo()
743 {
744     //IE in some circumstances generates WM_SETTINGCHANGE message on appearance
745     //and thus triggers this method
746     //but we may not have the devices list initialized yet.
747     if (!Devices::GetInstance()){
748         return;
749     }
750     Devices::InstanceAccess devices;
751     int devicesNum = devices->GetNumDevices();
752     for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) {
753         HMONITOR monitor = devices->GetDevice(deviceIndex)->GetMonitor();
754         ::GetMonitorInfo(monitor,
755                          devices->GetDevice(deviceIndex)->pMonitorInfo);
756     }
757 }
758 
DisableOffscreenAccelerationForDevice(HMONITOR hMonitor)759 void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice(
760     HMONITOR hMonitor)
761 {
762     Devices::InstanceAccess devices;
763     if (hMonitor == NULL) {
764         devices->GetDevice(0)->DisableOffscreenAcceleration();
765     } else {
766         int devicesNum = devices->GetNumDevices();
767         for (int i = 0; i < devicesNum; ++i) {
768             if (devices->GetDevice(i)->GetMonitor() == hMonitor) {
769                 devices->GetDevice(i)->DisableOffscreenAcceleration();
770             }
771         }
772     }
773 }
774 
GetMonitor(int deviceIndex)775 HMONITOR AwtWin32GraphicsDevice::GetMonitor(int deviceIndex)
776 {
777     Devices::InstanceAccess devices;
778     return devices->GetDevice(deviceIndex)->GetMonitor();
779 }
780 
GetPalette(int deviceIndex)781 HPALETTE AwtWin32GraphicsDevice::GetPalette(int deviceIndex)
782 {
783     Devices::InstanceAccess devices;
784     return devices->GetDevice(deviceIndex)->GetPalette();
785 }
786 
UpdateDynamicColorModel(int deviceIndex)787 void AwtWin32GraphicsDevice::UpdateDynamicColorModel(int deviceIndex)
788 {
789     Devices::InstanceAccess devices;
790     devices->GetDevice(deviceIndex)->UpdateDynamicColorModel();
791 }
792 
UpdateSystemPalette(int deviceIndex)793 BOOL AwtWin32GraphicsDevice::UpdateSystemPalette(int deviceIndex)
794 {
795     Devices::InstanceAccess devices;
796     return devices->GetDevice(deviceIndex)->UpdateSystemPalette();
797 }
798 
SelectPalette(HDC hDC,int deviceIndex)799 HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC, int deviceIndex)
800 {
801     Devices::InstanceAccess devices;
802     return devices->GetDevice(deviceIndex)->SelectPalette(hDC);
803 }
804 
RealizePalette(HDC hDC,int deviceIndex)805 void AwtWin32GraphicsDevice::RealizePalette(HDC hDC, int deviceIndex)
806 {
807     Devices::InstanceAccess devices;
808     devices->GetDevice(deviceIndex)->RealizePalette(hDC);
809 }
810 
GetColorData(int deviceIndex)811 ColorData *AwtWin32GraphicsDevice::GetColorData(int deviceIndex)
812 {
813     Devices::InstanceAccess devices;
814     return devices->GetDevice(deviceIndex)->GetColorData();
815 }
816 
817 /**
818  * Return the grayscale value for the indicated device.
819  */
GetGrayness(int deviceIndex)820 int AwtWin32GraphicsDevice::GetGrayness(int deviceIndex)
821 {
822     Devices::InstanceAccess devices;
823     return devices->GetDevice(deviceIndex)->GetGrayness();
824 }
825 
GetDCFromScreen(int screen)826 HDC AwtWin32GraphicsDevice::GetDCFromScreen(int screen) {
827     J2dTraceLn1(J2D_TRACE_INFO,
828                 "AwtWin32GraphicsDevice::GetDCFromScreen screen=%d", screen);
829     Devices::InstanceAccess devices;
830     AwtWin32GraphicsDevice *dev = devices->GetDevice(screen);
831     return MakeDCFromMonitor(dev->GetMonitor());
832 }
833 
834 /** Compare elements of MONITORINFOEX structures for the given HMONITORs.
835  * If equal, return TRUE
836  */
AreSameMonitors(HMONITOR mon1,HMONITOR mon2)837 BOOL AwtWin32GraphicsDevice::AreSameMonitors(HMONITOR mon1, HMONITOR mon2) {
838     J2dTraceLn2(J2D_TRACE_INFO,
839                 "AwtWin32GraphicsDevice::AreSameMonitors mhnd1=%x mhnd2=%x",
840                 mon1, mon2);
841     DASSERT(mon1 != NULL);
842     DASSERT(mon2 != NULL);
843 
844     MONITORINFOEX mi1;
845     MONITORINFOEX mi2;
846 
847     memset((void*)(&mi1), 0, sizeof(MONITORINFOEX));
848     mi1.cbSize = sizeof(MONITORINFOEX);
849     memset((void*)(&mi2), 0, sizeof(MONITORINFOEX));
850     mi2.cbSize = sizeof(MONITORINFOEX);
851 
852     if (::GetMonitorInfo(mon1, &mi1) != 0 &&
853         ::GetMonitorInfo(mon2, &mi2) != 0 )
854     {
855         if (::EqualRect(&mi1.rcMonitor, &mi2.rcMonitor) &&
856             ::EqualRect(&mi1.rcWork, &mi2.rcWork) &&
857             (mi1.dwFlags  == mi1.dwFlags))
858         {
859 
860             J2dTraceLn(J2D_TRACE_VERBOSE, "  the monitors are the same");
861             return TRUE;
862         }
863     }
864     J2dTraceLn(J2D_TRACE_VERBOSE, "  the monitors are not the same");
865     return FALSE;
866 }
867 
GetScreenFromHMONITOR(HMONITOR mon)868 int AwtWin32GraphicsDevice::GetScreenFromHMONITOR(HMONITOR mon) {
869     J2dTraceLn1(J2D_TRACE_INFO,
870                 "AwtWin32GraphicsDevice::GetScreenFromHMONITOR mhnd=%x", mon);
871 
872     DASSERT(mon != NULL);
873     JNIEnv *env = (JNIEnv*) JNU_GetEnv(jvm, JNI_VERSION_1_2);
874     if (!Devices::GetInstance()) {
875        Devices::UpdateInstance(env);
876     }
877     Devices::InstanceAccess devices;
878 
879     for (int i = 0; i < devices->GetNumDevices(); i++) {
880         HMONITOR mhnd = devices->GetDevice(i)->GetMonitor();
881         if (AreSameMonitors(mon, mhnd)) {
882             J2dTraceLn1(J2D_TRACE_VERBOSE, "  Found device: %d", i);
883             return i;
884         }
885     }
886 
887     J2dTraceLn1(J2D_TRACE_WARNING,
888                 "AwtWin32GraphicsDevice::GetScreenFromHMONITOR(): "\
889                 "couldn't find screen for HMONITOR %x, returning default", mon);
890     return AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
891 }
892 
893 
894 /**
895  * End of static deviceIndex-based methods
896  */
897 
898 
899     const DWORD REQUIRED_FLAGS = (   //Flags which must be set in
900      PFD_SUPPORT_GDI |               //in the PixelFormatDescriptor.
901      PFD_DRAW_TO_WINDOW);            //Used to choose the default config
902                                      //and to check formats in
903                                      //isPixFmtSupported()
904 extern "C" {
905 
906 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initIDs(JNIEnv * env,jclass cls)907 Java_sun_awt_Win32GraphicsDevice_initIDs(JNIEnv *env, jclass cls)
908 {
909     TRY;
910 
911     /* class ids */
912     jclass iCMClass = env->FindClass("java/awt/image/IndexColorModel");
913     CHECK_NULL(iCMClass);
914     AwtWin32GraphicsDevice::indexCMClass = (jclass) env->NewGlobalRef(iCMClass);
915     env->DeleteLocalRef(iCMClass);
916     DASSERT(AwtWin32GraphicsDevice::indexCMClass);
917     CHECK_NULL(AwtWin32GraphicsDevice::indexCMClass);
918 
919     jclass wTClass = env->FindClass("sun/awt/windows/WToolkit");
920     CHECK_NULL(wTClass);
921     AwtWin32GraphicsDevice::wToolkitClass = (jclass)env->NewGlobalRef(wTClass);
922     env->DeleteLocalRef(wTClass);
923     DASSERT(AwtWin32GraphicsDevice::wToolkitClass);
924     CHECK_NULL(AwtWin32GraphicsDevice::wToolkitClass);
925 
926     /* field ids */
927     AwtWin32GraphicsDevice::dynamicColorModelID = env->GetFieldID(cls,
928         "dynamicColorModel", "Ljava/awt/image/ColorModel;");
929     DASSERT(AwtWin32GraphicsDevice::dynamicColorModelID);
930     CHECK_NULL(AwtWin32GraphicsDevice::dynamicColorModelID);
931 
932     AwtWin32GraphicsDevice::indexCMrgbID =
933         env->GetFieldID(AwtWin32GraphicsDevice::indexCMClass, "rgb", "[I");
934     DASSERT(AwtWin32GraphicsDevice::indexCMrgbID);
935     CHECK_NULL(AwtWin32GraphicsDevice::indexCMrgbID);
936 
937     AwtWin32GraphicsDevice::indexCMcacheID =
938         env->GetFieldID(AwtWin32GraphicsDevice::indexCMClass,
939         "lookupcache", "[I");
940     DASSERT(AwtWin32GraphicsDevice::indexCMcacheID);
941     CHECK_NULL(AwtWin32GraphicsDevice::indexCMcacheID);
942 
943     /* method ids */
944     AwtWin32GraphicsDevice::paletteChangedMID = env->GetStaticMethodID(
945         AwtWin32GraphicsDevice::wToolkitClass, "paletteChanged", "()V");
946     DASSERT(AwtWin32GraphicsDevice::paletteChangedMID);
947     CHECK_NULL(AwtWin32GraphicsDevice::paletteChangedMID);
948 
949     // Only want to call this once per session
950     make_uns_ordered_dither_array(img_oda_alpha, 256);
951 
952     // workaround JDK-6477756, ignore return value to keep dll in memory
953     JDK_LoadSystemLibrary("opengl32.dll");
954 
955     CATCH_BAD_ALLOC;
956 }
957 
958 } /* extern "C" */
959 
960 
961 /*
962  * Class:     sun_awt_Win32GraphicsDevice
963  * Method:    getMaxConfigsImpl
964  * Signature: ()I
965  */
966 
Java_sun_awt_Win32GraphicsDevice_getMaxConfigsImpl(JNIEnv * jniEnv,jobject theThis,jint screen)967 JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getMaxConfigsImpl
968     (JNIEnv* jniEnv, jobject theThis, jint screen) {
969         TRY;
970     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
971 
972     PIXELFORMATDESCRIPTOR pfd;
973     int max = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR),
974         &pfd);
975     if (hDC != NULL) {
976         VERIFY(::DeleteDC(hDC));
977         hDC = NULL;
978     }
979     //If ::DescribePixelFormat() fails, max = 0
980     //In this case, we return 1 config with visual number 0
981     if (max == 0) {
982         max = 1;
983     }
984     return (jint)max;
985         CATCH_BAD_ALLOC_RET(0);
986 }
987 
988 /*
989  * Class:     sun_awt_Win32GraphicsDevice
990  * Method:    isPixFmtSupported
991  * Signature: (I)Z
992  */
993 
Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported(JNIEnv * env,jobject theThis,jint pixFmtID,jint screen)994 JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported
995     (JNIEnv* env, jobject theThis, jint pixFmtID, jint screen) {
996         TRY;
997     jboolean suppColor = JNI_TRUE;
998     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
999 
1000     if (pixFmtID == 0) {
1001         return true;
1002     }
1003 
1004     PIXELFORMATDESCRIPTOR pfd;
1005     int max = ::DescribePixelFormat(hDC, (int)pixFmtID,
1006         sizeof(PIXELFORMATDESCRIPTOR), &pfd);
1007     DASSERT(max);
1008 
1009     //Check for supported ColorModel
1010     if ((pfd.cColorBits < 8) ||
1011        ((pfd.cColorBits == 8) && (pfd.iPixelType != PFD_TYPE_COLORINDEX))) {
1012         //Note: this still allows for PixelFormats with > 8 color bits
1013         //which use COLORINDEX instead of RGB.  This seems to work fine,
1014         //although issues may crop up involving PFD_NEED_PALETTE, which
1015         //is not currently taken into account.
1016         //If changes are made, they should also be reflected in
1017         //getDefaultPixID.
1018         suppColor = JNI_FALSE;
1019     }
1020 
1021     if (hDC != NULL) {
1022         VERIFY(::DeleteDC(hDC));
1023         hDC = NULL;
1024     }
1025     return (((pfd.dwFlags & REQUIRED_FLAGS) == REQUIRED_FLAGS) && suppColor) ?
1026      JNI_TRUE : JNI_FALSE;
1027         CATCH_BAD_ALLOC_RET(FALSE);
1028 }
1029 
1030 /*
1031  * Class:     sun_awt_Win32GraphicsDevice
1032  * Method:    getDefaultPixIDImpl
1033  * Signature: (I)I
1034  */
1035 
Java_sun_awt_Win32GraphicsDevice_getDefaultPixIDImpl(JNIEnv * env,jobject theThis,jint screen)1036 JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getDefaultPixIDImpl
1037     (JNIEnv* env, jobject theThis, jint screen) {
1038         TRY;
1039     int pixFmtID = 0;
1040     HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
1041 
1042     PIXELFORMATDESCRIPTOR pfd = {
1043         sizeof(PIXELFORMATDESCRIPTOR),
1044         1,               //version
1045         REQUIRED_FLAGS,  //flags
1046         0,               //iPixelType
1047         0,               //cColorBits
1048         0,0,0,0,0,0,0,0, //cRedBits, cRedShift, green, blue, alpha
1049         0,0,0,0,0,       //cAccumBits, cAccumRedBits, green, blue, alpha
1050         0,0,0,0,0,0,0,0  //etc.
1051     };
1052 
1053     //If 8-bit mode, must use Indexed mode
1054     if (8 == ::GetDeviceCaps(hDC, BITSPIXEL)) {
1055         pfd.iPixelType = PFD_TYPE_COLORINDEX;
1056     }
1057 
1058     pixFmtID = ::ChoosePixelFormat(hDC, &pfd);
1059     if (pixFmtID == 0) {
1060         //Return 0 if GDI call fails.
1061         if (hDC != NULL) {
1062             VERIFY(::DeleteDC(hDC));
1063             hDC = NULL;
1064         }
1065         return pixFmtID;
1066     }
1067 
1068     if (JNI_FALSE == Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported(
1069      env, theThis, pixFmtID, screen)) {
1070         /* Can't find a suitable pixel format ID.  Fall back on 0. */
1071         pixFmtID = 0;
1072     }
1073 
1074     VERIFY(::DeleteDC(hDC));
1075     hDC = NULL;
1076     return (jint)pixFmtID;
1077         CATCH_BAD_ALLOC_RET(0);
1078 }
1079 
1080 /*
1081  * Class:     sun_awt_Win32GraphicsDevice
1082  * Method:    enterFullScreenExclusive
1083  * Signature: (Ljava/awt/peer/WindowPeer;)V
1084  */
1085 
1086 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_enterFullScreenExclusive(JNIEnv * env,jobject graphicsDevice,jint screen,jobject windowPeer)1087 Java_sun_awt_Win32GraphicsDevice_enterFullScreenExclusive(
1088         JNIEnv* env, jobject graphicsDevice,
1089         jint screen, jobject windowPeer) {
1090 
1091     TRY;
1092 
1093     PDATA pData;
1094     JNI_CHECK_PEER_RETURN(windowPeer);
1095 
1096     AwtWindow *window = (AwtWindow *)pData;  // safe cast since we are called
1097                                              // with the WWindowPeer object
1098     HWND hWnd = window->GetHWnd();
1099 
1100     if (!::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
1101                         SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
1102     {
1103         J2dTraceLn1(J2D_TRACE_ERROR,
1104                     "Error %d setting topmost attribute to fs window",
1105                     ::GetLastError());
1106     }
1107 
1108     CATCH_BAD_ALLOC;
1109 }
1110 
1111 /*
1112  * Class:     sun_awt_Win32GraphicsDevice
1113  * Method:    exitFullScreenExclusive
1114  * Signature: (Ljava/awt/peer/WindowPeer;)V
1115  */
1116 
1117 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive(JNIEnv * env,jobject graphicsDevice,jint screen,jobject windowPeer)1118 Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive(
1119         JNIEnv* env, jobject graphicsDevice,
1120         jint screen, jobject windowPeer) {
1121 
1122     TRY;
1123 
1124     PDATA pData;
1125     JNI_CHECK_PEER_RETURN(windowPeer);
1126 
1127     AwtWindow *window = (AwtWindow *)pData;  // safe cast since we are called
1128                                              // with the WWindowPeer object
1129     HWND hWnd = window->GetHWnd();
1130 
1131     jobject target = env->GetObjectField(windowPeer, AwtObject::targetID);
1132     jboolean alwaysOnTop = JNU_GetFieldByName(env, NULL, target, "alwaysOnTop", "Z").z;
1133     env->DeleteLocalRef(target);
1134 
1135     if (!::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
1136                         SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
1137     {
1138         J2dTraceLn1(J2D_TRACE_ERROR,
1139                     "Error %d unsetting topmost attribute to fs window",
1140                     ::GetLastError());
1141     }
1142 
1143     // We should restore alwaysOnTop state as it's anyway dropped here
1144     Java_sun_awt_windows_WWindowPeer_setAlwaysOnTopNative(env, windowPeer, alwaysOnTop);
1145 
1146     CATCH_BAD_ALLOC;
1147 }
1148 
CreateDisplayMode(JNIEnv * env,jint width,jint height,jint bitDepth,jint refreshRate)1149 jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
1150     jint bitDepth, jint refreshRate) {
1151 
1152     TRY;
1153 
1154     jclass displayModeClass = env->FindClass("java/awt/DisplayMode");
1155     if (JNU_IsNull(env, displayModeClass)) {
1156         env->ExceptionClear();
1157         JNU_ThrowInternalError(env, "Could not get display mode class");
1158         return NULL;
1159     }
1160 
1161     jmethodID cid = env->GetMethodID(displayModeClass, "<init>", "(IIII)V");
1162     if (cid == NULL) {
1163         env->ExceptionClear();
1164         JNU_ThrowInternalError(env, "Could not get display mode constructor");
1165         return NULL;
1166     }
1167 
1168     jobject displayMode = env->NewObject(displayModeClass, cid, width,
1169         height, bitDepth, refreshRate);
1170     return displayMode;
1171 
1172     CATCH_BAD_ALLOC_RET(NULL);
1173 }
1174 
1175 /**
1176  * A utility function which retrieves a DISPLAY_DEVICE information
1177  * given a screen number.
1178  *
1179  * If the function was able to find an attached device for the given screen
1180  * number, the lpDisplayDevice will be initialized with the data and
1181  * the function will return TRUE, otherwise it returns FALSE and contents
1182  * of the structure pointed to by lpDisplayDevice is undefined.
1183  */
1184 static BOOL
GetAttachedDisplayDevice(int screen,DISPLAY_DEVICE * lpDisplayDevice)1185 GetAttachedDisplayDevice(int screen, DISPLAY_DEVICE *lpDisplayDevice)
1186 {
1187     DWORD dwDeviceNum = 0;
1188     lpDisplayDevice->cb = sizeof(DISPLAY_DEVICE);
1189     while (EnumDisplayDevices(NULL, dwDeviceNum, lpDisplayDevice, 0) &&
1190            dwDeviceNum < 20) // avoid infinite loop with buggy drivers
1191     {
1192         if (lpDisplayDevice->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
1193             Devices::InstanceAccess devices;
1194             MONITORINFOEX *pMonInfo =
1195                 (LPMONITORINFOEX)devices->GetDevice(screen)->GetMonitorInfo();
1196             // make sure the device names match
1197             if (wcscmp(pMonInfo->szDevice, lpDisplayDevice->DeviceName) == 0) {
1198                 return TRUE;
1199             }
1200         }
1201         dwDeviceNum++;
1202     }
1203     return FALSE;
1204 }
1205 
1206 /*
1207  * Class:     sun_awt_Win32GraphicsDevice
1208  * Method:    getCurrentDisplayMode
1209  * Signature: (IZ)Ljava/awt/DisplayMode;
1210  */
1211 JNIEXPORT jobject JNICALL
Java_sun_awt_Win32GraphicsDevice_getCurrentDisplayMode(JNIEnv * env,jobject graphicsDevice,jint screen)1212 Java_sun_awt_Win32GraphicsDevice_getCurrentDisplayMode
1213     (JNIEnv* env, jobject graphicsDevice, jint screen)
1214 {
1215     TRY;
1216 
1217     DEVMODE dm;
1218     LPTSTR pName = NULL;
1219 
1220     dm.dmSize = sizeof(dm);
1221     dm.dmDriverExtra = 0;
1222 
1223     DISPLAY_DEVICE displayDevice;
1224     if (GetAttachedDisplayDevice(screen, &displayDevice)) {
1225         pName = displayDevice.DeviceName;
1226     }
1227     if (!EnumDisplaySettings(pName, ENUM_CURRENT_SETTINGS, &dm))
1228     {
1229         return NULL;
1230     }
1231 
1232     return CreateDisplayMode(env, dm.dmPelsWidth,
1233         dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency);
1234 
1235     CATCH_BAD_ALLOC_RET(NULL);
1236 }
1237 
1238 /*
1239  * Class:     sun_awt_Win32GraphicsDevice
1240  * Method:    configDisplayMode
1241  * Signature: (IIIIZ)V
1242  */
1243 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_configDisplayMode(JNIEnv * env,jobject graphicsDevice,jint screen,jobject windowPeer,jint width,jint height,jint bitDepth,jint refreshRate)1244 Java_sun_awt_Win32GraphicsDevice_configDisplayMode
1245     (JNIEnv* env, jobject graphicsDevice, jint screen, jobject windowPeer,
1246      jint width, jint height, jint bitDepth, jint refreshRate)
1247 {
1248     TRY;
1249 
1250         DEVMODE dm;
1251 
1252     dm.dmSize = sizeof(dm);
1253     dm.dmDriverExtra = 0;
1254     dm.dmPelsWidth = width;
1255     dm.dmPelsHeight = height;
1256     dm.dmBitsPerPel = bitDepth;
1257     dm.dmDisplayFrequency = refreshRate;
1258     dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT |
1259         DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
1260 
1261     // ChangeDisplaySettings works only on the primary screen.
1262     // ChangeDisplaySettingsEx is not available on NT,
1263     // so it'd be nice not to break it if we can help it.
1264     if (screen == AwtWin32GraphicsDevice::GetDefaultDeviceIndex()) {
1265         if (::ChangeDisplaySettings(&dm, CDS_FULLSCREEN) !=
1266             DISP_CHANGE_SUCCESSFUL)
1267         {
1268             JNU_ThrowInternalError(env,
1269                                    "Could not set display mode");
1270         }
1271         return;
1272     }
1273 
1274     DISPLAY_DEVICE displayDevice;
1275     if (!GetAttachedDisplayDevice(screen, &displayDevice) ||
1276         (::ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, CDS_FULLSCREEN, NULL) !=
1277           DISP_CHANGE_SUCCESSFUL))
1278     {
1279         JNU_ThrowInternalError(env,
1280                                "Could not set display mode");
1281     }
1282 
1283     CATCH_BAD_ALLOC;
1284 }
1285 
1286 class EnumDisplayModeParam {
1287 public:
EnumDisplayModeParam(JNIEnv * e,jobject a)1288     EnumDisplayModeParam(JNIEnv* e, jobject a) : env(e), arrayList(a) {}
1289     JNIEnv* env;
1290     jobject arrayList;
1291 };
1292 
addDisplayMode(JNIEnv * env,jobject arrayList,jint width,jint height,jint bitDepth,jint refreshRate)1293 void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
1294     jint height, jint bitDepth, jint refreshRate) {
1295 
1296     TRY;
1297 
1298     jobject displayMode = CreateDisplayMode(env, width, height,
1299         bitDepth, refreshRate);
1300     if (!JNU_IsNull(env, displayMode)) {
1301         jclass arrayListClass = env->GetObjectClass(arrayList);
1302         if (JNU_IsNull(env, arrayListClass)) {
1303             JNU_ThrowInternalError(env,
1304                 "Could not get class java.util.ArrayList");
1305             return;
1306         }
1307         jmethodID mid = env->GetMethodID(arrayListClass, "add",
1308         "(Ljava/lang/Object;)Z");
1309         if (mid == NULL) {
1310             env->ExceptionClear();
1311             JNU_ThrowInternalError(env,
1312                 "Could not get method java.util.ArrayList.add()");
1313             return;
1314         }
1315         env->CallObjectMethod(arrayList, mid, displayMode);
1316         env->DeleteLocalRef(displayMode);
1317     }
1318 
1319     CATCH_BAD_ALLOC;
1320 }
1321 
1322 /*
1323  * Class:     sun_awt_Win32GraphicsDevice
1324  * Method:    enumDisplayModes
1325  * Signature: (Ljava/util/ArrayList;Z)V
1326  */
Java_sun_awt_Win32GraphicsDevice_enumDisplayModes(JNIEnv * env,jobject graphicsDevice,jint screen,jobject arrayList)1327 JNIEXPORT void JNICALL Java_sun_awt_Win32GraphicsDevice_enumDisplayModes
1328     (JNIEnv* env, jobject graphicsDevice, jint screen, jobject arrayList)
1329 {
1330 
1331     TRY;
1332 
1333     DEVMODE dm;
1334     LPTSTR pName = NULL;
1335     DISPLAY_DEVICE displayDevice;
1336 
1337 
1338     if (GetAttachedDisplayDevice(screen, &displayDevice)) {
1339         pName = displayDevice.DeviceName;
1340     }
1341 
1342     dm.dmSize = sizeof(dm);
1343     dm.dmDriverExtra = 0;
1344 
1345     BOOL bContinue = TRUE;
1346     for (int i = 0; bContinue; i++) {
1347         bContinue = EnumDisplaySettings(pName, i, &dm);
1348         if (dm.dmBitsPerPel >= 8) {
1349             addDisplayMode(env, arrayList, dm.dmPelsWidth, dm.dmPelsHeight,
1350                            dm.dmBitsPerPel, dm.dmDisplayFrequency);
1351             JNU_CHECK_EXCEPTION(env);
1352         }
1353     }
1354 
1355     CATCH_BAD_ALLOC;
1356 }
1357 
1358 /*
1359  * Class:     sun_awt_Win32GraphicsDevice
1360  * Method:    makeColorModel
1361  * Signature: ()Ljava/awt/image/ColorModel
1362  */
1363 
1364 JNIEXPORT jobject JNICALL
Java_sun_awt_Win32GraphicsDevice_makeColorModel(JNIEnv * env,jobject thisPtr,jint screen,jboolean dynamic)1365     Java_sun_awt_Win32GraphicsDevice_makeColorModel
1366     (JNIEnv *env, jobject thisPtr, jint screen, jboolean dynamic)
1367 {
1368     Devices::InstanceAccess devices;
1369     return devices->GetDevice(screen)->GetColorModel(env, dynamic);
1370 }
1371 
1372 /*
1373  * Class:     sun_awt_Win32GraphicsDevice
1374  * Method:    initDevice
1375  * Signature: (I)V
1376  */
1377 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initDevice(JNIEnv * env,jobject thisPtr,jint screen)1378     Java_sun_awt_Win32GraphicsDevice_initDevice
1379     (JNIEnv *env, jobject thisPtr, jint screen)
1380 {
1381     Devices::InstanceAccess devices;
1382     devices->GetDevice(screen)->SetJavaDevice(env, thisPtr);
1383 }
1384 
1385 /*
1386  * Class:     sun_awt_Win32GraphicsDevice
1387  * Method:    setNativeScale
1388  * Signature: (I,F,F)V
1389  */
1390 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_setNativeScale(JNIEnv * env,jobject thisPtr,jint screen,jfloat scaleX,jfloat scaleY)1391     Java_sun_awt_Win32GraphicsDevice_setNativeScale
1392     (JNIEnv *env, jobject thisPtr, jint screen, jfloat scaleX, jfloat scaleY)
1393 {
1394     Devices::InstanceAccess devices;
1395     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1396 
1397     if (device != NULL ) {
1398         device->SetScale(scaleX, scaleY);
1399     }
1400 }
1401 
1402 /*
1403  * Class:     sun_awt_Win32GraphicsDevice
1404  * Method:    getNativeScaleX
1405  * Signature: (I)F
1406  */
1407 JNIEXPORT jfloat JNICALL
Java_sun_awt_Win32GraphicsDevice_getNativeScaleX(JNIEnv * env,jobject thisPtr,jint screen)1408     Java_sun_awt_Win32GraphicsDevice_getNativeScaleX
1409     (JNIEnv *env, jobject thisPtr, jint screen)
1410 {
1411     Devices::InstanceAccess devices;
1412     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1413     return (device == NULL) ? 1 : device->GetScaleX();
1414 }
1415 
1416 /*
1417  * Class:     sun_awt_Win32GraphicsDevice
1418  * Method:    getNativeScaleY
1419  * Signature: (I)F
1420  */
1421 JNIEXPORT jfloat JNICALL
Java_sun_awt_Win32GraphicsDevice_getNativeScaleY(JNIEnv * env,jobject thisPtr,jint screen)1422     Java_sun_awt_Win32GraphicsDevice_getNativeScaleY
1423     (JNIEnv *env, jobject thisPtr, jint screen)
1424 {
1425     Devices::InstanceAccess devices;
1426     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1427     return (device == NULL) ? 1 : device->GetScaleY();
1428 }
1429 
1430 /*
1431 * Class:     sun_awt_Win32GraphicsDevice
1432 * Method:    initNativeScale
1433 * Signature: (I)V;
1434 */
1435 JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initNativeScale(JNIEnv * env,jobject thisPtr,jint screen)1436 Java_sun_awt_Win32GraphicsDevice_initNativeScale
1437 (JNIEnv *env, jobject thisPtr, jint screen)
1438 {
1439     Devices::InstanceAccess devices;
1440     AwtWin32GraphicsDevice *device = devices->GetDevice(screen);
1441 
1442     if (device != NULL) {
1443         device->InitDesktopScales();
1444     }
1445 }
1446 
1447