2 // Copyright (C) 2008 Mozilla Foundation
4 // Permission is hereby granted, free of charge, to any person obtaining
5 // a copy of this software and associated documentation files (the "Software"),
6 // to deal in the Software without restriction, including without limitation
7 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 // and/or sell copies of the Software, and to permit persons to whom the Software
9 // is furnished to do so, subject to the following conditions:
11 // The above copyright notice and this permission notice shall be included in
12 // all copies or substantial portions of the Software.
14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
16 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 * Helper Macro for allocating precache tables and freeing them
27 * appropriately. We need a macro here so we can select the appropriate member
30 #define cmsAllocPrecacheTables(aProf, cacheType, unionMemb, nTables, elemSize, nElems) \
33 for (i = 0; i < nTables; ++i) { \
34 aProf->Precache[cacheType]->Impl.unionMemb.Cache[i] = \
35 _cmsMalloc(elemSize * nElems); \
36 if (aProf->Precache[cacheType]->Impl.unionMemb.Cache[i] == NULL) { \
37 for (j = 0; j < i; ++j) \
38 _cmsFree(aProf->Precache[cacheType]->Impl.unionMemb.Cache[j]); \
39 _cmsFree(aProf->Precache[cacheType]); \
40 aProf->Precache[cacheType] = NULL; \
47 * Precaches the results specified in Type in a reference-counted table.
49 * Returns true if the precache succeeded (or if the information was already
50 * precached), false otherwise (including cases where the profile was not
53 LCMSBOOL LCMSEXPORT
cmsPrecacheProfile(cmsHPROFILE hProfile
,
54 LCMSPRECACHETYPE Type
) {
57 LPGAMMATABLE GTables
[3];
58 LCMSBOOL hasGammaTables
;
59 LPLCMSICCPROFILE Icc
= (LPLCMSICCPROFILE
) (LPSTR
) hProfile
;
64 CMSASSERT(Type
< PRECACHE_TYPE_COUNT
);
66 /* Do we already have what we need? */
67 if (Icc
->Precache
[Type
] != NULL
)
70 /* Determine if we have gamma tables in the profile. */
71 hasGammaTables
= cmsIsTag(hProfile
, icSigRedTRCTag
) &&
72 cmsIsTag(hProfile
, icSigGreenTRCTag
) &&
73 cmsIsTag(hProfile
, icSigBlueTRCTag
);
75 /* Zero Out the Gamma Table Pointers. */
76 ZeroMemory(GTables
, sizeof(GTables
));
78 // Create and zero a precache structure
79 Icc
->Precache
[Type
] = _cmsMalloc(sizeof(LCMSPRECACHE
));
80 if (Icc
->Precache
[Type
] == NULL
)
82 ZeroMemory(Icc
->Precache
[Type
], sizeof(LCMSPRECACHE
));
84 // Grab a Reference to the precache
85 PRECACHE_ADDREF(Icc
->Precache
[Type
]);
87 // Tag the precache with its type (necessary for freeing)
88 Icc
->Precache
[Type
]->Type
= Type
;
90 // Read the Gamma Tables if we need then
91 if (IS_LI_REVERSE(Type
)) {
93 // Read in the reversed Gamma curves
95 GTables
[0] = cmsReadICCGammaReversed(hProfile
, icSigRedTRCTag
);
96 GTables
[1] = cmsReadICCGammaReversed(hProfile
, icSigGreenTRCTag
);
97 GTables
[2] = cmsReadICCGammaReversed(hProfile
, icSigBlueTRCTag
);
101 if (!GTables
[0] || !GTables
[1] || !GTables
[2]) {
102 _cmsFree(Icc
->Precache
[Type
]);
103 Icc
->Precache
[Type
] = NULL
;
107 else if (IS_LI_FORWARD(Type
)) {
109 // Read in the Gamma curves
110 if (hasGammaTables
) {
111 GTables
[0] = cmsReadICCGamma(hProfile
, icSigRedTRCTag
);
112 GTables
[1] = cmsReadICCGamma(hProfile
, icSigGreenTRCTag
);
113 GTables
[2] = cmsReadICCGamma(hProfile
, icSigBlueTRCTag
);
117 if (!GTables
[0] || !GTables
[1] || !GTables
[2]) {
118 _cmsFree(Icc
->Precache
[Type
]);
119 Icc
->Precache
[Type
] = NULL
;
124 // Type-Specific Precache Operations
127 case CMS_PRECACHE_LI1616_REVERSE
:
129 // Allocate the precache tables
130 cmsAllocPrecacheTables(Icc
, Type
, LI1616_REVERSE
, 3, sizeof(WORD
), (1 << 16));
132 // Calculate the interpolation parameters
133 cmsCalcL16Params(GTables
[0]->nEntries
, &p16
);
136 for (i
= 0; i
< 3; ++i
)
137 for (j
= 0; j
< (1 << 16); ++j
)
138 Icc
->Precache
[Type
]->Impl
.LI1616_REVERSE
.Cache
[i
][j
] =
139 cmsLinearInterpLUT16((WORD
)j
, GTables
[i
]->GammaTable
, &p16
);
142 case CMS_PRECACHE_LI168_REVERSE
:
144 // Allocate the precache tables
145 cmsAllocPrecacheTables(Icc
, Type
, LI168_REVERSE
, 3, sizeof(BYTE
), (1 << 16));
147 // Calculate the interpolation parameters
148 cmsCalcL16Params(GTables
[0]->nEntries
, &p16
);
151 for (i
= 0; i
< 3; ++i
)
152 for (j
= 0; j
< (1 << 16); ++j
)
153 Icc
->Precache
[Type
]->Impl
.LI168_REVERSE
.Cache
[i
][j
] =
154 RGB_16_TO_8(cmsLinearInterpLUT16((WORD
)j
, GTables
[i
]->GammaTable
, &p16
));
157 case CMS_PRECACHE_LI16W_FORWARD
:
159 // Allocate the precache tables
160 cmsAllocPrecacheTables(Icc
, Type
, LI16W_FORWARD
, 3, sizeof(Fixed32
), (1 << 16));
162 // Calculate the interpolation parameters
163 cmsCalcL16Params(GTables
[0]->nEntries
, &p16
);
166 for (i
= 0; i
< 3; ++i
)
167 for (j
= 0; j
< (1 << 16); ++j
)
168 Icc
->Precache
[Type
]->Impl
.LI16W_FORWARD
.Cache
[i
][j
] =
169 cmsLinearInterpFixed((WORD
)j
, GTables
[i
]->GammaTable
, &p16
);
172 case CMS_PRECACHE_LI8F_FORWARD
:
174 // Allocate the precache tables
175 cmsAllocPrecacheTables(Icc
, Type
, LI8F_FORWARD
, 3, sizeof(FLOAT
), 256);
177 // Calculate the interpolation parameters
178 cmsCalcL16Params(GTables
[0]->nEntries
, &p16
);
181 for (i
= 0; i
< 3; ++i
)
182 for (j
= 0; j
< 256; ++j
)
183 Icc
->Precache
[Type
]->Impl
.LI8F_FORWARD
.Cache
[i
][j
] =
184 ToFloatDomain(cmsLinearInterpLUT16(RGB_8_TO_16(((BYTE
)j
)), GTables
[i
]->GammaTable
, &p16
));
188 // TODO: change non-critical asserts to CMS warnings
189 CMSASSERT(0); // Not implemented
193 // Free the gamma tables
194 if (hasGammaTables
) {
195 CMSASSERT(GTables
[0] != NULL
);
196 cmsFreeGammaTriple(GTables
);
204 * Frees a Precache structure.
206 * This function is invoked by the refcounting mechanism when the refcount on
207 * the precache object drops to zero. If should never be invoked manually.
209 void cmsPrecacheFree(LPLCMSPRECACHE Cache
) {
214 // Validate Input/State
215 CMSASSERT(Cache
!= NULL
);
216 CMSASSERT(Cache
->RefCount
== 0);
218 // Type-Specific behavior
219 switch(Cache
->Type
) {
221 case CMS_PRECACHE_LI1616_REVERSE
:
222 for (i
= 0; i
< 3; ++i
)
223 _cmsFree(Cache
->Impl
.LI1616_REVERSE
.Cache
[i
]);
226 case CMS_PRECACHE_LI168_REVERSE
:
227 for (i
= 0; i
< 3; ++i
)
228 _cmsFree(Cache
->Impl
.LI168_REVERSE
.Cache
[i
]);
231 case CMS_PRECACHE_LI16W_FORWARD
:
232 for (i
= 0; i
< 3; ++i
)
233 _cmsFree(Cache
->Impl
.LI16W_FORWARD
.Cache
[i
]);
236 case CMS_PRECACHE_LI8F_FORWARD
:
237 for (i
= 0; i
< 3; ++i
)
238 _cmsFree(Cache
->Impl
.LI8F_FORWARD
.Cache
[i
]);
242 // TODO: proper warning
243 CMSASSERT(0); // Bad Type
247 // Free the structure itself