1/* 2 * Copyright (c) 2001, 2008, 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#include "awt.h" 27#include "awt_Palette.h" 28#include "awt_Component.h" 29#include "img_util_md.h" 30#include "awt_CustomPaletteDef.h" 31#include "Trace.h" 32 33BOOL AwtPalette::m_useCustomPalette = TRUE; 34 35#define ERROR_GRAY (-1) 36#define NON_GRAY 0 37#define LINEAR_STATIC_GRAY 1 38#define NON_LINEAR_STATIC_GRAY 2 39 40/** 41 * Select the palette into the given HDC. This will 42 * allow operations using this HDC to access the palette 43 * colors/indices. 44 */ 45HPALETTE AwtPalette::Select(HDC hDC) 46{ 47 HPALETTE prevPalette = NULL; 48 if (logicalPalette) { 49 BOOL background = !(m_useCustomPalette); 50 prevPalette = ::SelectPalette(hDC, logicalPalette, background); 51 } 52 return prevPalette; 53} 54 55/** 56 * Realize the palette of the given HDC. This will attempt to 57 * install the palette of the HDC onto the device associated with 58 * that HDC. 59 */ 60void AwtPalette::Realize(HDC hDC) 61{ 62 if (logicalPalette) { 63 if (!m_useCustomPalette || 64 AwtComponent::QueryNewPaletteCalled() || 65 AwtToolkit::GetInstance().HasDisplayChanged()) { 66 // Fix for bug 4178909, workaround for Windows bug. Shouldn't 67 // do a RealizePalette until the first QueryNewPalette message 68 // has been processed. 69 // But if we are switching the primary monitor from non-8bpp 70 // to 8bpp mode, we may not get any palette messages during 71 // the display change event. Go ahead and realize the palette 72 // now anyway in this situation. This was especially noticeable 73 // on win2k in multimon. Note that there still seems to be some 74 // problem with actually setting the palette on the primary 75 // screen until after QNP is called, but at least the 76 // secondary devices can correctly realize the palette. 77 ::RealizePalette(hDC); 78 } 79 } 80} 81 82/** 83 * Disable the use of our custom palette. This method is called 84 * during initialization if we detect that we are running inside 85 * the plugin; we do not want to clobber our parent application's 86 * palette with our own in that situation. 87 */ 88void AwtPalette::DisableCustomPalette() 89{ 90 m_useCustomPalette = FALSE; 91} 92 93/** 94 * Returns whether we are currently using a custom palette. Used 95 * by AwtWin32GraphicsDevice when creating the colorModel of the 96 * device. 97 */ 98BOOL AwtPalette::UseCustomPalette() 99{ 100 return m_useCustomPalette; 101} 102 103 104/** 105 * Constructor. Initialize the system and logical palettes. 106 * used by this object. 107 */ 108AwtPalette::AwtPalette(AwtWin32GraphicsDevice *device) 109{ 110 this->device = device; 111 Update(); 112 UpdateLogical(); 113} 114 115/** 116 * Retrieves system palette entries. Includes a workaround for some 117 * video drivers which may not support the GSPE call but may return 118 * valid values from this procedure. 119 */ 120int AwtPalette::FetchPaletteEntries(HDC hDC, PALETTEENTRY* pPalEntries) 121{ 122 LOGPALETTE* pLogPal = 0; 123 HPALETTE hPal = 0; 124 HPALETTE hPalOld = 0; 125 int numEntries; 126 127 numEntries = ::GetSystemPaletteEntries(hDC, 0, 256, pPalEntries); 128 129 if (numEntries > 0) { 130 return numEntries; 131 } 132 // Workaround: some drivers do not support GetSysPalEntries 133 134 pLogPal = (LOGPALETTE*) new char[sizeof(LOGPALETTE) 135 + 256*sizeof(PALETTEENTRY)]; 136 if (pLogPal == NULL) { 137 return 0; 138 } 139 140 pLogPal->palVersion = 0x300; 141 pLogPal->palNumEntries = 256; 142 int iEntry; 143 PALETTEENTRY* pEntry; 144 for (iEntry = 0; iEntry < 256; iEntry++) { 145 pEntry = pLogPal->palPalEntry + iEntry; 146 pEntry->peRed = iEntry; 147 pEntry->peGreen = pEntry->peBlue = 0; 148 pEntry->peFlags = PC_EXPLICIT; 149 } 150 hPal = ::CreatePalette(pLogPal); 151 delete pLogPal; 152 if ( hPal == 0 ) { 153 return 0; 154 } 155 156 hPalOld = ::SelectPalette(hDC, hPal, 1); 157 if (hPalOld == 0) { 158 ::DeleteObject(hPal); 159 return 0; 160 } 161 ::RealizePalette(hDC); 162 163 COLORREF rgb; 164 for (iEntry = 0; iEntry < 256; iEntry++) { 165 rgb = ::GetNearestColor(hDC, PALETTEINDEX(iEntry)); 166 pPalEntries[iEntry].peRed = GetRValue(rgb); 167 pPalEntries[iEntry].peGreen = GetGValue(rgb); 168 pPalEntries[iEntry].peBlue = GetBValue(rgb); 169 } 170 171 ::SelectPalette(hDC, hPalOld, 0 ); 172 ::DeleteObject(hPal); 173 ::RealizePalette(hDC); 174 175 return 256; 176} 177 178int AwtPalette::GetGSType(PALETTEENTRY* pPalEntries) 179{ 180 int isGray = 1; 181 int isLinearStaticGray = 1; 182 int isNonLinearStaticGray = 1; 183 int iEntry; 184 char bUsed[256]; 185 BYTE r, g, b; 186 187 memset(bUsed, 0, sizeof(bUsed)); 188 for (iEntry = 0; iEntry < 256; iEntry++) { 189 r = pPalEntries[iEntry].peRed; 190 g = pPalEntries[iEntry].peGreen; 191 b = pPalEntries[iEntry].peBlue; 192 if (r != g || r != b) { 193 isGray = 0; 194 break; 195 } else { 196 // the values are gray 197 if (r != iEntry) { 198 // it's not linear 199 // but it could be non-linear static gray 200 isLinearStaticGray = 0; 201 } 202 bUsed[r] = 1; 203 } 204 } 205 206 if (isGray && !isLinearStaticGray) { 207 // check if all 256 grays are there 208 // if that's the case, it's non-linear static gray 209 for (iEntry = 0; iEntry < 256; iEntry++ ) { 210 if (!bUsed[iEntry]) { 211 // not non-linear (not all 256 colors are used) 212 isNonLinearStaticGray = 0; 213 break; 214 } 215 } 216 } 217 218 if (!isGray) { 219 J2dTraceLn(J2D_TRACE_INFO, 220 "Detected palette: NON_GRAY/USER-MODIFIABLE"); 221 return NON_GRAY; 222 } 223 if (isLinearStaticGray) { 224 J2dTraceLn(J2D_TRACE_INFO, 225 "Detected palette: LINEAR_STATIC_GRAY"); 226 return LINEAR_STATIC_GRAY; 227 } 228 if (isNonLinearStaticGray) { 229 J2dTraceLn(J2D_TRACE_INFO, 230 "Detected palette: NON_LINEAR_STATIC_GRAY"); 231 return NON_LINEAR_STATIC_GRAY; 232 } 233 234 J2dTraceLn(J2D_TRACE_ERROR, 235 "Unable to detect palette type, non-gray is assumed"); 236 // not supposed to be here, error 237 return ERROR_GRAY; 238} 239 240/** 241 * Updates our system palette variables to make sure they match 242 * the current state of the actual system palette. This method 243 * is called during AwtPalette creation and after palette changes. 244 * Return whether there were any palette changes from the previous 245 * system palette. 246 */ 247BOOL AwtPalette::Update() 248{ 249 PALETTEENTRY pe[256]; 250 int numEntries = 0; 251 int bitsPerPixel; 252 int i; 253 HDC hDC; 254 255 hDC = device->GetDC(); 256 if (!hDC) { 257 return FALSE; 258 } 259 bitsPerPixel = ::GetDeviceCaps(hDC, BITSPIXEL); 260 device->ReleaseDC(hDC); 261 if (8 != bitsPerPixel) { 262 return FALSE; 263 } 264 265 hDC = device->GetDC(); 266 numEntries = FetchPaletteEntries(hDC, pe); 267 268 device->ReleaseDC(hDC); 269 270 if ((numEntries == numSystemEntries) && 271 (0 == memcmp(pe, systemEntriesWin32, numEntries * sizeof(PALETTEENTRY)))) 272 { 273 return FALSE; 274 } 275 276 // make this system palette the new cached win32 palette 277 numEntries = (numEntries > 256)? 256: numEntries; 278 memcpy(systemEntriesWin32, pe, numEntries * sizeof(PALETTEENTRY)); 279 numSystemEntries = numEntries; 280 281 // Create jdk-style system palette 282 int startIndex = 0, endIndex = numEntries-1; 283 int staticGrayType = GetGSType(systemEntriesWin32); 284 285 if (staticGrayType == LINEAR_STATIC_GRAY) { 286 device->SetGrayness(GS_STATICGRAY); 287 } else if (staticGrayType == NON_LINEAR_STATIC_GRAY) { 288 device->SetGrayness(GS_NONLINGRAY); 289 } else if (getenv("FORCEGRAY")) { 290 J2dTraceLn(J2D_TRACE_INFO, 291 "Gray Palette Forced via FORCEGRAY"); 292 // Need to zero first and last ten 293 // palette entries. Otherwise in UpdateDynamicColorModel 294 // we could set non-gray values to the palette. 295 for (i = 0; i < 10; i++) { 296 systemEntries[i] = 0x00000000; 297 systemEntries[i+246] = 0x00000000; 298 } 299 numEntries -= 20; 300 startIndex = 10; 301 endIndex -= 10; 302 device->SetGrayness(GS_INDEXGRAY); 303 } else { 304 device->SetGrayness(GS_NOTGRAY); 305 } 306 307 for (i = startIndex; i <= endIndex; i++) { 308 systemEntries[i] = 0xff000000 309 | (pe[i].peRed << 16) 310 | (pe[i].peGreen << 8) 311 | (pe[i].peBlue); 312 } 313 314 systemInverseLUT = 315 initCubemap((int *)systemEntries, numEntries, 32); 316 317 ColorData *cData = device->GetColorData(); 318 if ((device->GetGrayness() == GS_NONLINGRAY || 319 device->GetGrayness() == GS_INDEXGRAY) && 320 cData != NULL) { 321 322 if (cData->pGrayInverseLutData != NULL) { 323 free(cData->pGrayInverseLutData); 324 cData->pGrayInverseLutData = NULL; 325 } 326 initInverseGrayLut((int*)systemEntries, 256, device->GetColorData()); 327 } 328 329 return TRUE; 330} 331 332 333/** 334 * Creates our custom palette based on: the current system palette, 335 * the grayscale-ness of the system palette, and the state of the 336 * primary device. 337 */ 338void AwtPalette::UpdateLogical() 339{ 340 // Create and initialize a palette 341 int nEntries = 256; 342 char *buf = NULL; 343 buf = new char[sizeof(LOGPALETTE) + nEntries * 344 sizeof(PALETTEENTRY)]; 345 346 LOGPALETTE *pLogPal = (LOGPALETTE*)buf; 347 PALETTEENTRY *pPalEntries = (PALETTEENTRY *)(&(pLogPal->palPalEntry[0])); 348 349 memcpy(pPalEntries, systemEntriesWin32, 256 * sizeof(PALETTEENTRY)); 350 351 PALETTEENTRY *pPal = pPalEntries; 352 int i; 353 int staticGrayType = device->GetGrayness(); 354 if (staticGrayType == GS_INDEXGRAY) { 355 float m = 255.0f / 235.0f; 356 float g = 0.5f; 357 pPal = &pPalEntries[10]; 358 for (i = 10; i < 246; i++, pPal++) { 359 pPal->peRed = pPal->peGreen = pPal->peBlue = 360 (int)g; 361 g += m; 362 pPal->peFlags = PC_NOCOLLAPSE; 363 } 364 } else if (staticGrayType == GS_NOTGRAY) { 365 for (i = 10; i < 246; i++) { 366 pPalEntries[i] = customPalette[i-10]; 367 } 368 } 369 pLogPal->palNumEntries = 256; 370 pLogPal->palVersion = 0x300; 371 logicalPalette = ::CreatePalette(pLogPal); 372 373 for (i = 0; i < nEntries; i++) { 374 logicalEntries[i] = 0xff000000 375 | (pPalEntries[i].peRed << 16) 376 | (pPalEntries[i].peGreen << 8) 377 | (pPalEntries[i].peBlue); 378 } 379 delete [] buf; 380} 381