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