blob: 825a69c8c424ebd8bf1447c851b5865149fbc941 [file] [log] [blame]
/*
* Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* This class holds the information for a particular graphics device.
* Since a display change can cause the creation of new devices
* at any time, there is no referencing of the devices array allowed.
* Instead, anyone wishing to reference a device in the array (e.g.,
* the current default device or a device for a given hWnd) must
* call one of the static methods of this class with the index of
* the device in question. Those methods will then lock the devices
* array and forward the request to the current device at that
* array index.
*/
#include <awt.h>
#include <sun_awt_Win32GraphicsDevice.h>
#include "awt_Canvas.h"
#include "awt_Win32GraphicsDevice.h"
#include "awt_Window.h"
#include "java_awt_Transparency.h"
#include "java_awt_color_ColorSpace.h"
#include "sun_awt_Win32GraphicsDevice.h"
#include "java_awt_image_DataBuffer.h"
#include "dither.h"
#include "img_util_md.h"
#include "Devices.h"
uns_ordered_dither_array img_oda_alpha;
jclass AwtWin32GraphicsDevice::indexCMClass;
jclass AwtWin32GraphicsDevice::wToolkitClass;
jfieldID AwtWin32GraphicsDevice::dynamicColorModelID;
jfieldID AwtWin32GraphicsDevice::indexCMrgbID;
jfieldID AwtWin32GraphicsDevice::indexCMcacheID;
jmethodID AwtWin32GraphicsDevice::paletteChangedMID;
BOOL AwtWin32GraphicsDevice::primaryPalettized;
int AwtWin32GraphicsDevice::primaryIndex = 0;
/**
* Construct this device. Store the screen (index into the devices
* array of this object), the array (used in static references via
* particular device indices), the monitor/pMonitorInfo (which other
* classes will inquire of this device), the bits per pixel of this
* device, and information on whether the primary device is palettized.
*/
AwtWin32GraphicsDevice::AwtWin32GraphicsDevice(int screen,
HMONITOR mhnd, Devices *arr)
{
this->screen = screen;
this->devicesArray = arr;
javaDevice = NULL;
colorData = new ImgColorData;
colorData->grayscale = GS_NOTGRAY;
palette = NULL;
cData = NULL;
gpBitmapInfo = NULL;
monitor = mhnd;
pMonitorInfo = new MONITORINFOEX;
pMonitorInfo->cbSize = sizeof(MONITORINFOEX);
::GetMonitorInfo(monitor, pMonitorInfo);
// Set primary device info: other devices will need to know
// whether the primary is palettized during the initialization
// process
HDC hDC = this->GetDC();
colorData->bitsperpixel = ::GetDeviceCaps(hDC, BITSPIXEL);
this->ReleaseDC(hDC);
if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
primaryIndex = screen;
if (colorData->bitsperpixel > 8) {
primaryPalettized = FALSE;
} else {
primaryPalettized = TRUE;
}
}
}
AwtWin32GraphicsDevice::~AwtWin32GraphicsDevice()
{
delete colorData;
if (gpBitmapInfo) {
free(gpBitmapInfo);
}
if (palette) {
delete palette;
}
if (pMonitorInfo) {
delete pMonitorInfo;
}
if (javaDevice) {
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
env->DeleteWeakGlobalRef(javaDevice);
}
if (cData != NULL) {
freeICMColorData(cData);
}
}
HDC AwtWin32GraphicsDevice::MakeDCFromMonitor(HMONITOR hmMonitor) {
HDC retCode = NULL;
if (NULL != hmMonitor) {
MONITORINFOEX mieInfo;
memset((void*)(&mieInfo), 0, sizeof(MONITORINFOEX));
mieInfo.cbSize = sizeof(MONITORINFOEX);
if (TRUE == ::GetMonitorInfo(hmMonitor, (LPMONITORINFOEX)(&mieInfo))) {
HDC hDC = CreateDC(mieInfo.szDevice, NULL, NULL, NULL);
if (NULL != hDC) {
retCode = hDC;
}
}
}
return retCode;
}
HDC AwtWin32GraphicsDevice::GetDC()
{
return MakeDCFromMonitor(monitor);
}
void AwtWin32GraphicsDevice::ReleaseDC(HDC hDC)
{
if (hDC != NULL) {
::DeleteDC(hDC);
}
}
/**
* Init this device. This creates the bitmap structure
* used to hold the device color data and initializes any
* appropriate palette structures.
*/
void AwtWin32GraphicsDevice::Initialize()
{
unsigned int ri, gi, bi;
if (colorData->bitsperpixel < 8) {
// REMIND: how to handle?
}
// Create a BitmapInfo object for color data
if (!gpBitmapInfo) {
try {
gpBitmapInfo = (BITMAPINFO *)
safe_Malloc(sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
} catch (std::bad_alloc&) {
throw;
}
gpBitmapInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
}
gpBitmapInfo->bmiHeader.biBitCount = 0;
HDC hBMDC = this->GetDC();
HBITMAP hBM = ::CreateCompatibleBitmap(hBMDC, 1, 1);
VERIFY(::GetDIBits(hBMDC, hBM, 0, 1, NULL, gpBitmapInfo, DIB_RGB_COLORS));
if (colorData->bitsperpixel > 8) {
if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
primaryPalettized = FALSE;
}
if (colorData->bitsperpixel != 24) { // 15, 16, or 32 bpp
int foo;
gpBitmapInfo->bmiHeader.biCompression = BI_BITFIELDS;
if (::GetDIBits(hBMDC, hBM, 0, 1, &foo, gpBitmapInfo,
DIB_RGB_COLORS) == 0)
{
// Bug 4684966: If GetDIBits returns an error, we could
// get stuck in an infinite loop setting the colorData
// fields. Hardcode bitColors to reasonable values instead.
// These values are picked according to standard masks
// for these bit depths on win9x, according to MSDN docs.
switch (colorData->bitsperpixel) {
case 15:
((int *)gpBitmapInfo->bmiColors)[0] = 0x7c00;
((int *)gpBitmapInfo->bmiColors)[1] = 0x03e0;
((int *)gpBitmapInfo->bmiColors)[2] = 0x001f;
break;
case 16:
((int *)gpBitmapInfo->bmiColors)[0] = 0xf800;
((int *)gpBitmapInfo->bmiColors)[1] = 0x07e0;
((int *)gpBitmapInfo->bmiColors)[2] = 0x001f;
break;
case 32:
default:
((int *)gpBitmapInfo->bmiColors)[0] = 0xff0000;
((int *)gpBitmapInfo->bmiColors)[1] = 0x00ff00;
((int *)gpBitmapInfo->bmiColors)[2] = 0x0000ff;
break;
}
}
ri = ((unsigned int *)gpBitmapInfo->bmiColors)[0];
colorData->rOff = 0;
while ((ri & 1) == 0) {
colorData->rOff++;
ri >>= 1;
}
colorData->rScale = 0;
while (ri < 0x80) {
colorData->rScale++;
ri <<= 1;
}
gi = ((unsigned int *)gpBitmapInfo->bmiColors)[1];
colorData->gOff = 0;
while ((gi & 1) == 0) {
colorData->gOff++;
gi >>= 1;
}
colorData->gScale = 0;
while (gi < 0x80) {
colorData->gScale++;
gi <<= 1;
}
bi = ((unsigned int *)gpBitmapInfo->bmiColors)[2];
colorData->bOff = 0;
while ((bi & 1) == 0) {
colorData->bOff++;
bi >>= 1;
}
colorData->bScale = 0;
while (bi < 0x80) {
colorData->bScale++;
bi <<= 1;
}
if ( (0 == colorData->bOff)
&& (5 == colorData->gOff)
&& (10 == colorData->rOff)
&& (3 == colorData->bScale)
&& (3 == colorData->gScale)
&& (3 == colorData->rScale)) {
colorData->bitsperpixel = 15;
gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
}
} else { // 24 bpp
gpBitmapInfo->bmiHeader.biBitCount = 24;
gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
// Fill these values in as a convenience for the screen
// ColorModel construction code below (see getColorModel())
((int *)gpBitmapInfo->bmiColors)[0] = 0x0000ff;
((int *)gpBitmapInfo->bmiColors)[1] = 0x00ff00;
((int *)gpBitmapInfo->bmiColors)[2] = 0xff0000;
}
} else {
if (MONITORINFOF_PRIMARY & pMonitorInfo->dwFlags) {
primaryPalettized = TRUE;
}
gpBitmapInfo->bmiHeader.biBitCount = 8;
gpBitmapInfo->bmiHeader.biCompression = BI_RGB;
gpBitmapInfo->bmiHeader.biClrUsed = 256;
gpBitmapInfo->bmiHeader.biClrImportant = 256;
// The initialization of cData is done prior to
// calling palette->Update() since we need it
// for calculating inverseGrayLut
if (cData == NULL) {
cData = (ColorData*)safe_Calloc(1, sizeof(ColorData));
memset(cData, 0, sizeof(ColorData));
initDitherTables(cData);
}
if (!palette) {
palette = new AwtPalette(this);
} else {
palette->Update();
}
palette->UpdateLogical();
}
VERIFY(::DeleteObject(hBM));
VERIFY(::DeleteDC(hBMDC));
}
/**
* Creates a new colorModel given the current device configuration.
* The dynamic flag determines whether we use the system palette
* (dynamic == TRUE) or our custom palette in creating a new
* IndexedColorModel.
*/
jobject AwtWin32GraphicsDevice::GetColorModel(JNIEnv *env, jboolean dynamic)
{
jobject awt_colormodel;
int i;
if (colorData->bitsperpixel == 24) {
awt_colormodel =
JNU_NewObjectByName(env, "sun/awt/Win32ColorModel24", "()V");
} else if (colorData->bitsperpixel > 8) {
int *masks = (int *)gpBitmapInfo->bmiColors;
int numbits = 0;
unsigned int bits = (masks[0] | masks[1] | masks[2]);
while (bits) {
numbits++;
bits >>= 1;
}
awt_colormodel = JNU_NewObjectByName(env,
"java/awt/image/DirectColorModel",
"(IIII)V", numbits,
masks[0], masks[1], masks[2]);
} else if (colorData->grayscale == GS_STATICGRAY) {
jclass clazz;
jclass clazz1;
jmethodID mid;
jobject cspace = NULL;
jint bits[1];
jintArray bitsArray;
clazz1 = env->FindClass("java/awt/color/ColorSpace");
CHECK_NULL_RETURN(clazz1, NULL);
mid = env->GetStaticMethodID(clazz1, "getInstance",
"(I)Ljava/awt/color/ColorSpace;");
CHECK_NULL_RETURN(mid, NULL);
cspace = env->CallStaticObjectMethod(clazz1, mid,
java_awt_color_ColorSpace_CS_GRAY);
CHECK_NULL_RETURN(cspace, NULL);
bits[0] = 8;
bitsArray = env->NewIntArray(1);
if (bitsArray == 0) {
return NULL;
} else {
env->SetIntArrayRegion(bitsArray, 0, 1, bits);
}
clazz = env->FindClass("java/awt/image/ComponentColorModel");
CHECK_NULL_RETURN(clazz, NULL);
mid = env->GetMethodID(clazz,"<init>",
"(Ljava/awt/color/ColorSpace;[IZZII)V");
CHECK_NULL_RETURN(mid, NULL);
awt_colormodel = env->NewObject(clazz, mid,
cspace,
bitsArray,
JNI_FALSE,
JNI_FALSE,
java_awt_Transparency_OPAQUE,
java_awt_image_DataBuffer_TYPE_BYTE);
} else {
jintArray hRGB = env->NewIntArray(256);
unsigned int *rgb = NULL, *rgbP = NULL;
jboolean allvalid = JNI_TRUE;
jbyte vbits[256/8];
jobject validBits = NULL;
CHECK_NULL_RETURN(hRGB, NULL);
/* Create the LUT from the color map */
try {
rgb = (unsigned int *) env->GetPrimitiveArrayCritical(hRGB, 0);
CHECK_NULL_RETURN(rgb, NULL);
rgbP = rgb;
if (!palette) {
palette = new AwtPalette(this);
palette->UpdateLogical();
}
if (colorData->grayscale == GS_INDEXGRAY) {
/* For IndexColorModel, pretend first 10 colors and last
10 colors are transparent black. This makes
ICM.allgrayopaque true.
*/
unsigned int *logicalEntries = palette->GetLogicalEntries();
for (i=0; i < 10; i++) {
rgbP[i] = 0x00000000;
rgbP[i+246] = 0x00000000;
}
memcpy(&rgbP[10], &logicalEntries[10], 236 * sizeof(RGBQUAD));
// We need to specify which entries in the colormap are
// valid so that the transparent black entries we have
// created do not affect the Transparency setting of the
// IndexColorModel. The vbits array is used to construct
// a BigInteger such that the most significant bit of vbits[0]
// indicates the validity of the last color (#256) and the
// least significant bit of vbits[256/8] indicates the
// validity of the first color (#0). We need to fill vbits
// with all 1's and then turn off the first and last 10 bits.
memset(vbits, 0xff, sizeof(vbits));
vbits[0] = 0;
vbits[1] = (jbyte) (0xff >> 2);
vbits[sizeof(vbits)-2] = (jbyte) (0xff << 2);
vbits[sizeof(vbits)-1] = 0;
allvalid = JNI_FALSE;
} else {
if (AwtPalette::UseCustomPalette() && !dynamic) {
// If we plan to use our custom palette (i.e., we are
// not running inside another app and we are not creating
// a dynamic colorModel object), then setup ICM with
// custom palette entries
unsigned int *logicalEntries = palette->GetLogicalEntries();
memcpy(rgbP, logicalEntries, 256 * sizeof(int));
} else {
// Else, use current system palette entries.
// REMIND: This may not give the result we want if
// we are running inside another app and that
// parent app is running in the background when we
// reach here. We could at least cache an "ideal" set of
// system palette entries from the first time we are
// running in the foreground and then future ICM's will
// use that set instead.
unsigned int *systemEntries = palette->GetSystemEntries();
memcpy(rgbP, systemEntries, 256 * sizeof(int));
}
}
} catch (...) {
env->ReleasePrimitiveArrayCritical(hRGB, rgb, 0);
throw;
}
env->ReleasePrimitiveArrayCritical(hRGB, rgb, 0);
// Construct a new color model
if (!allvalid) {
jbyteArray bArray = env->NewByteArray(sizeof(vbits));
CHECK_NULL_RETURN(bArray, NULL);
env->SetByteArrayRegion(bArray, 0, sizeof(vbits), vbits);
validBits = JNU_NewObjectByName(env,
"java/math/BigInteger",
"([B)V", bArray);
JNU_CHECK_EXCEPTION_RETURN(env, NULL);
}
awt_colormodel =
JNU_NewObjectByName(env,
"java/awt/image/IndexColorModel",
"(II[IIILjava/math/BigInteger;)V",
8, 256,
hRGB, 0,
java_awt_image_DataBuffer_TYPE_BYTE,
validBits);
}
return awt_colormodel;
}
/**
* Called from AwtPalette code when it is determined what grayscale
* value (if any) the current logical palette has
*/
void AwtWin32GraphicsDevice::SetGrayness(int grayValue)
{
colorData->grayscale = grayValue;
}
/**
* Update our dynamic IndexedColorModel. This happens after
* a change to the system palette. Any surfaces stored in vram
* (Win32OffScreenSurfaceData and GDIWindowSurfaceData objects)
* refer to this colorModel and use its lookup table and inverse
* lookup to calculate correct index values for rgb colors. So
* the colorModel must always reflect the current state of the
* system palette.
*/
void AwtWin32GraphicsDevice::UpdateDynamicColorModel()
{
if (!javaDevice) {
// javaDevice may not be set yet. If not, return. In
// this situation, we probably don't need an update anyway
// since the colorModel will be created with the correct
// info when the java side is initialized.
return;
}
JNIEnv *env = (JNIEnv *)JNU_GetEnv(jvm, JNI_VERSION_1_2);
jobject colorModel = env->GetObjectField(javaDevice,
dynamicColorModelID);
if (!colorModel) {
return;
}
if (env->IsInstanceOf(colorModel, indexCMClass)) {
// If colorModel not of type ICM then we're not in 8-bit mode and
// don't need to update it
jboolean isCopy;
unsigned int *newEntries = palette->GetSystemEntries();
jintArray rgbArray = (jintArray)env->GetObjectField(colorModel,
AwtWin32GraphicsDevice::indexCMrgbID);
jintArray cacheArray = (jintArray)env->GetObjectField(colorModel,
AwtWin32GraphicsDevice::indexCMcacheID);
if (!rgbArray || !cacheArray) {
JNU_ThrowInternalError(env, "rgb or lookupcache array of IndexColorModel null");
return;
}
int rgbLength = env->GetArrayLength(rgbArray);
int cacheLength = env->GetArrayLength(cacheArray);
jint *cmEntries = (jint *)env->GetPrimitiveArrayCritical(rgbArray, &isCopy);
if (!cmEntries) {
env->ExceptionClear();
JNU_ThrowInternalError(env, "Problem retrieving rgb critical array");
return;
}
jint *cache = (jint *)env->GetPrimitiveArrayCritical(cacheArray, &isCopy);
if (!cache) {
env->ExceptionClear();
env->ReleasePrimitiveArrayCritical(rgbArray, cmEntries, JNI_ABORT);
JNU_ThrowInternalError(env, "Problem retrieving cache critical array");
return;
}
// Set the new rgb values
int i;
for (i = 0; i < rgbLength; ++i) {
cmEntries[i] = newEntries[i];
}
// clear out the old cache
for (i = 0; i < cacheLength; ++i) {
cache[i] = 0;
}
env->ReleasePrimitiveArrayCritical(cacheArray, cache, 0);
env->ReleasePrimitiveArrayCritical(rgbArray, cmEntries, 0);
// Call WToolkit::paletteChanged() method; this will invalidate
// the offscreen surfaces dependent on this dynamic colorModel
// to ensure that they get redrawn with the correct color indices
env->CallStaticVoidMethod(AwtWin32GraphicsDevice::wToolkitClass,
paletteChangedMID);
}
}
unsigned int *AwtWin32GraphicsDevice::GetSystemPaletteEntries()
{
// REMIND: What to do if palette NULL? Need to throw
// some kind of exception?
return palette->GetSystemEntries();
}
unsigned char *AwtWin32GraphicsDevice::GetSystemInverseLUT()
{
// REMIND: What to do if palette NULL? Need to throw
// some kind of exception?
return palette->GetSystemInverseLUT();
}
BOOL AwtWin32GraphicsDevice::UpdateSystemPalette()
{
if (colorData->bitsperpixel > 8) {
return FALSE;
} else {
return palette->Update();
}
}
HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC)
{
if (palette) {
return palette->Select(hDC);
} else {
return NULL;
}
}
void AwtWin32GraphicsDevice::RealizePalette(HDC hDC)
{
if (palette) {
palette->Realize(hDC);
}
}
/**
* Deterine which device the HWND exists on and return the
* appropriate index into the devices array.
*/
int AwtWin32GraphicsDevice::DeviceIndexForWindow(HWND hWnd)
{
HMONITOR mon = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);
int screen = AwtWin32GraphicsDevice::GetScreenFromHMONITOR(mon);
return screen;
}
/**
* Get the HPALETTE associated with this device
*/
HPALETTE AwtWin32GraphicsDevice::GetPalette()
{
if (palette) {
return palette->GetPalette();
} else {
return NULL;
}
}
/**
* Object referring to this device is releasing that reference.
* This allows the array holding all devices to be released (once
* all references to the array have gone away).
*/
void AwtWin32GraphicsDevice::Release()
{
devicesArray->Release();
}
/**
* Links this native object with its java Win32GraphicsDevice.
* Need this link because the colorModel of the java device
* may be updated from native code.
*/
void AwtWin32GraphicsDevice::SetJavaDevice(JNIEnv *env, jobject objPtr)
{
javaDevice = env->NewWeakGlobalRef(objPtr);
}
/**
* Disables offscreen acceleration for this device. This
* sets a flag in the java object that is used to determine
* whether offscreen surfaces can be created on the device.
*/
void AwtWin32GraphicsDevice::DisableOffscreenAcceleration()
{
// REMIND: noop for now
}
/**
* Invalidates the GraphicsDevice object associated with this
* device by disabling offscreen acceleration and calling
* invalidate(defIndex) on the java object.
*/
void AwtWin32GraphicsDevice::Invalidate(JNIEnv *env)
{
int defIndex = AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
DisableOffscreenAcceleration();
jobject javaDevice = GetJavaDevice();
if (!JNU_IsNull(env, javaDevice)) {
JNU_CallMethodByName(env, NULL, javaDevice, "invalidate",
"(I)V", defIndex);
}
}
/**
* Static deviceIndex-based methods
*
* The following methods take a deviceIndex for the list of devices
* and perform the appropriate action on that device. This way of
* dereferencing the list of devices allows us to do appropriate
* locks around the list to ensure multi-threaded safety.
*/
jobject AwtWin32GraphicsDevice::GetColorModel(JNIEnv *env, jboolean dynamic,
int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->GetColorModel(env, dynamic);
}
LPMONITORINFO AwtWin32GraphicsDevice::GetMonitorInfo(int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->GetMonitorInfo();
}
/**
* This function updates the data in the MONITORINFOEX structure pointed to by
* pMonitorInfo for all monitors on the system. Added for 4654713.
*/
void AwtWin32GraphicsDevice::ResetAllMonitorInfo()
{
//IE in some circumstances generates WM_SETTINGCHANGE message on appearance
//and thus triggers this method
//but we may not have the devices list initialized yet.
if (!Devices::GetInstance()){
return;
}
Devices::InstanceAccess devices;
int devicesNum = devices->GetNumDevices();
for (int deviceIndex = 0; deviceIndex < devicesNum; deviceIndex++) {
HMONITOR monitor = devices->GetDevice(deviceIndex)->GetMonitor();
::GetMonitorInfo(monitor,
devices->GetDevice(deviceIndex)->pMonitorInfo);
}
}
void AwtWin32GraphicsDevice::DisableOffscreenAccelerationForDevice(
HMONITOR hMonitor)
{
Devices::InstanceAccess devices;
if (hMonitor == NULL) {
devices->GetDevice(0)->DisableOffscreenAcceleration();
} else {
int devicesNum = devices->GetNumDevices();
for (int i = 0; i < devicesNum; ++i) {
if (devices->GetDevice(i)->GetMonitor() == hMonitor) {
devices->GetDevice(i)->DisableOffscreenAcceleration();
}
}
}
}
HMONITOR AwtWin32GraphicsDevice::GetMonitor(int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->GetMonitor();
}
HPALETTE AwtWin32GraphicsDevice::GetPalette(int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->GetPalette();
}
void AwtWin32GraphicsDevice::UpdateDynamicColorModel(int deviceIndex)
{
Devices::InstanceAccess devices;
devices->GetDevice(deviceIndex)->UpdateDynamicColorModel();
}
BOOL AwtWin32GraphicsDevice::UpdateSystemPalette(int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->UpdateSystemPalette();
}
HPALETTE AwtWin32GraphicsDevice::SelectPalette(HDC hDC, int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->SelectPalette(hDC);
}
void AwtWin32GraphicsDevice::RealizePalette(HDC hDC, int deviceIndex)
{
Devices::InstanceAccess devices;
devices->GetDevice(deviceIndex)->RealizePalette(hDC);
}
ColorData *AwtWin32GraphicsDevice::GetColorData(int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->GetColorData();
}
/**
* Return the grayscale value for the indicated device.
*/
int AwtWin32GraphicsDevice::GetGrayness(int deviceIndex)
{
Devices::InstanceAccess devices;
return devices->GetDevice(deviceIndex)->GetGrayness();
}
HDC AwtWin32GraphicsDevice::GetDCFromScreen(int screen) {
J2dTraceLn1(J2D_TRACE_INFO,
"AwtWin32GraphicsDevice::GetDCFromScreen screen=%d", screen);
Devices::InstanceAccess devices;
AwtWin32GraphicsDevice *dev = devices->GetDevice(screen);
return MakeDCFromMonitor(dev->GetMonitor());
}
/** Compare elements of MONITORINFOEX structures for the given HMONITORs.
* If equal, return TRUE
*/
BOOL AwtWin32GraphicsDevice::AreSameMonitors(HMONITOR mon1, HMONITOR mon2) {
J2dTraceLn2(J2D_TRACE_INFO,
"AwtWin32GraphicsDevice::AreSameMonitors mhnd1=%x mhnd2=%x",
mon1, mon2);
DASSERT(mon1 != NULL);
DASSERT(mon2 != NULL);
MONITORINFOEX mi1;
MONITORINFOEX mi2;
memset((void*)(&mi1), 0, sizeof(MONITORINFOEX));
mi1.cbSize = sizeof(MONITORINFOEX);
memset((void*)(&mi2), 0, sizeof(MONITORINFOEX));
mi2.cbSize = sizeof(MONITORINFOEX);
if (::GetMonitorInfo(mon1, &mi1) != 0 &&
::GetMonitorInfo(mon2, &mi2) != 0 )
{
if (::EqualRect(&mi1.rcMonitor, &mi2.rcMonitor) &&
::EqualRect(&mi1.rcWork, &mi2.rcWork) &&
(mi1.dwFlags == mi1.dwFlags))
{
J2dTraceLn(J2D_TRACE_VERBOSE, " the monitors are the same");
return TRUE;
}
}
J2dTraceLn(J2D_TRACE_VERBOSE, " the monitors are not the same");
return FALSE;
}
int AwtWin32GraphicsDevice::GetScreenFromHMONITOR(HMONITOR mon) {
J2dTraceLn1(J2D_TRACE_INFO,
"AwtWin32GraphicsDevice::GetScreenFromHMONITOR mhnd=%x", mon);
DASSERT(mon != NULL);
Devices::InstanceAccess devices;
for (int i = 0; i < devices->GetNumDevices(); i++) {
HMONITOR mhnd = devices->GetDevice(i)->GetMonitor();
if (AreSameMonitors(mon, mhnd)) {
J2dTraceLn1(J2D_TRACE_VERBOSE, " Found device: %d", i);
return i;
}
}
J2dTraceLn1(J2D_TRACE_WARNING,
"AwtWin32GraphicsDevice::GetScreenFromHMONITOR(): "\
"couldn't find screen for HMONITOR %x, returning default", mon);
return AwtWin32GraphicsDevice::GetDefaultDeviceIndex();
}
/**
* End of static deviceIndex-based methods
*/
const DWORD REQUIRED_FLAGS = ( //Flags which must be set in
PFD_SUPPORT_GDI | //in the PixelFormatDescriptor.
PFD_DRAW_TO_WINDOW); //Used to choose the default config
//and to check formats in
//isPixFmtSupported()
extern "C" {
JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initIDs(JNIEnv *env, jclass cls)
{
TRY;
/* class ids */
jclass iCMClass = env->FindClass("java/awt/image/IndexColorModel");
CHECK_NULL(iCMClass);
AwtWin32GraphicsDevice::indexCMClass = (jclass) env->NewGlobalRef(iCMClass);
env->DeleteLocalRef(iCMClass);
DASSERT(AwtWin32GraphicsDevice::indexCMClass);
CHECK_NULL(AwtWin32GraphicsDevice::indexCMClass);
jclass wTClass = env->FindClass("sun/awt/windows/WToolkit");
CHECK_NULL(wTClass);
AwtWin32GraphicsDevice::wToolkitClass = (jclass)env->NewGlobalRef(wTClass);
env->DeleteLocalRef(wTClass);
DASSERT(AwtWin32GraphicsDevice::wToolkitClass);
CHECK_NULL(AwtWin32GraphicsDevice::wToolkitClass);
/* field ids */
AwtWin32GraphicsDevice::dynamicColorModelID = env->GetFieldID(cls,
"dynamicColorModel", "Ljava/awt/image/ColorModel;");
DASSERT(AwtWin32GraphicsDevice::dynamicColorModelID);
CHECK_NULL(AwtWin32GraphicsDevice::dynamicColorModelID);
AwtWin32GraphicsDevice::indexCMrgbID =
env->GetFieldID(AwtWin32GraphicsDevice::indexCMClass, "rgb", "[I");
DASSERT(AwtWin32GraphicsDevice::indexCMrgbID);
CHECK_NULL(AwtWin32GraphicsDevice::indexCMrgbID);
AwtWin32GraphicsDevice::indexCMcacheID =
env->GetFieldID(AwtWin32GraphicsDevice::indexCMClass,
"lookupcache", "[I");
DASSERT(AwtWin32GraphicsDevice::indexCMcacheID);
CHECK_NULL(AwtWin32GraphicsDevice::indexCMcacheID);
/* method ids */
AwtWin32GraphicsDevice::paletteChangedMID = env->GetStaticMethodID(
AwtWin32GraphicsDevice::wToolkitClass, "paletteChanged", "()V");
DASSERT(AwtWin32GraphicsDevice::paletteChangedMID);
CHECK_NULL(AwtWin32GraphicsDevice::paletteChangedMID);
// Only want to call this once per session
make_uns_ordered_dither_array(img_oda_alpha, 256);
CATCH_BAD_ALLOC;
}
} /* extern "C" */
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: getMaxConfigsImpl
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getMaxConfigsImpl
(JNIEnv* jniEnv, jobject theThis, jint screen) {
TRY;
HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
PIXELFORMATDESCRIPTOR pfd;
int max = ::DescribePixelFormat(hDC, 1, sizeof(PIXELFORMATDESCRIPTOR),
&pfd);
if (hDC != NULL) {
VERIFY(::DeleteDC(hDC));
hDC = NULL;
}
//If ::DescribePixelFormat() fails, max = 0
//In this case, we return 1 config with visual number 0
if (max == 0) {
max = 1;
}
return (jint)max;
CATCH_BAD_ALLOC_RET(0);
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: isPixFmtSupported
* Signature: (I)Z
*/
JNIEXPORT jboolean JNICALL Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported
(JNIEnv* env, jobject theThis, jint pixFmtID, jint screen) {
TRY;
jboolean suppColor = JNI_TRUE;
HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
if (pixFmtID == 0) {
return true;
}
PIXELFORMATDESCRIPTOR pfd;
int max = ::DescribePixelFormat(hDC, (int)pixFmtID,
sizeof(PIXELFORMATDESCRIPTOR), &pfd);
DASSERT(max);
//Check for supported ColorModel
if ((pfd.cColorBits < 8) ||
((pfd.cColorBits == 8) && (pfd.iPixelType != PFD_TYPE_COLORINDEX))) {
//Note: this still allows for PixelFormats with > 8 color bits
//which use COLORINDEX instead of RGB. This seems to work fine,
//although issues may crop up involving PFD_NEED_PALETTE, which
//is not currently taken into account.
//If changes are made, they should also be reflected in
//getDefaultPixID.
suppColor = JNI_FALSE;
}
if (hDC != NULL) {
VERIFY(::DeleteDC(hDC));
hDC = NULL;
}
return (((pfd.dwFlags & REQUIRED_FLAGS) == REQUIRED_FLAGS) && suppColor) ?
JNI_TRUE : JNI_FALSE;
CATCH_BAD_ALLOC_RET(FALSE);
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: getDefaultPixIDImpl
* Signature: (I)I
*/
JNIEXPORT jint JNICALL Java_sun_awt_Win32GraphicsDevice_getDefaultPixIDImpl
(JNIEnv* env, jobject theThis, jint screen) {
TRY;
int pixFmtID = 0;
HDC hDC = AwtWin32GraphicsDevice::GetDCFromScreen(screen);
PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR),
1, //version
REQUIRED_FLAGS, //flags
0, //iPixelType
0, //cColorBits
0,0,0,0,0,0,0,0, //cRedBits, cRedShift, green, blue, alpha
0,0,0,0,0, //cAccumBits, cAccumRedBits, green, blue, alpha
0,0,0,0,0,0,0,0 //etc.
};
//If 8-bit mode, must use Indexed mode
if (8 == ::GetDeviceCaps(hDC, BITSPIXEL)) {
pfd.iPixelType = PFD_TYPE_COLORINDEX;
}
pixFmtID = ::ChoosePixelFormat(hDC, &pfd);
if (pixFmtID == 0) {
//Return 0 if GDI call fails.
if (hDC != NULL) {
VERIFY(::DeleteDC(hDC));
hDC = NULL;
}
return pixFmtID;
}
if (JNI_FALSE == Java_sun_awt_Win32GraphicsDevice_isPixFmtSupported(
env, theThis, pixFmtID, screen)) {
/* Can't find a suitable pixel format ID. Fall back on 0. */
pixFmtID = 0;
}
VERIFY(::DeleteDC(hDC));
hDC = NULL;
return (jint)pixFmtID;
CATCH_BAD_ALLOC_RET(0);
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: enterFullScreenExclusive
* Signature: (Ljava/awt/peer/WindowPeer;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_enterFullScreenExclusive(
JNIEnv* env, jobject graphicsDevice,
jint screen, jobject windowPeer) {
TRY;
PDATA pData;
JNI_CHECK_PEER_RETURN(windowPeer);
AwtWindow *window = (AwtWindow *)pData; // safe cast since we are called
// with the WWindowPeer object
HWND hWnd = window->GetHWnd();
if (!::SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
{
J2dTraceLn1(J2D_TRACE_ERROR,
"Error %d setting topmost attribute to fs window",
::GetLastError());
}
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: exitFullScreenExclusive
* Signature: (Ljava/awt/peer/WindowPeer;)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_exitFullScreenExclusive(
JNIEnv* env, jobject graphicsDevice,
jint screen, jobject windowPeer) {
TRY;
PDATA pData;
JNI_CHECK_PEER_RETURN(windowPeer);
AwtWindow *window = (AwtWindow *)pData; // safe cast since we are called
// with the WWindowPeer object
HWND hWnd = window->GetHWnd();
jobject target = env->GetObjectField(windowPeer, AwtObject::targetID);
jboolean alwaysOnTop = JNU_GetFieldByName(env, NULL, target, "alwaysOnTop", "Z").z;
env->DeleteLocalRef(target);
if (!::SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE|SWP_NOOWNERZORDER|SWP_NOSIZE))
{
J2dTraceLn1(J2D_TRACE_ERROR,
"Error %d unsetting topmost attribute to fs window",
::GetLastError());
}
// We should restore alwaysOnTop state as it's anyway dropped here
Java_sun_awt_windows_WWindowPeer_setAlwaysOnTopNative(env, windowPeer, alwaysOnTop);
CATCH_BAD_ALLOC;
}
jobject CreateDisplayMode(JNIEnv* env, jint width, jint height,
jint bitDepth, jint refreshRate) {
TRY;
jclass displayModeClass = env->FindClass("java/awt/DisplayMode");
if (JNU_IsNull(env, displayModeClass)) {
env->ExceptionClear();
JNU_ThrowInternalError(env, "Could not get display mode class");
return NULL;
}
jmethodID cid = env->GetMethodID(displayModeClass, "<init>", "(IIII)V");
if (cid == NULL) {
env->ExceptionClear();
JNU_ThrowInternalError(env, "Could not get display mode constructor");
return NULL;
}
jobject displayMode = env->NewObject(displayModeClass, cid, width,
height, bitDepth, refreshRate);
return displayMode;
CATCH_BAD_ALLOC_RET(NULL);
}
/**
* A utility function which retrieves a DISPLAY_DEVICE information
* given a screen number.
*
* If the function was able to find an attached device for the given screen
* number, the lpDisplayDevice will be initialized with the data and
* the function will return TRUE, otherwise it returns FALSE and contents
* of the structure pointed to by lpDisplayDevice is undefined.
*/
static BOOL
GetAttachedDisplayDevice(int screen, DISPLAY_DEVICE *lpDisplayDevice)
{
DWORD dwDeviceNum = 0;
lpDisplayDevice->cb = sizeof(DISPLAY_DEVICE);
while (EnumDisplayDevices(NULL, dwDeviceNum, lpDisplayDevice, 0) &&
dwDeviceNum < 20) // avoid infinite loop with buggy drivers
{
if (lpDisplayDevice->StateFlags & DISPLAY_DEVICE_ATTACHED_TO_DESKTOP) {
Devices::InstanceAccess devices;
MONITORINFOEX *pMonInfo =
(LPMONITORINFOEX)devices->GetDevice(screen)->GetMonitorInfo();
// make sure the device names match
if (wcscmp(pMonInfo->szDevice, lpDisplayDevice->DeviceName) == 0) {
return TRUE;
}
}
dwDeviceNum++;
}
return FALSE;
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: getCurrentDisplayMode
* Signature: (IZ)Ljava/awt/DisplayMode;
*/
JNIEXPORT jobject JNICALL
Java_sun_awt_Win32GraphicsDevice_getCurrentDisplayMode
(JNIEnv* env, jobject graphicsDevice, jint screen)
{
TRY;
DEVMODE dm;
LPTSTR pName = NULL;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
DISPLAY_DEVICE displayDevice;
if (GetAttachedDisplayDevice(screen, &displayDevice)) {
pName = displayDevice.DeviceName;
}
if (!EnumDisplaySettings(pName, ENUM_CURRENT_SETTINGS, &dm))
{
return NULL;
}
return CreateDisplayMode(env, dm.dmPelsWidth,
dm.dmPelsHeight, dm.dmBitsPerPel, dm.dmDisplayFrequency);
CATCH_BAD_ALLOC_RET(NULL);
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: configDisplayMode
* Signature: (IIIIZ)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_configDisplayMode
(JNIEnv* env, jobject graphicsDevice, jint screen, jobject windowPeer,
jint width, jint height, jint bitDepth, jint refreshRate)
{
TRY;
DEVMODE dm;
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
dm.dmPelsWidth = width;
dm.dmPelsHeight = height;
dm.dmBitsPerPel = bitDepth;
dm.dmDisplayFrequency = refreshRate;
dm.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT |
DM_BITSPERPEL | DM_DISPLAYFREQUENCY;
// ChangeDisplaySettings works only on the primary screen.
// ChangeDisplaySettingsEx is not available on NT,
// so it'd be nice not to break it if we can help it.
if (screen == AwtWin32GraphicsDevice::GetDefaultDeviceIndex()) {
if (::ChangeDisplaySettings(&dm, CDS_FULLSCREEN) !=
DISP_CHANGE_SUCCESSFUL)
{
JNU_ThrowInternalError(env,
"Could not set display mode");
}
return;
}
DISPLAY_DEVICE displayDevice;
if (!GetAttachedDisplayDevice(screen, &displayDevice) ||
(::ChangeDisplaySettingsEx(displayDevice.DeviceName, &dm, NULL, CDS_FULLSCREEN, NULL) !=
DISP_CHANGE_SUCCESSFUL))
{
JNU_ThrowInternalError(env,
"Could not set display mode");
}
CATCH_BAD_ALLOC;
}
class EnumDisplayModeParam {
public:
EnumDisplayModeParam(JNIEnv* e, jobject a) : env(e), arrayList(a) {}
JNIEnv* env;
jobject arrayList;
};
void addDisplayMode(JNIEnv* env, jobject arrayList, jint width,
jint height, jint bitDepth, jint refreshRate) {
TRY;
jobject displayMode = CreateDisplayMode(env, width, height,
bitDepth, refreshRate);
if (!JNU_IsNull(env, displayMode)) {
jclass arrayListClass = env->GetObjectClass(arrayList);
if (JNU_IsNull(env, arrayListClass)) {
JNU_ThrowInternalError(env,
"Could not get class java.util.ArrayList");
return;
}
jmethodID mid = env->GetMethodID(arrayListClass, "add",
"(Ljava/lang/Object;)Z");
if (mid == NULL) {
env->ExceptionClear();
JNU_ThrowInternalError(env,
"Could not get method java.util.ArrayList.add()");
return;
}
env->CallObjectMethod(arrayList, mid, displayMode);
env->DeleteLocalRef(displayMode);
}
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: enumDisplayModes
* Signature: (Ljava/util/ArrayList;Z)V
*/
JNIEXPORT void JNICALL Java_sun_awt_Win32GraphicsDevice_enumDisplayModes
(JNIEnv* env, jobject graphicsDevice, jint screen, jobject arrayList)
{
TRY;
DEVMODE dm;
LPTSTR pName = NULL;
DISPLAY_DEVICE displayDevice;
if (GetAttachedDisplayDevice(screen, &displayDevice)) {
pName = displayDevice.DeviceName;
}
dm.dmSize = sizeof(dm);
dm.dmDriverExtra = 0;
BOOL bContinue = TRUE;
for (int i = 0; bContinue; i++) {
bContinue = EnumDisplaySettings(pName, i, &dm);
if (dm.dmBitsPerPel >= 8) {
addDisplayMode(env, arrayList, dm.dmPelsWidth, dm.dmPelsHeight,
dm.dmBitsPerPel, dm.dmDisplayFrequency);
JNU_CHECK_EXCEPTION(env);
}
}
CATCH_BAD_ALLOC;
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: makeColorModel
* Signature: ()Ljava/awt/image/ColorModel
*/
JNIEXPORT jobject JNICALL
Java_sun_awt_Win32GraphicsDevice_makeColorModel
(JNIEnv *env, jobject thisPtr, jint screen, jboolean dynamic)
{
Devices::InstanceAccess devices;
return devices->GetDevice(screen)->GetColorModel(env, dynamic);
}
/*
* Class: sun_awt_Win32GraphicsDevice
* Method: initDevice
* Signature: (I)V
*/
JNIEXPORT void JNICALL
Java_sun_awt_Win32GraphicsDevice_initDevice
(JNIEnv *env, jobject thisPtr, jint screen)
{
Devices::InstanceAccess devices;
devices->GetDevice(screen)->SetJavaDevice(env, thisPtr);
}