/* * Copyright (c) 1996, 2015, Oracle and/or its affiliates. All rights reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include #include #include #include #include #include #include #include "Xcmsint.h" #include "Cv.h" #define XSOLARIS_STD_GAMMA 2.22 #define MAX_SAMPLES 16 /* ** The following three routines are derived from code in bin/xcmsdb/xcmsdb.c. */ static int QueryTableType0 (unsigned int maxcolor, int format, char **pChar, unsigned long *pCount, unsigned int *nelem, unsigned short **pph, unsigned int **ppf) { unsigned int nElements; unsigned short *ph = NULL; unsigned int *pf = NULL; nElements = _XcmsGetElement(format, pChar, pCount) + 1; *nelem = nElements; if (!(ph = (unsigned short *) malloc(nElements * sizeof(unsigned short))) || !(pf = (unsigned int *) malloc(nElements * sizeof(unsigned int)))) { goto Bad; } *ppf = pf; *pph = ph; switch (format) { case 8: while (nElements--) { /* 0xFFFF/0xFF = 0x101 */ *ph++ = _XcmsGetElement (format, pChar, pCount) * 0x101; *pf++ = (_XcmsGetElement (format, pChar, pCount) / (XcmsFloat)255.0) * maxcolor; } break; case 16: while (nElements--) { *ph++ = (unsigned short)_XcmsGetElement (format, pChar, pCount); *pf++ = (_XcmsGetElement (format, pChar, pCount) / (XcmsFloat)65535.0) * maxcolor; } break; case 32: while (nElements--) { *ph++ = (unsigned short)_XcmsGetElement (format, pChar, pCount); *pf++ = (_XcmsGetElement (format, pChar, pCount) / (XcmsFloat)4294967295.0) * maxcolor; } break; default: goto Bad; } return (1); Bad: if (ph) { free(ph); } if (pf) { free(pf); } *pph = NULL; *ppf = NULL; return (0); } static int QueryTableType1 (unsigned int maxcolor, int format, char **pChar, unsigned long *pCount, unsigned int *nelem, unsigned short **pph, unsigned int **ppf) { int count; unsigned int max_index; unsigned int nElements; unsigned short *ph = NULL; unsigned int *pf = NULL; max_index = _XcmsGetElement(format, pChar, pCount); nElements = max_index + 1; *nelem = nElements; if (!(ph = (unsigned short *) malloc(nElements * sizeof(unsigned short))) || !(pf = (unsigned int *) malloc(nElements * sizeof(unsigned int)))) { goto Bad; } *ppf = pf; *pph = ph; switch (format) { case 8: for (count = 0; count < nElements; count++) { *ph++ = count; *pf++ = ((XcmsFloat) _XcmsGetElement(format, pChar, pCount) / (XcmsFloat)255.0) * (XcmsFloat)maxcolor; } break; case 16: for (count = 0; count < nElements; count++) { *ph++ = count; *pf++ = ((XcmsFloat) _XcmsGetElement(format, pChar, pCount) / (XcmsFloat)65535.0) * (XcmsFloat)maxcolor; } break; case 32: for (count = 0; count < nElements; count++) { *ph++ = count; *pf++ = ((XcmsFloat) _XcmsGetElement (format, pChar, pCount) / (XcmsFloat)4294967295.0) * (XcmsFloat)maxcolor; } break; default: goto Bad; } return (1); Bad: if (ph) { free(ph); } if (pf) { free(pf); } *pph = NULL; *ppf = NULL; return (0); } /* ** If the given n pairs (hi, fi) approximate a power function with the ** relation h = f**exp, the exponent exp is returned. */ static double exponentOfPowerFunc (unsigned int maxh, unsigned int maxf, int n, unsigned short *ph, unsigned int *pf) { unsigned short h; unsigned int f; double logh, logf; int i, nsamples, incr; double sum, logmaxh, logmaxf, denom; incr = n / MAX_SAMPLES; if (incr < 1) { incr = 1; } logmaxh = log((double)maxh); logmaxf = log((double)maxf); sum = 0; nsamples = 0; for (i = (incr>>1); i < n; i += incr) { h = ph[i]; f = pf[i]; if (h == 0 || f == 0) { continue; } logh = log((double) h); logf = log((double) f); denom = logh - logmaxh; if (denom) { sum += (logf - logmaxf) / denom; nsamples++; } } if (nsamples == 0) { /* Note: as good as anything else */ return(XSOLARIS_STD_GAMMA); } else { return(sum/nsamples); } } /* ** Updates the current prop element pointer to point beyond the current channel. ** Upon entry, pChar should point to the length element of the channel. ** ** Returns 0 if the property contents are invalid, 1 otherwise. */ static int skipChannel (int cType, int format, char **pChar, unsigned long *pCount) { unsigned int nElements, length; if ((long)*pCount <= 0) { return (0); } length = _XcmsGetElement(format, pChar, pCount) + 1; nElements = ((cType == 0) ? 2 : 1) * length; if ((long)nElements > *pCount) { return (0); } while (nElements--) { (void) _XcmsGetElement (format, pChar, pCount); } return (1); } /* ** Updates the current prop element pointer to point beyond the current visual. ** Upon entry, pChar should point to the type element immediately following ** the visualID elemnt. ** ** Returns 0 if the property contents are invalid, 1 otherwise. */ static int skipVisual (int format, char **pChar, unsigned long *pCount) { int cType, nTables; /* Get table type */ if ((long)*pCount <= 0) { return (0); } cType = (int)_XcmsGetElement(format, pChar, pCount); if (cType != 0 && cType != 1) { return (0); } /* Get number of channels */ if ((long)*pCount <= 0) { return (0); } nTables = (int)_XcmsGetElement(format, pChar, pCount); if (nTables != 1 && nTables != 3) { return (0); } /* Skip red channel */ if (!skipChannel(cType, format, pChar, pCount)) { return (0); } if (nTables > 1) { /* Skip green channel */ if (!skipChannel(cType, format, pChar, pCount)) { return (0); } /* Skip blue channel */ if (!skipChannel(cType, format, pChar, pCount)) { return (0); } } return (1); } static int XSolarisGetVisualGammaCalledFlag = 0; int XSolarisGetVisualGammaCalled (void) { return (XSolarisGetVisualGammaCalledFlag); } /* ** Note: this function ignores the green and blue intensity correction ** data; it assumes that these are the same as the red channel. */ Status XSolarisGetVisualGamma (Display *dpy, int screen_number, Visual *visual, double *gamma) { char *property_return = NULL, *pChar; int count, format, cType, nTables; unsigned long nitems = 0; unsigned long nbytes_return; Atom CorrectAtom; VisualID visualID; unsigned int maxcolor, nelem; unsigned short *ph; unsigned int *pf; XSolarisGetVisualGammaCalledFlag = 1; /* * Get Intensity Tables */ CorrectAtom = XInternAtom (dpy, XDCCC_CORRECT_ATOM_NAME, False); if (CorrectAtom != None) { if (_XcmsGetProperty (dpy, XRootWindow(dpy, screen_number), CorrectAtom, &format, &nitems, &nbytes_return, &property_return) == XcmsFailure) { *gamma = XSOLARIS_STD_GAMMA; return (Success); } else if ((long)nitems <= 0) { /* use standard gamma */ if (property_return) { XFree (property_return); } *gamma = XSOLARIS_STD_GAMMA; return (Success); } } pChar = property_return; /* Note: nitems is decremented as a side-effect of calling getElement */ while (nitems) { switch (format) { case 8: /* * Must have at least: * VisualID0 * VisualID1 * VisualID2 * VisualID3 * type * count * length * intensity1 * intensity2 */ if (nitems < 9) { XFree (property_return); return (BadMatch); } count = 3; break; case 16: /* * Must have at least: * VisualID0 * VisualID3 * type * count * length * intensity1 * intensity2 */ if (nitems < 7) { XFree (property_return); return (BadMatch); } count = 1; break; case 32: /* * Must have at least: * VisualID0 * type * count * length * intensity1 * intensity2 */ if (nitems < 6) { XFree (property_return); return (BadMatch); } count = 0; break; default: XFree (property_return); return (BadMatch); } /* Get VisualID */ visualID = _XcmsGetElement(format, &pChar, &nitems); while (count--) { visualID = visualID << format; visualID |= _XcmsGetElement(format, &pChar, &nitems); } if (visual->visualid != visualID) { if (!skipVisual(format, &pChar, &nitems)) { XFree (property_return); return (BadMatch); } continue; } /* Found the visual */ maxcolor = 0xffff; /* Get table type and number of channels */ cType = (int)_XcmsGetElement(format, &pChar, &nitems); nTables = (int)_XcmsGetElement(format, &pChar, &nitems); /* ** Note: it is assumed that the per-channel maps in the table all have ** the same length. This is a safe bet for most hardware, as it depends ** not on the visual masks but on the visual bits_per_rgb. Thus, we ** extract the information from the red channel map and ignore the rest. */ switch (cType) { case 0: if (!QueryTableType0(maxcolor, format, &pChar, &nitems, &nelem, &ph, &pf)) { XFree (property_return); return (BadMatch); } if (nelem == 2 && *ph == 0 && *pf == 0 && *(ph+1) == maxcolor && *(pf+1) == maxcolor) { /* exactly linear */ *gamma = 1.0; } else { *gamma = exponentOfPowerFunc(maxcolor, maxcolor, (int)nelem, ph, pf); } break; case 1: if (!QueryTableType1(maxcolor, format, &pChar, &nitems, &nelem, &ph, &pf)) { XFree (property_return); return (BadMatch); } *gamma = exponentOfPowerFunc((1<bits_per_rgb)-1, maxcolor, (int)nelem, ph, pf); break; default: XFree (property_return); return (BadMatch); } XFree (property_return); /* These were allocated in the QueryTableType routines and must be freed now */ if (ph) { free(ph); } if (pf) { free(pf); } return (Success); } /* bug fix for 4248958: OPENGL program shows mem leak in libdga*/ if(property_return) XFree (property_return); *gamma = XSOLARIS_STD_GAMMA; return (Success); }