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