blob: cd38ca5e5587a968d61f54350e0df5c7d1da741a [file] [log] [blame]
/*
* Copyright (c) 2001, 2008, 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.
*/
#include "awt.h"
#include "awt_Palette.h"
#include "awt_Component.h"
#include "img_util_md.h"
#include "awt_CustomPaletteDef.h"
#include "Trace.h"
BOOL AwtPalette::m_useCustomPalette = TRUE;
#define ERROR_GRAY (-1)
#define NON_GRAY 0
#define LINEAR_STATIC_GRAY 1
#define NON_LINEAR_STATIC_GRAY 2
/**
* Select the palette into the given HDC. This will
* allow operations using this HDC to access the palette
* colors/indices.
*/
HPALETTE AwtPalette::Select(HDC hDC)
{
HPALETTE prevPalette = NULL;
if (logicalPalette) {
BOOL background = !(m_useCustomPalette);
prevPalette = ::SelectPalette(hDC, logicalPalette, background);
}
return prevPalette;
}
/**
* Realize the palette of the given HDC. This will attempt to
* install the palette of the HDC onto the device associated with
* that HDC.
*/
void AwtPalette::Realize(HDC hDC)
{
if (logicalPalette) {
if (!m_useCustomPalette ||
AwtComponent::QueryNewPaletteCalled() ||
AwtToolkit::GetInstance().HasDisplayChanged()) {
// Fix for bug 4178909, workaround for Windows bug. Shouldn't
// do a RealizePalette until the first QueryNewPalette message
// has been processed.
// But if we are switching the primary monitor from non-8bpp
// to 8bpp mode, we may not get any palette messages during
// the display change event. Go ahead and realize the palette
// now anyway in this situation. This was especially noticeable
// on win2k in multimon. Note that there still seems to be some
// problem with actually setting the palette on the primary
// screen until after QNP is called, but at least the
// secondary devices can correctly realize the palette.
::RealizePalette(hDC);
}
}
}
/**
* Disable the use of our custom palette. This method is called
* during initialization if we detect that we are running inside
* the plugin; we do not want to clobber our parent application's
* palette with our own in that situation.
*/
void AwtPalette::DisableCustomPalette()
{
m_useCustomPalette = FALSE;
}
/**
* Returns whether we are currently using a custom palette. Used
* by AwtWin32GraphicsDevice when creating the colorModel of the
* device.
*/
BOOL AwtPalette::UseCustomPalette()
{
return m_useCustomPalette;
}
/**
* Constructor. Initialize the system and logical palettes.
* used by this object.
*/
AwtPalette::AwtPalette(AwtWin32GraphicsDevice *device)
{
this->device = device;
Update();
UpdateLogical();
}
/**
* Retrieves system palette entries. Includes a workaround for for some
* video drivers which may not support the GSPE call but may return
* valid values from this procedure.
*/
int AwtPalette::FetchPaletteEntries(HDC hDC, PALETTEENTRY* pPalEntries)
{
LOGPALETTE* pLogPal = 0;
HPALETTE hPal = 0;
HPALETTE hPalOld = 0;
int numEntries;
numEntries = ::GetSystemPaletteEntries(hDC, 0, 256, pPalEntries);
if (numEntries > 0) {
return numEntries;
}
// Workaround: some drivers do not support GetSysPalEntries
pLogPal = (LOGPALETTE*) new char[sizeof(LOGPALETTE)
+ 256*sizeof(PALETTEENTRY)];
if (pLogPal == NULL) {
return 0;
}
pLogPal->palVersion = 0x300;
pLogPal->palNumEntries = 256;
int iEntry;
PALETTEENTRY* pEntry;
for (iEntry = 0; iEntry < 256; iEntry++) {
pEntry = pLogPal->palPalEntry + iEntry;
pEntry->peRed = iEntry;
pEntry->peGreen = pEntry->peBlue = 0;
pEntry->peFlags = PC_EXPLICIT;
}
hPal = ::CreatePalette(pLogPal);
delete pLogPal;
if ( hPal == 0 ) {
return 0;
}
hPalOld = ::SelectPalette(hDC, hPal, 1);
if (hPalOld == 0) {
::DeleteObject(hPal);
return 0;
}
::RealizePalette(hDC);
COLORREF rgb;
for (iEntry = 0; iEntry < 256; iEntry++) {
rgb = ::GetNearestColor(hDC, PALETTEINDEX(iEntry));
pPalEntries[iEntry].peRed = GetRValue(rgb);
pPalEntries[iEntry].peGreen = GetGValue(rgb);
pPalEntries[iEntry].peBlue = GetBValue(rgb);
}
::SelectPalette(hDC, hPalOld, 0 );
::DeleteObject(hPal);
::RealizePalette(hDC);
return 256;
}
int AwtPalette::GetGSType(PALETTEENTRY* pPalEntries)
{
int isGray = 1;
int isLinearStaticGray = 1;
int isNonLinearStaticGray = 1;
int iEntry;
char bUsed[256];
BYTE r, g, b;
memset(bUsed, 0, sizeof(bUsed));
for (iEntry = 0; iEntry < 256; iEntry++) {
r = pPalEntries[iEntry].peRed;
g = pPalEntries[iEntry].peGreen;
b = pPalEntries[iEntry].peBlue;
if (r != g || r != b) {
isGray = 0;
break;
} else {
// the values are gray
if (r != iEntry) {
// it's not linear
// but it could be non-linear static gray
isLinearStaticGray = 0;
}
bUsed[r] = 1;
}
}
if (isGray && !isLinearStaticGray) {
// check if all 256 grays are there
// if that's the case, it's non-linear static gray
for (iEntry = 0; iEntry < 256; iEntry++ ) {
if (!bUsed[iEntry]) {
// not non-linear (not all 256 colors are used)
isNonLinearStaticGray = 0;
break;
}
}
}
if (!isGray) {
J2dTraceLn(J2D_TRACE_INFO,
"Detected palette: NON_GRAY/USER-MODIFIABLE");
return NON_GRAY;
}
if (isLinearStaticGray) {
J2dTraceLn(J2D_TRACE_INFO,
"Detected palette: LINEAR_STATIC_GRAY");
return LINEAR_STATIC_GRAY;
}
if (isNonLinearStaticGray) {
J2dTraceLn(J2D_TRACE_INFO,
"Detected palette: NON_LINEAR_STATIC_GRAY");
return NON_LINEAR_STATIC_GRAY;
}
J2dTraceLn(J2D_TRACE_ERROR,
"Unable to detect palette type, non-gray is assumed");
// not supposed to be here, error
return ERROR_GRAY;
}
/**
* Updates our system palette variables to make sure they match
* the current state of the actual system palette. This method
* is called during AwtPalette creation and after palette changes.
* Return whether there were any palette changes from the previous
* system palette.
*/
BOOL AwtPalette::Update()
{
PALETTEENTRY pe[256];
int numEntries = 0;
int bitsPerPixel;
int i;
HDC hDC;
hDC = device->GetDC();
if (!hDC) {
return FALSE;
}
bitsPerPixel = ::GetDeviceCaps(hDC, BITSPIXEL);
device->ReleaseDC(hDC);
if (8 != bitsPerPixel) {
return FALSE;
}
hDC = device->GetDC();
numEntries = FetchPaletteEntries(hDC, pe);
device->ReleaseDC(hDC);
if ((numEntries == numSystemEntries) &&
(0 == memcmp(pe, systemEntriesWin32, numEntries * sizeof(PALETTEENTRY))))
{
return FALSE;
}
// make this system palette the new cached win32 palette
numEntries = (numEntries > 256)? 256: numEntries;
memcpy(systemEntriesWin32, pe, numEntries * sizeof(PALETTEENTRY));
numSystemEntries = numEntries;
// Create jdk-style system palette
int startIndex = 0, endIndex = numEntries-1;
int staticGrayType = GetGSType(systemEntriesWin32);
if (staticGrayType == LINEAR_STATIC_GRAY) {
device->SetGrayness(GS_STATICGRAY);
} else if (staticGrayType == NON_LINEAR_STATIC_GRAY) {
device->SetGrayness(GS_NONLINGRAY);
} else if (getenv("FORCEGRAY")) {
J2dTraceLn(J2D_TRACE_INFO,
"Gray Palette Forced via FORCEGRAY");
// Need to zero first and last ten
// palette entries. Otherwise in UpdateDynamicColorModel
// we could set non-gray values to the palette.
for (i = 0; i < 10; i++) {
systemEntries[i] = 0x00000000;
systemEntries[i+246] = 0x00000000;
}
numEntries -= 20;
startIndex = 10;
endIndex -= 10;
device->SetGrayness(GS_INDEXGRAY);
} else {
device->SetGrayness(GS_NOTGRAY);
}
for (i = startIndex; i <= endIndex; i++) {
systemEntries[i] = 0xff000000
| (pe[i].peRed << 16)
| (pe[i].peGreen << 8)
| (pe[i].peBlue);
}
systemInverseLUT =
initCubemap((int *)systemEntries, numEntries, 32);
ColorData *cData = device->GetColorData();
if ((device->GetGrayness() == GS_NONLINGRAY ||
device->GetGrayness() == GS_INDEXGRAY) &&
cData != NULL) {
if (cData->pGrayInverseLutData != NULL) {
free(cData->pGrayInverseLutData);
cData->pGrayInverseLutData = NULL;
}
initInverseGrayLut((int*)systemEntries, 256, device->GetColorData());
}
return TRUE;
}
/**
* Creates our custom palette based on: the current system palette,
* the grayscale-ness of the system palette, and the state of the
* primary device.
*/
void AwtPalette::UpdateLogical()
{
// Create and initialize a palette
int nEntries = 256;
char *buf = NULL;
buf = new char[sizeof(LOGPALETTE) + nEntries *
sizeof(PALETTEENTRY)];
LOGPALETTE *pLogPal = (LOGPALETTE*)buf;
PALETTEENTRY *pPalEntries = (PALETTEENTRY *)(&(pLogPal->palPalEntry[0]));
memcpy(pPalEntries, systemEntriesWin32, 256 * sizeof(PALETTEENTRY));
PALETTEENTRY *pPal = pPalEntries;
int i;
int staticGrayType = device->GetGrayness();
if (staticGrayType == GS_INDEXGRAY) {
float m = 255.0f / 235.0f;
float g = 0.5f;
pPal = &pPalEntries[10];
for (i = 10; i < 246; i++, pPal++) {
pPal->peRed = pPal->peGreen = pPal->peBlue =
(int)g;
g += m;
pPal->peFlags = PC_NOCOLLAPSE;
}
} else if (staticGrayType == GS_NOTGRAY) {
for (i = 10; i < 246; i++) {
pPalEntries[i] = customPalette[i-10];
}
}
pLogPal->palNumEntries = 256;
pLogPal->palVersion = 0x300;
logicalPalette = ::CreatePalette(pLogPal);
for (i = 0; i < nEntries; i++) {
logicalEntries[i] = 0xff000000
| (pPalEntries[i].peRed << 16)
| (pPalEntries[i].peGreen << 8)
| (pPalEntries[i].peBlue);
}
delete [] buf;
}