Upgrade to lcms 2.14.
- Remove already applied part of 0033-opt-integer-overflow.patch.
- Add 0034-dead-code.patch to delete some useless code.
Change-Id: If00ae157835c3f7e797274397674d4c154a82ff9
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/102174
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/third_party/lcms/0030-const-data.patch b/third_party/lcms/0030-const-data.patch
index 42a3b93..0c42dde 100644
--- a/third_party/lcms/0030-const-data.patch
+++ b/third_party/lcms/0030-const-data.patch
@@ -63,16 +63,3 @@
_cmsAssert(Params != NULL);
-diff --git a/third_party/lcms/src/cmshalf.c b/third_party/lcms/src/cmshalf.c
-index 292b6fdf9..52c0a2a22 100644
---- a/third_party/lcms/src/cmshalf.c
-+++ b/third_party/lcms/src/cmshalf.c
-@@ -377,7 +377,7 @@ static const cmsUInt32Number Mantissa[2048] = {
- 0x387fc000, 0x387fe000
- };
-
--static cmsUInt16Number Offset[64] = {
-+static const cmsUInt16Number Offset[64] = {
- 0x0000, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
- 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
- 0x0400, 0x0400, 0x0400, 0x0400, 0x0400, 0x0400,
diff --git a/third_party/lcms/0034-dead-code.patch b/third_party/lcms/0034-dead-code.patch
new file mode 100644
index 0000000..d02e60b
--- /dev/null
+++ b/third_party/lcms/0034-dead-code.patch
@@ -0,0 +1,14 @@
+diff --git a/third_party/lcms/src/cmspack.c b/third_party/lcms/src/cmspack.c
+index 3982cc564..7f55ce304 100644
+--- a/third_party/lcms/src/cmspack.c
++++ b/third_party/lcms/src/cmspack.c
+@@ -3864,9 +3864,6 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU
+ cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
+ cmsUInt32Number Float = lIsFloat ? 1U : 0;
+
+- // Unsupported color space?
+- if (nOutputChans < 0) return 0;
+-
+ // Create a fake formatter for result
+ return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
+ }
diff --git a/third_party/lcms/README.pdfium b/third_party/lcms/README.pdfium
index e5c3645..4f20a08 100644
--- a/third_party/lcms/README.pdfium
+++ b/third_party/lcms/README.pdfium
@@ -1,6 +1,6 @@
Name: Little CMS
URL: http://www.littlecms.com/
-Version: 2.13
+Version: 2.14
Security Critical: yes
License: MIT License
@@ -20,3 +20,4 @@
0029-drop-register-keyword.patch: Remove deprecated 'register' keyword.
0030-const-data.patch: Mark many data structures as const.
0033-opt-integer-overflow.patch: Protect against integer overflow.
+0034-dead-code.patch: Remove dead code.
diff --git a/third_party/lcms/include/lcms2.h b/third_party/lcms/include/lcms2.h
index 11d0c53..330709d 100644
--- a/third_party/lcms/include/lcms2.h
+++ b/third_party/lcms/include/lcms2.h
@@ -23,7 +23,7 @@
//
//---------------------------------------------------------------------------------
//
-// Version 2.13
+// Version 2.14
//
#ifndef _lcms2_H
@@ -81,7 +81,7 @@
#endif
// Version/release
-#define LCMS_VERSION 2130
+#define LCMS_VERSION 2140
// I will give the chance of redefining basic types for compilers that are not fully C99 compliant
#ifndef CMS_BASIC_TYPES_ALREADY_DEFINED
@@ -152,7 +152,7 @@
#endif
// Handle "register" keyword
-#if defined(CMS_NO_REGISTER_KEYWORD) && !defined(CMS_DLL) && !defined(CMS_DLL_BUILD)
+#if defined(CMS_NO_REGISTER_KEYWORD)
# define CMSREGISTER
#else
# define CMSREGISTER register
@@ -290,6 +290,7 @@
// Base ICC type definitions
typedef enum {
cmsSigChromaticityType = 0x6368726D, // 'chrm'
+ cmsSigcicpType = 0x63696370, // 'cicp'
cmsSigColorantOrderType = 0x636C726F, // 'clro'
cmsSigColorantTableType = 0x636C7274, // 'clrt'
cmsSigCrdInfoType = 0x63726469, // 'crdi'
@@ -401,6 +402,7 @@
cmsSigViewingConditionsTag = 0x76696577, // 'view'
cmsSigVcgtTag = 0x76636774, // 'vcgt'
cmsSigMetaTag = 0x6D657461, // 'meta'
+ cmsSigcicpTag = 0x63696370, // 'cicp'
cmsSigArgyllArtsTag = 0x61727473 // 'arts'
} cmsTagSignature;
@@ -1038,6 +1040,16 @@
} cmsICCViewingConditions;
+typedef struct {
+ cmsUInt8Number ColourPrimaries; // Recommendation ITU-T H.273
+ cmsUInt8Number TransferCharacteristics; // (ISO/IEC 23091-2)
+ cmsUInt8Number MatrixCoefficients;
+ cmsUInt8Number VideoFullRangeFlag;
+
+} cmsVideoSignalType;
+
+
+
// Get LittleCMS version (for shared objects) -----------------------------------------------------------------------------
CMSAPI int CMSEXPORT cmsGetEncodedCMMversion(void);
@@ -1520,8 +1532,12 @@
CMSAPI cmsColorSpaceSignature CMSEXPORT _cmsICCcolorSpace(int OurNotation);
CMSAPI int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace);
+// Deprecated, use cmsChannelsOfColorSpace instead
CMSAPI cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace);
+// Get number of channels of color space or -1 if color space is not listed/supported
+CMSAPI cmsInt32Number CMSEXPORT cmsChannelsOfColorSpace(cmsColorSpaceSignature ColorSpace);
+
// Build a suitable formatter for the colorspace of this profile. nBytes=1 means 8 bits, nBytes=2 means 16 bits.
CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat);
CMSAPI cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsUInt32Number nBytes, cmsBool lIsFloat);
diff --git a/third_party/lcms/include/lcms2_plugin.h b/third_party/lcms/include/lcms2_plugin.h
index 27fdb6a..33540b8 100644
--- a/third_party/lcms/include/lcms2_plugin.h
+++ b/third_party/lcms/include/lcms2_plugin.h
@@ -209,6 +209,7 @@
#define cmsPluginOptimizationSig 0x6F707448 // 'optH'
#define cmsPluginTransformSig 0x7A666D48 // 'xfmH'
#define cmsPluginMutexSig 0x6D747A48 // 'mtxH'
+#define cmsPluginParalellizationSig 0x70726C48 // 'prlH
typedef struct _cmsPluginBaseStruct {
@@ -596,7 +597,7 @@
const void* InputBuffer,
void* OutputBuffer,
cmsUInt32Number Size,
- cmsUInt32Number Stride); // Stride in bytes to the next plana in planar formats
+ cmsUInt32Number Stride); // Stride in bytes to the next plane in planar formats
typedef void (*_cmsTransform2Fn)(struct _cmstransform_struct *CMMcargo,
@@ -669,6 +670,25 @@
CMSAPI cmsBool CMSEXPORT _cmsLockMutex(cmsContext ContextID, void* mtx);
CMSAPI void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx);
+//----------------------------------------------------------------------------------------------------------
+// Parallelization
+
+CMSAPI _cmsTransform2Fn CMSEXPORT _cmsGetTransformWorker(struct _cmstransform_struct* CMMcargo);
+CMSAPI cmsInt32Number CMSEXPORT _cmsGetTransformMaxWorkers(struct _cmstransform_struct* CMMcargo);
+CMSAPI cmsUInt32Number CMSEXPORT _cmsGetTransformWorkerFlags(struct _cmstransform_struct* CMMcargo);
+
+// Let's plug-in to guess the best number of workers
+#define CMS_GUESS_MAX_WORKERS -1
+
+typedef struct {
+ cmsPluginBase base;
+
+ cmsInt32Number MaxWorkers; // Number of starts to do as maximum
+ cmsUInt32Number WorkerFlags; // Reserved
+ _cmsTransform2Fn SchedulerFn; // callback to setup functions
+
+} cmsPluginParalellization;
+
#ifndef CMS_USE_CPP_API
# ifdef __cplusplus
diff --git a/third_party/lcms/src/cmscgats.c b/third_party/lcms/src/cmscgats.c
index 241a88f..352f126 100644
--- a/third_party/lcms/src/cmscgats.c
+++ b/third_party/lcms/src/cmscgats.c
@@ -370,6 +370,7 @@
string* StringAlloc(cmsIT8* it8, int max)
{
string* s = (string*) AllocChunk(it8, sizeof(string));
+ if (s == NULL) return NULL;
s->it8 = it8;
s->max = max;
@@ -393,13 +394,18 @@
char* new_ptr;
s->max *= 10;
- new_ptr = AllocChunk(s->it8, s->max);
- memcpy(new_ptr, s->begin, s->len);
+ new_ptr = (char*) AllocChunk(s->it8, s->max);
+ if (new_ptr != NULL && s->begin != NULL)
+ memcpy(new_ptr, s->begin, s->len);
+
s->begin = new_ptr;
}
- s->begin[s->len++] = c;
- s->begin[s->len] = 0;
+ if (s->begin != NULL)
+ {
+ s->begin[s->len++] = c;
+ s->begin[s->len] = 0;
+ }
}
static
@@ -836,6 +842,7 @@
if ((cmsFloat64Number) it8->inum * 16.0 + (cmsFloat64Number) j > (cmsFloat64Number)+2147483647.0)
{
SynError(it8, "Invalid hexadecimal number");
+ it8->sy = SEOF;
return;
}
@@ -857,6 +864,7 @@
if ((cmsFloat64Number) it8->inum * 2.0 + j > (cmsFloat64Number)+2147483647.0)
{
SynError(it8, "Invalid binary number");
+ it8->sy = SEOF;
return;
}
@@ -925,13 +933,9 @@
}
else
switch ((int) it8->ch) {
-
- // EOF marker -- ignore it
- case '\x1a':
- NextCh(it8);
- break;
-
+
// Eof stream markers
+ case '\x1a':
case 0:
case -1:
it8->sy = SEOF;
@@ -971,6 +975,7 @@
default:
SynError(it8, "Unrecognized character: 0x%x", it8 ->ch);
+ it8->sy = SEOF;
return;
}
@@ -985,24 +990,33 @@
if(it8 -> IncludeSP >= (MAXINCLUDE-1)) {
SynError(it8, "Too many recursion levels");
+ it8->sy = SEOF;
return;
}
InStringSymbol(it8);
- if (!Check(it8, SSTRING, "Filename expected")) return;
+ if (!Check(it8, SSTRING, "Filename expected"))
+ {
+ it8->sy = SEOF;
+ return;
+ }
FileNest = it8 -> FileStack[it8 -> IncludeSP + 1];
if(FileNest == NULL) {
FileNest = it8 ->FileStack[it8 -> IncludeSP + 1] = (FILECTX*)AllocChunk(it8, sizeof(FILECTX));
- //if(FileNest == NULL)
- // TODO: how to manage out-of-memory conditions?
+ if (FileNest == NULL) {
+ SynError(it8, "Out of memory");
+ it8->sy = SEOF;
+ return;
+ }
}
if (BuildAbsolutePath(StringPtr(it8->str),
it8->FileStack[it8->IncludeSP]->FileName,
FileNest->FileName, cmsMAX_PATH-1) == FALSE) {
SynError(it8, "File path too long");
+ it8->sy = SEOF;
return;
}
@@ -1010,6 +1024,7 @@
if (FileNest->Stream == NULL) {
SynError(it8, "File %s not found", FileNest->FileName);
+ it8->sy = SEOF;
return;
}
it8->IncludeSP++;
@@ -1170,9 +1185,12 @@
it8 ->Allocator.BlockSize = size;
it8 ->Allocator.Used = 0;
- it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize);
+ it8 ->Allocator.Block = (cmsUInt8Number*) AllocBigBlock(it8, it8 ->Allocator.BlockSize);
}
+ if (it8->Allocator.Block == NULL)
+ return NULL;
+
ptr = it8 ->Allocator.Block + it8 ->Allocator.Used;
it8 ->Allocator.Used += size;
@@ -1513,28 +1531,45 @@
// ----------------------------------------------------------------- Datasets
+// A safe atoi that returns 0 when NULL input is given
+static
+cmsInt32Number satoi(const char* b)
+{
+ int n;
+
+ if (b == NULL) return 0;
+
+ n = atoi(b);
+ if (n > 0x7fffffffL) return 0x7fffffffL;
+ if (n < -0x7ffffffeL) return -0x7ffffffeL;
+
+ return (cmsInt32Number)n;
+}
+
static
-void AllocateDataFormat(cmsIT8* it8)
+cmsBool AllocateDataFormat(cmsIT8* it8)
{
TABLE* t = GetTable(it8);
- if (t -> DataFormat) return; // Already allocated
+ if (t -> DataFormat) return TRUE; // Already allocated
- t -> nSamples = (int) cmsIT8GetPropertyDbl(it8, "NUMBER_OF_FIELDS");
+ t -> nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
if (t -> nSamples <= 0) {
SynError(it8, "AllocateDataFormat: Unknown NUMBER_OF_FIELDS");
- t -> nSamples = 10;
+ return FALSE;
}
t -> DataFormat = (char**) AllocChunk (it8, ((cmsUInt32Number) t->nSamples + 1) * sizeof(char *));
if (t->DataFormat == NULL) {
SynError(it8, "AllocateDataFormat: Unable to allocate dataFormat array");
+ return FALSE;
}
+ return TRUE;
}
static
@@ -1553,8 +1588,11 @@
{
TABLE* t = GetTable(it8);
- if (!t->DataFormat)
- AllocateDataFormat(it8);
+ if (!t->DataFormat) {
+
+ if (!AllocateDataFormat(it8))
+ return FALSE;
+ }
if (n > t -> nSamples) {
SynError(it8, "More than NUMBER_OF_FIELDS fields.");
@@ -1563,6 +1601,7 @@
if (t->DataFormat) {
t->DataFormat[n] = AllocString(it8, label);
+ if (t->DataFormat[n] == NULL) return FALSE;
}
return TRUE;
@@ -1575,14 +1614,6 @@
return SetDataFormat(it8, n, Sample);
}
-// A safe atoi that returns 0 when NULL input is given
-static
-cmsInt32Number satoi(const char* b)
-{
- if (b == NULL) return 0;
- return atoi(b);
-}
-
// Convert to binary
static
const char* satob(const char* v)
@@ -1603,11 +1634,11 @@
static
-void AllocateDataSet(cmsIT8* it8)
+cmsBool AllocateDataSet(cmsIT8* it8)
{
TABLE* t = GetTable(it8);
- if (t -> Data) return; // Already allocated
+ if (t -> Data) return TRUE; // Already allocated
t-> nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS"));
t-> nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS"));
@@ -1615,6 +1646,7 @@
if (t -> nSamples < 0 || t->nSamples > 0x7ffe || t->nPatches < 0 || t->nPatches > 0x7ffe)
{
SynError(it8, "AllocateDataSet: too much data");
+ return FALSE;
}
else {
// Some dumb analizers warns of possible overflow here, just take a look couple of lines above.
@@ -1622,9 +1654,11 @@
if (t->Data == NULL) {
SynError(it8, "AllocateDataSet: Unable to allocate data array");
+ return FALSE;
}
}
+ return TRUE;
}
static
@@ -1646,8 +1680,9 @@
{
TABLE* t = GetTable(it8);
- if (!t->Data)
- AllocateDataSet(it8);
+ if (!t->Data) {
+ if (!AllocateDataSet(it8)) return FALSE;
+ }
if (!t->Data) return FALSE;
@@ -1990,8 +2025,9 @@
InSymbol(it8); // Eats "BEGIN_DATA"
CheckEOLN(it8);
- if (!t->Data)
- AllocateDataSet(it8);
+ if (!t->Data) {
+ if (!AllocateDataSet(it8)) return FALSE;
+ }
while (it8->sy != SEND_DATA && it8->sy != SEOF)
{
@@ -2324,19 +2360,19 @@
snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type);
SetData(it8, i, idField, Buffer);
- }
- }
+ }
+ }
- }
+ }
- }
+ }
- }
+ }
- }
- }
+ }
+ }
it8 ->nTable = nOldTable;
}
@@ -2538,15 +2574,18 @@
}
- Props = (char **) AllocChunk(it8, sizeof(char *) * n);
+ Props = (char**)AllocChunk(it8, sizeof(char*) * n);
+ if (Props != NULL) {
- // Pass#2 - Fill pointers
- n = 0;
- for (p = t -> HeaderList; p != NULL; p = p->Next) {
- Props[n++] = p -> Keyword;
- }
+ // Pass#2 - Fill pointers
+ n = 0;
+ for (p = t->HeaderList; p != NULL; p = p->Next) {
+ Props[n++] = p->Keyword;
+ }
- *PropertyNames = Props;
+ }
+ *PropertyNames = Props;
+
return n;
}
@@ -2578,12 +2617,14 @@
Props = (const char **) AllocChunk(it8, sizeof(char *) * n);
+ if (Props != NULL) {
- // Pass#2 - Fill pointers
- n = 0;
- for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) {
- if(tmp->Subkey != NULL)
- Props[n++] = p ->Subkey;
+ // Pass#2 - Fill pointers
+ n = 0;
+ for (tmp = p; tmp != NULL; tmp = tmp->NextSubkey) {
+ if (tmp->Subkey != NULL)
+ Props[n++] = p->Subkey;
+ }
}
*SubpropertyNames = Props;
@@ -2759,8 +2800,12 @@
if (t-> nPatches == 0) {
- AllocateDataFormat(it8);
- AllocateDataSet(it8);
+ if (!AllocateDataFormat(it8))
+ return FALSE;
+
+ if (!AllocateDataSet(it8))
+ return FALSE;
+
CookPointers(it8);
}
diff --git a/third_party/lcms/src/cmscnvrt.c b/third_party/lcms/src/cmscnvrt.c
index fe25525..50e5a1e 100644
--- a/third_party/lcms/src/cmscnvrt.c
+++ b/third_party/lcms/src/cmscnvrt.c
@@ -386,7 +386,7 @@
if (BPC) {
- cmsCIEXYZ BlackPointIn, BlackPointOut;
+ cmsCIEXYZ BlackPointIn = { 0, 0, 0}, BlackPointOut = { 0, 0, 0 };
cmsDetectBlackPoint(&BlackPointIn, hProfiles[i-1], Intent, 0);
cmsDetectDestinationBlackPoint(&BlackPointOut, hProfiles[i], Intent, 0);
@@ -630,7 +630,7 @@
ColorSpaceOut == cmsSigRgbData ||
ColorSpaceOut == cmsSigCmykData) {
- cmsStage* clip = _cmsStageClipNegatives(Result->ContextID, cmsChannelsOf(ColorSpaceOut));
+ cmsStage* clip = _cmsStageClipNegatives(Result->ContextID, cmsChannelsOfColorSpace(ColorSpaceOut));
if (clip == NULL) goto Error;
if (!cmsPipelineInsertStage(Result, cmsAT_END, clip))
diff --git a/third_party/lcms/src/cmserr.c b/third_party/lcms/src/cmserr.c
index c65dce5..29fe9ca 100644
--- a/third_party/lcms/src/cmserr.c
+++ b/third_party/lcms/src/cmserr.c
@@ -471,7 +471,6 @@
if (Plugin ->CreateMutexPtr == NULL || Plugin ->DestroyMutexPtr == NULL ||
Plugin ->LockMutexPtr == NULL || Plugin ->UnlockMutexPtr == NULL) return FALSE;
-
ctx->CreateMutexPtr = Plugin->CreateMutexPtr;
ctx->DestroyMutexPtr = Plugin ->DestroyMutexPtr;
ctx ->LockMutexPtr = Plugin ->LockMutexPtr;
@@ -519,3 +518,47 @@
ptr ->UnlockMutexPtr(ContextID, mtx);
}
}
+
+// The global Context0 storage for parallelization plug-in
+ _cmsParallelizationPluginChunkType _cmsParallelizationPluginChunk = { 0 };
+
+// Allocate parallelization container.
+void _cmsAllocParallelizationPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src)
+{
+ if (src != NULL) {
+ void* from = src->chunks[ParallelizationPlugin];
+ ctx->chunks[ParallelizationPlugin] = _cmsSubAllocDup(ctx->MemPool, from, sizeof(_cmsParallelizationPluginChunkType));
+ }
+ else {
+ _cmsParallelizationPluginChunkType ParallelizationPluginChunk = { 0 };
+ ctx->chunks[ParallelizationPlugin] = _cmsSubAllocDup(ctx->MemPool, &ParallelizationPluginChunk, sizeof(_cmsParallelizationPluginChunkType));
+ }
+}
+
+// Register parallel processing
+cmsBool _cmsRegisterParallelizationPlugin(cmsContext ContextID, cmsPluginBase* Data)
+{
+ cmsPluginParalellization* Plugin = (cmsPluginParalellization*)Data;
+ _cmsParallelizationPluginChunkType* ctx = (_cmsParallelizationPluginChunkType*)_cmsContextGetClientChunk(ContextID, ParallelizationPlugin);
+
+ if (Data == NULL) {
+
+ // No parallelization routines
+ ctx->MaxWorkers = 0;
+ ctx->WorkerFlags = 0;
+ ctx->SchedulerFn = NULL;
+ return TRUE;
+ }
+
+ // callback is required
+ if (Plugin->SchedulerFn == NULL) return FALSE;
+
+ ctx->MaxWorkers = Plugin->MaxWorkers;
+ ctx->WorkerFlags = Plugin->WorkerFlags;
+ ctx->SchedulerFn = Plugin->SchedulerFn;
+
+ // All is ok
+ return TRUE;
+}
+
diff --git a/third_party/lcms/src/cmsgamma.c b/third_party/lcms/src/cmsgamma.c
index dee1b4b..1dc3244 100644
--- a/third_party/lcms/src/cmsgamma.c
+++ b/third_party/lcms/src/cmsgamma.c
@@ -427,8 +427,8 @@
// IEC 61966-3
- // Y = (aX + b)^Gamma | X <= -b/a
- // Y = c | else
+ // Y = (aX + b)^Gamma + c | X <= -b/a
+ // Y = c | else
case 3:
{
if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
@@ -462,7 +462,8 @@
// X=-b/a | (Y<c)
case -3:
{
- if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE)
{
Val = 0;
}
@@ -601,7 +602,8 @@
// ((Y - c) ^1/Gamma - b) / a
case -6:
{
- if (fabs(Params[1]) < MATRIX_DET_TOLERANCE)
+ if (fabs(Params[0]) < MATRIX_DET_TOLERANCE ||
+ fabs(Params[1]) < MATRIX_DET_TOLERANCE)
{
Val = 0;
}
@@ -1488,6 +1490,9 @@
}
}
+ // We need enough valid samples
+ if (n <= 1) return -1.0;
+
// Take a look on SD to see if gamma isn't exponential at all
Std = sqrt((n * sum2 - sum * sum) / (n*(n-1)));
diff --git a/third_party/lcms/src/cmsgmt.c b/third_party/lcms/src/cmsgmt.c
index 70f2803..5109bfa 100644
--- a/third_party/lcms/src/cmsgmt.c
+++ b/third_party/lcms/src/cmsgmt.c
@@ -297,7 +297,8 @@
cmsStage* CLUT;
cmsUInt32Number dwFormat;
GAMUTCHAIN Chain;
- cmsUInt32Number nChannels, nGridpoints;
+ cmsUInt32Number nGridpoints;
+ cmsInt32Number nChannels;
cmsColorSpaceSignature ColorSpace;
cmsUInt32Number i;
cmsHPROFILE ProfileList[256];
@@ -346,8 +347,7 @@
ColorSpace = cmsGetColorSpace(hGamut);
-
- nChannels = cmsChannelsOf(ColorSpace);
+ nChannels = cmsChannelsOfColorSpace(ColorSpace);
nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC);
dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2));
@@ -472,6 +472,9 @@
// Create a fake formatter for result
dwFormatter = cmsFormatterForColorspaceOfProfile(hProfile, 4, TRUE);
+ // Unsupported color space?
+ if (dwFormatter == 0) return 0;
+
bp.nOutputChans = T_CHANNELS(dwFormatter);
bp.MaxTAC = 0; // Initial TAC is 0
@@ -619,6 +622,8 @@
ContextID = cmsGetProfileContextID(hProfile);
hXYZ = cmsCreateXYZProfileTHR(ContextID);
+ if (hXYZ == NULL)
+ return -1;
xform = cmsCreateTransformTHR(ContextID, hProfile, TYPE_RGB_16, hXYZ, TYPE_XYZ_DBL,
INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE);
diff --git a/third_party/lcms/src/cmsintrp.c b/third_party/lcms/src/cmsintrp.c
index 5cd6d16..5eb98e6 100644
--- a/third_party/lcms/src/cmsintrp.c
+++ b/third_party/lcms/src/cmsintrp.c
@@ -278,10 +278,10 @@
// if last value...
if (Input[0] == 0xffff || p16->Domain[0] == 0) {
- cmsUInt16Number y0 = LutTable[p16->Domain[0]];
-
+ cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0];
+
for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) {
- Output[OutChan] = y0;
+ Output[OutChan] = LutTable[y0 + OutChan];
}
}
else
@@ -324,10 +324,10 @@
// if last value...
if (val2 == 1.0 || p->Domain[0] == 0) {
- y0 = LutTable[p->Domain[0]];
+ cmsUInt32Number start = p->Domain[0] * p->opta[0];
for (OutChan = 0; OutChan < p->nOutputs; OutChan++) {
- Output[OutChan] = y0;
+ Output[OutChan] = LutTable[start + OutChan];
}
}
else
diff --git a/third_party/lcms/src/cmsio0.c b/third_party/lcms/src/cmsio0.c
index 0724eaa..413b106 100644
--- a/third_party/lcms/src/cmsio0.c
+++ b/third_party/lcms/src/cmsio0.c
@@ -374,24 +374,58 @@
{
cmsIOHANDLER* iohandler = NULL;
FILE* fm = NULL;
- cmsInt32Number fileLen;
+ cmsInt32Number fileLen;
+ char mode[4] = { 0,0,0,0 };
_cmsAssert(FileName != NULL);
_cmsAssert(AccessMode != NULL);
iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER));
if (iohandler == NULL) return NULL;
+
+ // Validate access mode
+ while (*AccessMode) {
- switch (*AccessMode) {
+ switch (*AccessMode)
+ {
+ case 'r':
+ case 'w':
+
+ if (mode[0] == 0) {
+ mode[0] = *AccessMode;
+ mode[1] = 'b';
+ }
+ else {
+ _cmsFree(ContextID, iohandler);
+ cmsSignalError(ContextID, cmsERROR_FILE, "Access mode already specified '%c'", *AccessMode);
+ return NULL;
+ }
+ break;
+
+ // Close on exec. Not all runtime supports that. Up to the caller to decide.
+ case 'e':
+ mode[2] = 'e';
+ break;
+
+ default:
+ _cmsFree(ContextID, iohandler);
+ cmsSignalError(ContextID, cmsERROR_FILE, "Wrong access mode '%c'", *AccessMode);
+ return NULL;
+ }
+
+ AccessMode++;
+ }
+
+ switch (mode[0]) {
case 'r':
- fm = fopen(FileName, "rb");
+ fm = fopen(FileName, mode);
if (fm == NULL) {
_cmsFree(ContextID, iohandler);
cmsSignalError(ContextID, cmsERROR_FILE, "File '%s' not found", FileName);
return NULL;
}
- fileLen = cmsfilelength(fm);
+ fileLen = (cmsInt32Number)cmsfilelength(fm);
if (fileLen < 0)
{
fclose(fm);
@@ -399,12 +433,11 @@
cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of file '%s'", FileName);
return NULL;
}
-
iohandler -> ReportedSize = (cmsUInt32Number) fileLen;
break;
case 'w':
- fm = fopen(FileName, "wb");
+ fm = fopen(FileName, mode);
if (fm == NULL) {
_cmsFree(ContextID, iohandler);
cmsSignalError(ContextID, cmsERROR_FILE, "Couldn't create '%s'", FileName);
@@ -414,8 +447,7 @@
break;
default:
- _cmsFree(ContextID, iohandler);
- cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode);
+ _cmsFree(ContextID, iohandler); // Would never reach
return NULL;
}
@@ -442,7 +474,7 @@
cmsIOHANDLER* iohandler = NULL;
cmsInt32Number fileSize;
- fileSize = cmsfilelength(Stream);
+ fileSize = (cmsInt32Number)cmsfilelength(Stream);
if (fileSize < 0)
{
cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of stream");
@@ -507,6 +539,9 @@
// Set default version
Icc ->Version = 0x02100000;
+ // Set default device class
+ Icc->DeviceClass = cmsSigDisplayClass;
+
// Set creation date/time
if (!_cmsGetTime(&Icc->Created))
goto Error;
@@ -673,6 +708,27 @@
return _cmsSearchTag(Icc, sig, FALSE) >= 0;
}
+
+
+// Checks for link compatibility
+static
+cmsBool CompatibleTypes(const cmsTagDescriptor* desc1, const cmsTagDescriptor* desc2)
+{
+ cmsUInt32Number i;
+
+ if (desc1 == NULL || desc2 == NULL) return FALSE;
+
+ if (desc1->nSupportedTypes != desc2->nSupportedTypes) return FALSE;
+ if (desc1->ElemCount != desc2->ElemCount) return FALSE;
+
+ for (i = 0; i < desc1->nSupportedTypes; i++)
+ {
+ if (desc1->SupportedTypes[i] != desc2->SupportedTypes[i]) return FALSE;
+ }
+
+ return TRUE;
+}
+
// Enforces that the profile version is per. spec.
// Operates on the big endian bytes from the profile.
// Called before converting to platform endianness.
@@ -698,6 +754,29 @@
return DWord;
}
+// Check device class
+static
+cmsBool validDeviceClass(cmsProfileClassSignature cl)
+{
+ if ((int)cl == 0) return TRUE; // We allow zero because older lcms versions defaulted to that.
+
+ switch (cl)
+ {
+ case cmsSigInputClass:
+ case cmsSigDisplayClass:
+ case cmsSigOutputClass:
+ case cmsSigLinkClass:
+ case cmsSigAbstractClass:
+ case cmsSigColorSpaceClass:
+ case cmsSigNamedColorClass:
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+
+}
+
// Read profile header and validate it
cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc)
{
@@ -734,6 +813,16 @@
_cmsAdjustEndianess64(&Icc -> attributes, &Header.attributes);
Icc -> Version = _cmsAdjustEndianess32(_validatedVersion(Header.version));
+ if (Icc->Version > 0x5000000) {
+ cmsSignalError(Icc->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported profile version '0x%x'", Icc->Version);
+ return FALSE;
+ }
+
+ if (!validDeviceClass(Icc->DeviceClass)) {
+ cmsSignalError(Icc->ContextID, cmsERROR_UNKNOWN_EXTENSION, "Unsupported device class '0x%x'", Icc->DeviceClass);
+ return FALSE;
+ }
+
// Get size as reported in header
HeaderSize = _cmsAdjustEndianess32(Header.size);
@@ -767,6 +856,7 @@
if (!_cmsReadUInt32Number(io, &Tag.size)) return FALSE;
// Perform some sanity check. Offset + size should fall inside file.
+ if (Tag.size == 0 || Tag.offset == 0) continue;
if (Tag.offset + Tag.size > HeaderSize ||
Tag.offset + Tag.size < Tag.offset)
continue;
@@ -777,12 +867,17 @@
// Search for links
for (j=0; j < Icc ->TagCount; j++) {
-
+
if ((Icc ->TagOffsets[j] == Tag.offset) &&
(Icc ->TagSizes[j] == Tag.size) &&
(Icc ->TagNames[j] == Tag.sig)) {
- Icc ->TagLinked[Icc ->TagCount] = Icc ->TagNames[j];
+ // Check types.
+ if (CompatibleTypes(_cmsGetTagDescriptor(Icc->ContextID, Icc->TagNames[j]),
+ _cmsGetTagDescriptor(Icc->ContextID, Tag.sig))) {
+
+ Icc->TagLinked[Icc->TagCount] = Icc->TagNames[j];
+ }
}
}
@@ -790,6 +885,19 @@
Icc ->TagCount++;
}
+
+ for (i = 0; i < Icc->TagCount; i++) {
+ for (j = 0; j < Icc->TagCount; j++) {
+
+ // Tags cannot be duplicate
+ if ((i != j) && (Icc->TagNames[i] == Icc->TagNames[j])) {
+ cmsSignalError(Icc->ContextID, cmsERROR_RANGE, "Duplicate tag found");
+ return FALSE;
+ }
+
+ }
+ }
+
return TRUE;
}
@@ -1581,6 +1689,13 @@
if (TagSize < 8) goto Error;
io = Icc ->IOhandler;
+
+ if (io == NULL) { // This is a built-in profile that has been manipulated, abort early
+
+ cmsSignalError(Icc->ContextID, cmsERROR_CORRUPTION_DETECTED, "Corrupted built-in profile.");
+ goto Error;
+ }
+
// Seek to its location
if (!io -> Seek(io, Offset))
goto Error;
@@ -1792,11 +1907,9 @@
}
-// Read and write raw data. The only way those function would work and keep consistence with normal read and write
-// is to do an additional step of serialization. That means, readRaw would issue a normal read and then convert the obtained
-// data to raw bytes by using the "write" serialization logic. And vice-versa. I know this may end in situations where
-// raw data written does not exactly correspond with the raw data proposed to cmsWriteRaw data, but this approach allows
-// to write a tag as raw data and the read it as handled.
+// Read and write raw data. Read/Write Raw/cooked pairs try to maintain consistency within the pair. Some sequences
+// raw/cooked would work, but at a cost. Data "cooked" may be converted to "raw" by using the "write" serialization logic.
+// In general it is better to avoid mixing pairs.
cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature sig, void* data, cmsUInt32Number BufferSize)
{
@@ -1810,9 +1923,13 @@
cmsUInt32Number rc;
cmsUInt32Number Offset, TagSize;
+ // Sanity check
+ if (data != NULL && BufferSize == 0) return 0;
+
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
// Search for given tag in ICC profile directory
+
i = _cmsSearchTag(Icc, sig, TRUE);
if (i < 0) goto Error; // Not found,
@@ -1824,10 +1941,11 @@
TagSize = Icc ->TagSizes[i];
// read the data directly, don't keep copy
+
if (data != NULL) {
if (BufferSize < TagSize)
- TagSize = BufferSize;
+ goto Error;
if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error;
if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error;
@@ -1842,13 +1960,14 @@
// The data has been already read, or written. But wait!, maybe the user chose to save as
// raw data. In this case, return the raw data directly
+
if (Icc ->TagSaveAsRaw[i]) {
if (data != NULL) {
TagSize = Icc ->TagSizes[i];
if (BufferSize < TagSize)
- TagSize = BufferSize;
+ goto Error;
memmove(data, Icc ->TagPtrs[i], TagSize);
@@ -1861,8 +1980,8 @@
}
// Already read, or previously set by cmsWriteTag(). We need to serialize that
- // data to raw in order to maintain consistency.
-
+ // data to raw to get something that makes sense
+
_cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex);
Object = cmsReadTag(hProfile, sig);
if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return 0;
diff --git a/third_party/lcms/src/cmsio1.c b/third_party/lcms/src/cmsio1.c
index db18b9f..2d7deee 100644
--- a/third_party/lcms/src/cmsio1.c
+++ b/third_party/lcms/src/cmsio1.c
@@ -322,10 +322,8 @@
if (nc == NULL) return NULL;
Lut = cmsPipelineAlloc(ContextID, 0, 0);
- if (Lut == NULL) {
- cmsFreeNamedColorList(nc);
- return NULL;
- }
+ if (Lut == NULL)
+ return NULL;
if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) ||
!cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) {
@@ -739,8 +737,7 @@
return Lut;
Error:
- cmsPipelineFree(Lut);
- cmsFreeNamedColorList(nc);
+ cmsPipelineFree(Lut);
return NULL;
}
diff --git a/third_party/lcms/src/cmslut.c b/third_party/lcms/src/cmslut.c
index 49cc63b..152e6d6 100644
--- a/third_party/lcms/src/cmslut.c
+++ b/third_party/lcms/src/cmslut.c
@@ -467,7 +467,7 @@
for (rv = 1; b > 0; b--) {
dim = Dims[b-1];
- if (dim == 0) return 0; // Error
+ if (dim <= 1) return 0; // Error
rv *= dim;
diff --git a/third_party/lcms/src/cmsnamed.c b/third_party/lcms/src/cmsnamed.c
index 28e67f2..87f3936 100644
--- a/third_party/lcms/src/cmsnamed.c
+++ b/third_party/lcms/src/cmsnamed.c
@@ -542,10 +542,14 @@
// Allocate a list for n elements
cmsNAMEDCOLORLIST* CMSEXPORT cmsAllocNamedColorList(cmsContext ContextID, cmsUInt32Number n, cmsUInt32Number ColorantCount, const char* Prefix, const char* Suffix)
{
- cmsNAMEDCOLORLIST* v = (cmsNAMEDCOLORLIST*) _cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
-
+ cmsNAMEDCOLORLIST* v;
+
+ if (ColorantCount > cmsMAXCHANNELS)
+ return NULL;
+
+ v = (cmsNAMEDCOLORLIST*)_cmsMallocZero(ContextID, sizeof(cmsNAMEDCOLORLIST));
if (v == NULL) return NULL;
-
+
v ->List = NULL;
v ->nColors = 0;
v ->ContextID = ContextID;
diff --git a/third_party/lcms/src/cmsopt.c b/third_party/lcms/src/cmsopt.c
index 3eb8f62..f65fc87 100644
--- a/third_party/lcms/src/cmsopt.c
+++ b/third_party/lcms/src/cmsopt.c
@@ -1550,10 +1550,10 @@
}
-// A fast matrix-shaper evaluator for 8 bits. This is a bit ticky since I'm using 1.14 signed fixed point
+// A fast matrix-shaper evaluator for 8 bits. This is a bit tricky since I'm using 1.14 signed fixed point
// to accomplish some performance. Actually it takes 256x3 16 bits tables and 16385 x 3 tables of 8 bits,
// in total about 50K, and the performance boost is huge!
-static
+static CMS_NO_SANITIZE
void MatShaperEval16(CMSREGISTER const cmsUInt16Number In[],
CMSREGISTER cmsUInt16Number Out[],
CMSREGISTER const void* D)
diff --git a/third_party/lcms/src/cmspack.c b/third_party/lcms/src/cmspack.c
index 955687c..7f55ce3 100644
--- a/third_party/lcms/src/cmspack.c
+++ b/third_party/lcms/src/cmspack.c
@@ -592,8 +592,11 @@
if (SwapEndian)
v = CHANGE_ENDIAN(v);
- v = (v << 16) / alpha_factor;
- if (v > 0xffff) v = 0xffff;
+ if (alpha_factor > 0) {
+
+ v = (v << 16) / alpha_factor;
+ if (v > 0xffff) v = 0xffff;
+ }
wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
@@ -674,8 +677,11 @@
if (SwapEndian)
v = CHANGE_ENDIAN(v);
- v = (v << 16) / alpha_factor;
- if (v > 0xffff) v = 0xffff;
+ if (alpha_factor > 0) {
+
+ v = (v << 16) / alpha_factor;
+ if (v > 0xffff) v = 0xffff;
+ }
wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v);
@@ -3799,6 +3805,11 @@
_cmsFormattersPluginChunkType* ctx = ( _cmsFormattersPluginChunkType*) _cmsContextGetClientChunk(ContextID, FormattersPlugin);
cmsFormattersFactoryList* f;
+ if (T_CHANNELS(Type) == 0) {
+ static const cmsFormatter nullFormatter = { 0 };
+ return nullFormatter;
+ }
+
for (f =ctx->FactoryList; f != NULL; f = f ->Next) {
cmsFormatter fn = f ->Factory(Type, Dir, dwFlags);
@@ -3833,9 +3844,12 @@
cmsColorSpaceSignature ColorSpace = cmsGetColorSpace(hProfile);
cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace);
- cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace);
+ cmsInt32Number nOutputChans = cmsChannelsOfColorSpace(ColorSpace);
cmsUInt32Number Float = lIsFloat ? 1U : 0;
+ // Unsupported color space?
+ if (nOutputChans < 0) return 0;
+
// Create a fake formatter for result
return FLOAT_SH(Float) | COLORSPACE_SH(ColorSpaceBits) | BYTES_SH(nBytes) | CHANNELS_SH(nOutputChans);
}
diff --git a/third_party/lcms/src/cmspcs.c b/third_party/lcms/src/cmspcs.c
index 3d6323a..a0f1952 100644
--- a/third_party/lcms/src/cmspcs.c
+++ b/third_party/lcms/src/cmspcs.c
@@ -874,7 +874,7 @@
}
-cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
+cmsInt32Number CMSEXPORT cmsChannelsOfColorSpace(cmsColorSpaceSignature ColorSpace)
{
switch (ColorSpace) {
@@ -935,6 +935,16 @@
case cmsSigMCHFData:
case cmsSig15colorData: return 15;
- default: return 3;
+ default: return -1;
}
}
+
+/**
+* DEPRECATED: Provided for compatibility only
+*/
+cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace)
+{
+ int n = cmsChannelsOfColorSpace(ColorSpace);
+ if (n < 0) return 3;
+ return (cmsUInt32Number)n;
+}
\ No newline at end of file
diff --git a/third_party/lcms/src/cmsplugin.c b/third_party/lcms/src/cmsplugin.c
index dbda3fd..7d038d2 100644
--- a/third_party/lcms/src/cmsplugin.c
+++ b/third_party/lcms/src/cmsplugin.c
@@ -168,18 +168,21 @@
cmsBool CMSEXPORT _cmsReadFloat32Number(cmsIOHANDLER* io, cmsFloat32Number* n)
{
- cmsUInt32Number tmp;
+ union typeConverter {
+ cmsUInt32Number integer;
+ cmsFloat32Number floating_point;
+ } tmp;
_cmsAssert(io != NULL);
- if (io->Read(io, &tmp, sizeof(cmsUInt32Number), 1) != 1)
+ if (io->Read(io, &tmp.integer, sizeof(cmsUInt32Number), 1) != 1)
return FALSE;
if (n != NULL) {
- tmp = _cmsAdjustEndianess32(tmp);
- *n = *(cmsFloat32Number*)(void*)&tmp;
-
+ tmp.integer = _cmsAdjustEndianess32(tmp.integer);
+ *n = tmp.floating_point;
+
// Safeguard which covers against absurd values
if (*n > 1E+20 || *n < -1E+20) return FALSE;
@@ -305,13 +308,14 @@
cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n)
{
- cmsUInt32Number tmp;
+ union typeConverter {
+ cmsUInt32Number integer;
+ cmsFloat32Number floating_point;
+ } tmp;
- _cmsAssert(io != NULL);
-
- tmp = *(cmsUInt32Number*) (void*) &n;
- tmp = _cmsAdjustEndianess32(tmp);
- if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1)
+ tmp.floating_point = n;
+ tmp.integer = _cmsAdjustEndianess32(tmp.integer);
+ if (io -> Write(io, sizeof(cmsUInt32Number), &tmp.integer) != 1)
return FALSE;
return TRUE;
@@ -621,6 +625,10 @@
if (!_cmsRegisterMutexPlugin(id, Plugin)) return FALSE;
break;
+ case cmsPluginParalellizationSig:
+ if (!_cmsRegisterParallelizationPlugin(id, Plugin)) return FALSE;
+ break;
+
default:
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized plugin type '%X'", Plugin -> Type);
return FALSE;
@@ -643,24 +651,25 @@
// pointers structure. All global vars are referenced here.
static struct _cmsContext_struct globalContext = {
- NULL, // Not in the linked list
- NULL, // No suballocator
- {
- NULL, // UserPtr,
- &_cmsLogErrorChunk, // Logger,
- &_cmsAlarmCodesChunk, // AlarmCodes,
- &_cmsAdaptationStateChunk, // AdaptationState,
- &_cmsMemPluginChunk, // MemPlugin,
- &_cmsInterpPluginChunk, // InterpPlugin,
- &_cmsCurvesPluginChunk, // CurvesPlugin,
- &_cmsFormattersPluginChunk, // FormattersPlugin,
- &_cmsTagTypePluginChunk, // TagTypePlugin,
- &_cmsTagPluginChunk, // TagPlugin,
- &_cmsIntentsPluginChunk, // IntentPlugin,
- &_cmsMPETypePluginChunk, // MPEPlugin,
- &_cmsOptimizationPluginChunk, // OptimizationPlugin,
- &_cmsTransformPluginChunk, // TransformPlugin,
- &_cmsMutexPluginChunk // MutexPlugin
+ NULL, // Not in the linked list
+ NULL, // No suballocator
+ {
+ NULL, // UserPtr,
+ &_cmsLogErrorChunk, // Logger,
+ &_cmsAlarmCodesChunk, // AlarmCodes,
+ &_cmsAdaptationStateChunk, // AdaptationState,
+ &_cmsMemPluginChunk, // MemPlugin,
+ &_cmsInterpPluginChunk, // InterpPlugin,
+ &_cmsCurvesPluginChunk, // CurvesPlugin,
+ &_cmsFormattersPluginChunk, // FormattersPlugin,
+ &_cmsTagTypePluginChunk, // TagTypePlugin,
+ &_cmsTagPluginChunk, // TagPlugin,
+ &_cmsIntentsPluginChunk, // IntentPlugin,
+ &_cmsMPETypePluginChunk, // MPEPlugin,
+ &_cmsOptimizationPluginChunk, // OptimizationPlugin,
+ &_cmsTransformPluginChunk, // TransformPlugin,
+ &_cmsMutexPluginChunk, // MutexPlugin,
+ &_cmsParallelizationPluginChunk // ParallelizationPlugin
},
{ NULL, NULL, NULL, NULL, NULL, NULL } // The default memory allocator is not used for context 0
@@ -787,6 +796,8 @@
// identify which plug-in to unregister.
void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID)
{
+ struct _cmsContext_struct* ctx = _cmsGetContext(ContextID);
+
_cmsRegisterMemHandlerPlugin(ContextID, NULL);
_cmsRegisterInterpPlugin(ContextID, NULL);
_cmsRegisterTagTypePlugin(ContextID, NULL);
@@ -798,6 +809,11 @@
_cmsRegisterOptimizationPlugin(ContextID, NULL);
_cmsRegisterTransformPlugin(ContextID, NULL);
_cmsRegisterMutexPlugin(ContextID, NULL);
+ _cmsRegisterParallelizationPlugin(ContextID, NULL);
+
+ if (ctx->MemPool != NULL)
+ _cmsSubAllocDestroy(ctx->MemPool);
+ ctx->MemPool = NULL;
}
@@ -881,6 +897,7 @@
_cmsAllocOptimizationPluginChunk(ctx, NULL);
_cmsAllocTransformPluginChunk(ctx, NULL);
_cmsAllocMutexPluginChunk(ctx, NULL);
+ _cmsAllocParallelizationPluginChunk(ctx, NULL);
// Setup the plug-ins
if (!cmsPluginTHR(ctx, Plugin)) {
@@ -944,6 +961,7 @@
_cmsAllocOptimizationPluginChunk(ctx, src);
_cmsAllocTransformPluginChunk(ctx, src);
_cmsAllocMutexPluginChunk(ctx, src);
+ _cmsAllocParallelizationPluginChunk(ctx, src);
// Make sure no one failed
for (i=Logger; i < MemoryClientMax; i++) {
diff --git a/third_party/lcms/src/cmssamp.c b/third_party/lcms/src/cmssamp.c
index 868664a..f5957d1 100644
--- a/third_party/lcms/src/cmssamp.c
+++ b/third_party/lcms/src/cmssamp.c
@@ -126,6 +126,7 @@
// Force it to be neutral, clip to max. L* of 50
Lab.a = Lab.b = 0;
if (Lab.L > 50) Lab.L = 50;
+ if (Lab.L < 0) Lab.L = 0;
// Free the resources
cmsDeleteTransform(xform);
@@ -322,6 +323,7 @@
if (fabs(a) < 1.0E-10) {
+ if (fabs(b) < 1.0E-10) return 0;
return cmsmin(0, cmsmax(50, -c/b ));
}
else {
@@ -332,7 +334,11 @@
}
else {
- double rt = (-b + sqrt(d)) / (2.0 * a);
+ double rt;
+
+ if (fabs(a) < 1.0E-10) return 0;
+
+ rt = (-b + sqrt(d)) / (2.0 * a);
return cmsmax(0, cmsmin(50, rt));
}
diff --git a/third_party/lcms/src/cmstypes.c b/third_party/lcms/src/cmstypes.c
index c05a3ec..1144d98 100644
--- a/third_party/lcms/src/cmstypes.c
+++ b/third_party/lcms/src/cmstypes.c
@@ -1425,9 +1425,9 @@
{
cmsICCMeasurementConditions mc;
-
+
memset(&mc, 0, sizeof(mc));
-
+
if (!_cmsReadUInt32Number(io, &mc.Observer)) return NULL;
if (!_cmsReadXYZNumber(io, &mc.Backing)) return NULL;
if (!_cmsReadUInt32Number(io, &mc.Geometry)) return NULL;
@@ -1550,7 +1550,10 @@
Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag);
if (Block == NULL) goto Error;
NumOfWchar = SizeOfTag / sizeof(wchar_t);
- if (!_cmsReadWCharArray(io, NumOfWchar, Block)) goto Error;
+ if (!_cmsReadWCharArray(io, NumOfWchar, Block)) {
+ _cmsFree(self->ContextID, Block);
+ goto Error;
+ }
}
mlu ->MemPool = Block;
@@ -1935,29 +1938,37 @@
// That should be all
if (mpe != NULL) {
- cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT8");
return FALSE;
}
if (clut == NULL)
clutPoints = 0;
- else
- clutPoints = clut->Params->nSamples[0];
-
- if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->InputChannels)) return FALSE;
- if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) return FALSE;
+ else {
+ // Lut8 only allows same CLUT points in all dimensions
+ clutPoints = clut->Params->nSamples[0];
+ for (i = 1; i < cmsPipelineInputChannels(NewLUT); i++) {
+ if (clut->Params->nSamples[i] != clutPoints) {
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT with different samples per dimension not suitable to be saved as LUT16");
+ return FALSE;
+ }
+ }
+ }
+
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number)cmsPipelineInputChannels(NewLUT))) return FALSE;
+ if (!_cmsWriteUInt8Number(io, (cmsUInt8Number)cmsPipelineOutputChannels(NewLUT))) return FALSE;
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
if (MatMPE != NULL) {
- for (i = 0; i < 9; i++)
- {
- if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
- }
+ for (i = 0; i < 9; i++)
+ {
+ if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
+ }
}
else {
-
+
if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
@@ -2071,11 +2082,11 @@
cmsUInt32Number nEntries;
_cmsAssert(Tables != NULL);
-
- nEntries = Tables->TheCurves[0]->nEntries;
-
+
for (i=0; i < Tables ->nCurves; i++) {
+ nEntries = Tables->TheCurves[i]->nEntries;
+
for (j=0; j < nEntries; j++) {
val = Tables->TheCurves[i]->Table16[j];
@@ -2218,7 +2229,7 @@
// That should be all
if (mpe != NULL) {
- cmsSignalError(mpe->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT is not suitable to be saved as LUT16");
return FALSE;
}
@@ -2227,24 +2238,32 @@
if (clut == NULL)
clutPoints = 0;
- else
- clutPoints = clut->Params->nSamples[0];
+ else {
+ // Lut16 only allows same CLUT points in all dimensions
+ clutPoints = clut->Params->nSamples[0];
+ for (i = 1; i < InputChannels; i++) {
+ if (clut->Params->nSamples[i] != clutPoints) {
+ cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "LUT with different samples per dimension not suitable to be saved as LUT16");
+ return FALSE;
+ }
+ }
+ }
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) InputChannels)) return FALSE;
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) OutputChannels)) return FALSE;
if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) clutPoints)) return FALSE;
if (!_cmsWriteUInt8Number(io, 0)) return FALSE; // Padding
-
+
if (MatMPE != NULL) {
- for (i = 0; i < 9; i++)
- {
- if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
- }
+ for (i = 0; i < 9; i++)
+ {
+ if (!_cmsWrite15Fixed16Number(io, MatMPE->Double[i])) return FALSE;
+ }
}
else {
-
+
if (!_cmsWrite15Fixed16Number(io, 1)) return FALSE;
if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
@@ -2586,31 +2605,31 @@
static
cmsBool WriteMatrix(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsStage* mpe)
{
- cmsUInt32Number i, n;
+ cmsUInt32Number i, n;
_cmsStageMatrixData* m = (_cmsStageMatrixData*) mpe -> Data;
- n = mpe->InputChannels * mpe->OutputChannels;
+ n = mpe->InputChannels * mpe->OutputChannels;
- // Write the Matrix
- for (i = 0; i < n; i++)
- {
- if (!_cmsWrite15Fixed16Number(io, m->Double[i])) return FALSE;
- }
+ // Write the Matrix
+ for (i = 0; i < n; i++)
+ {
+ if (!_cmsWrite15Fixed16Number(io, m->Double[i])) return FALSE;
+ }
- if (m->Offset != NULL) {
+ if (m->Offset != NULL) {
- for (i = 0; i < mpe->OutputChannels; i++)
- {
- if (!_cmsWrite15Fixed16Number(io, m->Offset[i])) return FALSE;
- }
- }
- else {
- for (i = 0; i < mpe->OutputChannels; i++)
- {
- if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
- }
- }
+ for (i = 0; i < mpe->OutputChannels; i++)
+ {
+ if (!_cmsWrite15Fixed16Number(io, m->Offset[i])) return FALSE;
+ }
+ }
+ else {
+ for (i = 0; i < mpe->OutputChannels; i++)
+ {
+ if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE;
+ }
+ }
return TRUE;
@@ -3141,7 +3160,6 @@
static
void *Type_NamedColor_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
{
-
cmsUInt32Number vendorFlag; // Bottom 16 bits for ICC use
cmsUInt32Number count; // Count of named colors
cmsUInt32Number nDeviceCoords; // Num of device coordinates
@@ -3471,7 +3489,6 @@
// Get table count
if (!_cmsReadUInt32Number(io, &Count)) return NULL;
- SizeOfTag -= sizeof(cmsUInt32Number);
// Allocate an empty structure
OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count);
@@ -3489,6 +3506,7 @@
*nItems = 1;
return OutSeq;
+ cmsUNUSED_PARAMETER(SizeOfTag);
}
@@ -3706,7 +3724,7 @@
// Auxiliary, read an string specified as count + string
static
-cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
+cmsBool ReadCountAndString(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, cmsUInt32Number* SizeOfTag, const char* Section)
{
cmsUInt32Number Count;
char* Text;
@@ -3736,7 +3754,7 @@
}
static
-cmsBool WriteCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
+cmsBool WriteCountAndString(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsMLU* mlu, const char* Section)
{
cmsUInt32Number TextSize;
char* Text;
@@ -3760,11 +3778,11 @@
cmsMLU* mlu = cmsMLUalloc(self ->ContextID, 5);
*nItems = 0;
- if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "nm")) goto Error;
- if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#0")) goto Error;
- if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#1")) goto Error;
- if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#2")) goto Error;
- if (!ReadCountAndSting(self, io, mlu, &SizeOfTag, "#3")) goto Error;
+ if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "nm")) goto Error;
+ if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#0")) goto Error;
+ if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#1")) goto Error;
+ if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#2")) goto Error;
+ if (!ReadCountAndString(self, io, mlu, &SizeOfTag, "#3")) goto Error;
*nItems = 1;
return (void*) mlu;
@@ -3781,11 +3799,11 @@
cmsMLU* mlu = (cmsMLU*) Ptr;
- if (!WriteCountAndSting(self, io, mlu, "nm")) goto Error;
- if (!WriteCountAndSting(self, io, mlu, "#0")) goto Error;
- if (!WriteCountAndSting(self, io, mlu, "#1")) goto Error;
- if (!WriteCountAndSting(self, io, mlu, "#2")) goto Error;
- if (!WriteCountAndSting(self, io, mlu, "#3")) goto Error;
+ if (!WriteCountAndString(self, io, mlu, "nm")) goto Error;
+ if (!WriteCountAndString(self, io, mlu, "#0")) goto Error;
+ if (!WriteCountAndString(self, io, mlu, "#1")) goto Error;
+ if (!WriteCountAndString(self, io, mlu, "#2")) goto Error;
+ if (!WriteCountAndString(self, io, mlu, "#3")) goto Error;
return TRUE;
@@ -5383,6 +5401,64 @@
cmsUNUSED_PARAMETER(self);
}
+// cicp VideoSignalType
+
+static
+void* Type_VideoSignal_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag)
+{
+ cmsVideoSignalType* cicp = NULL;
+
+ if (SizeOfTag != 8) return NULL;
+
+ if (!_cmsReadUInt32Number(io, NULL)) return NULL;
+
+ cicp = (cmsVideoSignalType*)_cmsCalloc(self->ContextID, 1, sizeof(cmsVideoSignalType));
+ if (cicp == NULL) return NULL;
+
+ if (!_cmsReadUInt8Number(io, &cicp->ColourPrimaries)) goto Error;
+ if (!_cmsReadUInt8Number(io, &cicp->TransferCharacteristics)) goto Error;
+ if (!_cmsReadUInt8Number(io, &cicp->MatrixCoefficients)) goto Error;
+ if (!_cmsReadUInt8Number(io, &cicp->VideoFullRangeFlag)) goto Error;
+
+ // Success
+ *nItems = 1;
+ return cicp;
+
+Error:
+ if (cicp != NULL) _cmsFree(self->ContextID, cicp);
+ return NULL;
+}
+
+static
+cmsBool Type_VideoSignal_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems)
+{
+ cmsVideoSignalType* cicp = (cmsVideoSignalType*)Ptr;
+
+ if (!_cmsWriteUInt32Number(io, 0)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, cicp->ColourPrimaries)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, cicp->TransferCharacteristics)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, cicp->MatrixCoefficients)) return FALSE;
+ if (!_cmsWriteUInt8Number(io, cicp->VideoFullRangeFlag)) return FALSE;
+
+ return TRUE;
+
+ cmsUNUSED_PARAMETER(self);
+ cmsUNUSED_PARAMETER(nItems);
+}
+
+void* Type_VideoSignal_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n)
+{
+ return _cmsDupMem(self->ContextID, Ptr, sizeof(cmsVideoSignalType));
+
+ cmsUNUSED_PARAMETER(n);
+}
+
+
+static
+void Type_VideoSignal_Free(struct _cms_typehandler_struct* self, void* Ptr)
+{
+ _cmsFree(self->ContextID, Ptr);
+}
// ********************************************************************************
// Type support main routines
@@ -5422,6 +5498,7 @@
{TYPE_HANDLER(cmsMonacoBrokenCurveType, Curve), (_cmsTagTypeLinkedList*) &SupportedTagTypes[28] },
{TYPE_HANDLER(cmsSigProfileSequenceIdType, ProfileSequenceId), (_cmsTagTypeLinkedList*) &SupportedTagTypes[29] },
{TYPE_HANDLER(cmsSigDictType, Dictionary), (_cmsTagTypeLinkedList*) &SupportedTagTypes[30] },
+{TYPE_HANDLER(cmsSigcicpType, VideoSignal), (_cmsTagTypeLinkedList*) &SupportedTagTypes[31] },
{TYPE_HANDLER(cmsSigVcgtType, vcgt), NULL }
};
@@ -5616,6 +5693,8 @@
{ cmsSigProfileSequenceIdTag, { 1, 1, { cmsSigProfileSequenceIdType}, NULL }, &SupportedTags[62]},
{ cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]},
+ { cmsSigcicpTag, { 1, 1, { cmsSigcicpType}, NULL }, &SupportedTags[64]},
+
{ cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL}
};
diff --git a/third_party/lcms/src/cmsvirt.c b/third_party/lcms/src/cmsvirt.c
index bffb88e..b8ef607 100644
--- a/third_party/lcms/src/cmsvirt.c
+++ b/third_party/lcms/src/cmsvirt.c
@@ -114,7 +114,7 @@
if (!hICC) // can't allocate
return NULL;
- cmsSetProfileVersion(hICC, 4.3);
+ cmsSetProfileVersion(hICC, 4.4);
cmsSetDeviceClass(hICC, cmsSigDisplayClass);
cmsSetColorSpace(hICC, cmsSigRgbData);
@@ -235,7 +235,7 @@
if (!hICC) // can't allocate
return NULL;
- cmsSetProfileVersion(hICC, 4.3);
+ cmsSetProfileVersion(hICC, 4.4);
cmsSetDeviceClass(hICC, cmsSigDisplayClass);
cmsSetColorSpace(hICC, cmsSigGrayData);
@@ -291,13 +291,13 @@
{
cmsHPROFILE hICC;
cmsPipeline* Pipeline;
- cmsUInt32Number nChannels;
+ cmsInt32Number nChannels;
hICC = cmsCreateProfilePlaceholder(ContextID);
if (!hICC)
return NULL;
- cmsSetProfileVersion(hICC, 4.3);
+ cmsSetProfileVersion(hICC, 4.4);
cmsSetDeviceClass(hICC, cmsSigLinkClass);
cmsSetColorSpace(hICC, ColorSpace);
@@ -306,7 +306,7 @@
cmsSetHeaderRenderingIntent(hICC, INTENT_PERCEPTUAL);
// Set up channels
- nChannels = cmsChannelsOf(ColorSpace);
+ nChannels = cmsChannelsOfColorSpace(ColorSpace);
// Creates a Pipeline with prelinearization step only
Pipeline = cmsPipelineAlloc(ContextID, nChannels, nChannels);
@@ -397,7 +397,7 @@
cmsHPROFILE hICC;
cmsPipeline* LUT;
cmsStage* CLUT;
- cmsUInt32Number nChannels;
+ cmsInt32Number nChannels;
if (ColorSpace != cmsSigCmykData) {
cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported");
@@ -416,7 +416,7 @@
if (!hICC) // can't allocate
return NULL;
- cmsSetProfileVersion(hICC, 4.3);
+ cmsSetProfileVersion(hICC, 4.4);
cmsSetDeviceClass(hICC, cmsSigLinkClass);
cmsSetColorSpace(hICC, ColorSpace);
@@ -526,7 +526,7 @@
hProfile = cmsCreateRGBProfileTHR(ContextID, WhitePoint == NULL ? cmsD50_xyY() : WhitePoint, NULL, NULL);
if (hProfile == NULL) return NULL;
- cmsSetProfileVersion(hProfile, 4.3);
+ cmsSetProfileVersion(hProfile, 4.4);
cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
cmsSetColorSpace(hProfile, cmsSigLabData);
@@ -572,7 +572,7 @@
hProfile = cmsCreateRGBProfileTHR(ContextID, cmsD50_xyY(), NULL, NULL);
if (hProfile == NULL) return NULL;
- cmsSetProfileVersion(hProfile, 4.3);
+ cmsSetProfileVersion(hProfile, 4.4);
cmsSetDeviceClass(hProfile, cmsSigAbstractClass);
cmsSetColorSpace(hProfile, cmsSigXYZData);
@@ -839,7 +839,7 @@
if (!hProfile) // can't allocate
return NULL;
- cmsSetProfileVersion(hProfile, 4.3);
+ cmsSetProfileVersion(hProfile, 4.4);
if (!SetTextTags(hProfile, L"NULL profile built-in")) goto Error;
@@ -974,7 +974,7 @@
// Make sure we have proper formatters
cmsChangeBuffersFormat(xform, TYPE_NAMED_COLOR_INDEX,
FLOAT_SH(0) | COLORSPACE_SH(_cmsLCMScolorSpace(v ->ExitColorSpace))
- | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOf(v ->ExitColorSpace)));
+ | BYTES_SH(2) | CHANNELS_SH(cmsChannelsOfColorSpace(v ->ExitColorSpace)));
// Apply the transfor to colorants.
for (i=0; i < nColors; i++) {
@@ -1062,8 +1062,9 @@
cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags)
{
cmsHPROFILE hProfile = NULL;
- cmsUInt32Number FrmIn, FrmOut, ChansIn, ChansOut;
- int ColorSpaceBitsIn, ColorSpaceBitsOut;
+ cmsUInt32Number FrmIn, FrmOut;
+ cmsInt32Number ChansIn, ChansOut;
+ int ColorSpaceBitsIn, ColorSpaceBitsOut;
_cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform;
cmsPipeline* LUT = NULL;
cmsStage* mpe;
@@ -1114,8 +1115,8 @@
// Optimize the LUT and precalculate a devicelink
- ChansIn = cmsChannelsOf(xform -> EntryColorSpace);
- ChansOut = cmsChannelsOf(xform -> ExitColorSpace);
+ ChansIn = cmsChannelsOfColorSpace(xform -> EntryColorSpace);
+ ChansOut = cmsChannelsOfColorSpace(xform -> ExitColorSpace);
ColorSpaceBitsIn = _cmsLCMScolorSpace(xform -> EntryColorSpace);
ColorSpaceBitsOut = _cmsLCMScolorSpace(xform -> ExitColorSpace);
diff --git a/third_party/lcms/src/cmsxform.c b/third_party/lcms/src/cmsxform.c
index c7183fc..38ea624 100644
--- a/third_party/lcms/src/cmsxform.c
+++ b/third_party/lcms/src/cmsxform.c
@@ -781,6 +781,73 @@
return CMMcargo->dwOriginalFlags;
}
+// Returns the worker callback for parallelization plug-ins
+_cmsTransform2Fn CMSEXPORT _cmsGetTransformWorker(struct _cmstransform_struct* CMMcargo)
+{
+ _cmsAssert(CMMcargo != NULL);
+ return CMMcargo->Worker;
+}
+
+// This field holds maximum number of workers or -1 to auto
+cmsInt32Number CMSEXPORT _cmsGetTransformMaxWorkers(struct _cmstransform_struct* CMMcargo)
+{
+ _cmsAssert(CMMcargo != NULL);
+ return CMMcargo->MaxWorkers;
+}
+
+// This field is actually unused and reserved
+cmsUInt32Number CMSEXPORT _cmsGetTransformWorkerFlags(struct _cmstransform_struct* CMMcargo)
+{
+ _cmsAssert(CMMcargo != NULL);
+ return CMMcargo->WorkerFlags;
+}
+
+// In the case there is a parallelization plug-in, let it to do its job
+static
+void ParalellizeIfSuitable(_cmsTRANSFORM* p)
+{
+ _cmsParallelizationPluginChunkType* ctx = (_cmsParallelizationPluginChunkType*)_cmsContextGetClientChunk(p->ContextID, ParallelizationPlugin);
+
+ _cmsAssert(p != NULL);
+ if (ctx != NULL && ctx->SchedulerFn != NULL) {
+
+ p->Worker = p->xform;
+ p->xform = ctx->SchedulerFn;
+ p->MaxWorkers = ctx->MaxWorkers;
+ p->WorkerFlags = ctx->WorkerFlags;
+ }
+}
+
+
+/**
+* An empty unroll to avoid a check with NULL on cmsDoTransform()
+*/
+static
+cmsUInt8Number* UnrollNothing(CMSREGISTER _cmsTRANSFORM* info,
+ CMSREGISTER cmsUInt16Number wIn[],
+ CMSREGISTER cmsUInt8Number* accum,
+ CMSREGISTER cmsUInt32Number Stride)
+{
+ return accum;
+
+ cmsUNUSED_PARAMETER(info);
+ cmsUNUSED_PARAMETER(wIn);
+ cmsUNUSED_PARAMETER(Stride);
+}
+
+static
+cmsUInt8Number* PackNothing(CMSREGISTER _cmsTRANSFORM* info,
+ CMSREGISTER cmsUInt16Number wOut[],
+ CMSREGISTER cmsUInt8Number* output,
+ CMSREGISTER cmsUInt32Number Stride)
+{
+ return output;
+
+ cmsUNUSED_PARAMETER(info);
+ cmsUNUSED_PARAMETER(wOut);
+ cmsUNUSED_PARAMETER(Stride);
+}
+
// Allocate transform struct and set it to defaults. Ask the optimization plug-in about if those formats are proper
// for separated transforms. If this is the case,
static
@@ -836,6 +903,7 @@
p->xform = _cmsTransform2toTransformAdaptor;
}
+ ParalellizeIfSuitable(p);
return p;
}
}
@@ -872,8 +940,10 @@
}
else {
+ // Formats are intended to be changed before use
if (*InputFormat == 0 && *OutputFormat == 0) {
- p ->FromInput = p ->ToOutput = NULL;
+ p->FromInput = UnrollNothing;
+ p->ToOutput = PackNothing;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
}
else {
@@ -890,7 +960,7 @@
return NULL;
}
- BytesPerPixelInput = T_BYTES(p ->InputFormat);
+ BytesPerPixelInput = T_BYTES(*InputFormat);
if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2)
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
@@ -924,6 +994,7 @@
p ->dwOriginalFlags = *dwFlags;
p ->ContextID = ContextID;
p ->UserData = NULL;
+ ParalellizeIfSuitable(p);
return p;
}
@@ -1098,8 +1169,8 @@
}
// Check channel count
- if ((cmsChannelsOf(EntryColorSpace) != cmsPipelineInputChannels(Lut)) ||
- (cmsChannelsOf(ExitColorSpace) != cmsPipelineOutputChannels(Lut))) {
+ if ((cmsChannelsOfColorSpace(EntryColorSpace) != (cmsInt32Number) cmsPipelineInputChannels(Lut)) ||
+ (cmsChannelsOfColorSpace(ExitColorSpace) != (cmsInt32Number) cmsPipelineOutputChannels(Lut))) {
cmsPipelineFree(Lut);
cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Channel count doesn't match. Profile is corrupted");
return NULL;
diff --git a/third_party/lcms/src/lcms2_internal.h b/third_party/lcms/src/lcms2_internal.h
index 9eecf6e..4aa98c5 100644
--- a/third_party/lcms/src/lcms2_internal.h
+++ b/third_party/lcms/src/lcms2_internal.h
@@ -283,38 +283,38 @@
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
- EnterCriticalSection(m);
- return 0;
+ EnterCriticalSection(m);
+ return 0;
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
- LeaveCriticalSection(m);
- return 0;
+ LeaveCriticalSection(m);
+ return 0;
}
-
+
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
- InitializeCriticalSection(m);
- return 0;
+ InitializeCriticalSection(m);
+ return 0;
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
- DeleteCriticalSection(m);
- return 0;
+ DeleteCriticalSection(m);
+ return 0;
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
- EnterCriticalSection(m);
- return 0;
+ EnterCriticalSection(m);
+ return 0;
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
- LeaveCriticalSection(m);
- return 0;
+ LeaveCriticalSection(m);
+ return 0;
}
#else
@@ -328,32 +328,32 @@
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
- return pthread_mutex_lock(m);
+ return pthread_mutex_lock(m);
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
- return pthread_mutex_unlock(m);
+ return pthread_mutex_unlock(m);
}
-
+
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
- return pthread_mutex_init(m, NULL);
+ return pthread_mutex_init(m, NULL);
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
- return pthread_mutex_destroy(m);
+ return pthread_mutex_destroy(m);
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
- return pthread_mutex_lock(m);
+ return pthread_mutex_lock(m);
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
- return pthread_mutex_unlock(m);
+ return pthread_mutex_unlock(m);
}
#endif
@@ -366,37 +366,37 @@
cmsINLINE int _cmsLockPrimitive(_cmsMutex *m)
{
cmsUNUSED_PARAMETER(m);
- return 0;
+ return 0;
}
cmsINLINE int _cmsUnlockPrimitive(_cmsMutex *m)
{
cmsUNUSED_PARAMETER(m);
- return 0;
+ return 0;
}
-
+
cmsINLINE int _cmsInitMutexPrimitive(_cmsMutex *m)
{
cmsUNUSED_PARAMETER(m);
- return 0;
+ return 0;
}
cmsINLINE int _cmsDestroyMutexPrimitive(_cmsMutex *m)
{
cmsUNUSED_PARAMETER(m);
- return 0;
+ return 0;
}
cmsINLINE int _cmsEnterCriticalSectionPrimitive(_cmsMutex *m)
{
cmsUNUSED_PARAMETER(m);
- return 0;
+ return 0;
}
cmsINLINE int _cmsLeaveCriticalSectionPrimitive(_cmsMutex *m)
{
cmsUNUSED_PARAMETER(m);
- return 0;
+ return 0;
}
#endif
@@ -438,6 +438,9 @@
// Mutex
cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
+// Paralellization
+cmsBool _cmsRegisterParallelizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin);
+
// ---------------------------------------------------------------------------------------------------------
// Suballocators.
@@ -485,6 +488,7 @@
OptimizationPlugin,
TransformPlugin,
MutexPlugin,
+ ParallelizationPlugin,
// Last in list
MemoryClientMax
@@ -720,6 +724,24 @@
void _cmsAllocMutexPluginChunk(struct _cmsContext_struct* ctx,
const struct _cmsContext_struct* src);
+// Container for parallelization plug-in
+typedef struct {
+
+ cmsInt32Number MaxWorkers; // Number of workers to do as maximum
+ cmsInt32Number WorkerFlags; // reserved
+ _cmsTransform2Fn SchedulerFn; // callback to setup functions
+
+} _cmsParallelizationPluginChunkType;
+
+// The global Context0 storage for parallelization plug-in
+extern _cmsParallelizationPluginChunkType _cmsParallelizationPluginChunk;
+
+// Allocate parallelization container.
+void _cmsAllocParallelizationPluginChunk(struct _cmsContext_struct* ctx,
+ const struct _cmsContext_struct* src);
+
+
+
// ----------------------------------------------------------------------------------
// MLU internal representation
typedef struct {
@@ -1081,6 +1103,11 @@
// A way to provide backwards compatibility with full xform plugins
_cmsTransformFn OldXform;
+ // A one-worker transform entry for parallelization
+ _cmsTransform2Fn Worker;
+ cmsInt32Number MaxWorkers;
+ cmsUInt32Number WorkerFlags;
+
} _cmsTRANSFORM;
// Copies extra channels from input to output if the original flags in the transform structure