1 /*
2 * Copyright (c) 2001, 2017, 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
33 BOOL 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 */
Select(HDC hDC)45 HPALETTE 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 */
Realize(HDC hDC)60 void 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 */
DisableCustomPalette()88 void 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 */
UseCustomPalette()98 BOOL 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 */
AwtPalette(AwtWin32GraphicsDevice * device)108 AwtPalette::AwtPalette(AwtWin32GraphicsDevice *device)
109 {
110 this->device = device;
111 Update();
112 UpdateLogical();
113 }
114
115 /**
116 * Retrieves system palette entries. Includes a workaround for for some
117 * video drivers which may not support the GSPE call but may return
118 * valid values from this procedure.
119 */
FetchPaletteEntries(HDC hDC,PALETTEENTRY * pPalEntries)120 int 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
GetGSType(PALETTEENTRY * pPalEntries)178 int 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 */
Update()247 BOOL 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 */
UpdateLogical()338 void 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