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