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