From 7536819c65f57b2fe682053c8c55fd2062381ab3 Mon Sep 17 00:00:00 2001 From: Ekaterina Vergizova Date: Thu, 21 Aug 2025 20:42:25 +0300 Subject: [PATCH 1/3] Backport 01b213899cb8124860441fa26c9652b4a4bff896 --- THIRD_PARTY_README | 111 +++- .../native/sun/java2d/cmm/lcms/UPDATING.txt | 23 + .../native/sun/java2d/cmm/lcms/cmsalpha.c | 20 +- .../native/sun/java2d/cmm/lcms/cmscam02.c | 2 +- .../native/sun/java2d/cmm/lcms/cmscgats.c | 331 +++++++--- .../native/sun/java2d/cmm/lcms/cmscnvrt.c | 6 +- .../share/native/sun/java2d/cmm/lcms/cmserr.c | 51 +- .../native/sun/java2d/cmm/lcms/cmsgamma.c | 81 ++- .../share/native/sun/java2d/cmm/lcms/cmsgmt.c | 99 ++- .../native/sun/java2d/cmm/lcms/cmshalf.c | 4 +- .../native/sun/java2d/cmm/lcms/cmsintrp.c | 46 +- .../share/native/sun/java2d/cmm/lcms/cmsio0.c | 217 +++++-- .../share/native/sun/java2d/cmm/lcms/cmsio1.c | 13 +- .../share/native/sun/java2d/cmm/lcms/cmslut.c | 9 +- .../share/native/sun/java2d/cmm/lcms/cmsmd5.c | 2 +- .../native/sun/java2d/cmm/lcms/cmsmtrx.c | 2 +- .../native/sun/java2d/cmm/lcms/cmsnamed.c | 12 +- .../share/native/sun/java2d/cmm/lcms/cmsopt.c | 32 +- .../native/sun/java2d/cmm/lcms/cmspack.c | 606 +++++++++++++++--- .../share/native/sun/java2d/cmm/lcms/cmspcs.c | 16 +- .../native/sun/java2d/cmm/lcms/cmsplugin.c | 186 ++++-- .../share/native/sun/java2d/cmm/lcms/cmsps2.c | 6 +- .../native/sun/java2d/cmm/lcms/cmssamp.c | 10 +- .../share/native/sun/java2d/cmm/lcms/cmssm.c | 2 +- .../native/sun/java2d/cmm/lcms/cmstypes.c | 406 ++++++++---- .../native/sun/java2d/cmm/lcms/cmsvirt.c | 35 +- .../native/sun/java2d/cmm/lcms/cmswtpnt.c | 10 +- .../native/sun/java2d/cmm/lcms/cmsxform.c | 94 ++- .../share/native/sun/java2d/cmm/lcms/lcms2.h | 54 +- .../sun/java2d/cmm/lcms/lcms2_internal.h | 80 ++- .../native/sun/java2d/cmm/lcms/lcms2_plugin.h | 26 +- 31 files changed, 2000 insertions(+), 592 deletions(-) create mode 100644 jdk/src/share/native/sun/java2d/cmm/lcms/UPDATING.txt diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README index 2b296592728..4e6995948e9 100644 --- a/THIRD_PARTY_README +++ b/THIRD_PARTY_README @@ -1725,31 +1725,108 @@ THE SOFTWARE. ------------------------------------------------------------------------------- -%% This notice is provided with respect to Little CMS 2.12, which may be +%% This notice is provided with respect to Little CMS 2.14, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- +README.1ST file information + +LittleCMS core is released under MIT License + +--------------------------------- + Little CMS -Copyright (c) 1998-2020 Marti Maria Saguer +Copyright (c) 1998-2022 Marti Maria Saguer -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject +to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +--------------------------------- + +The below license applies to the following files: +liblcms/cmssm.c + +Copyright 2001, softSurfer (www.softsurfer.com) + +This code may be freely used and modified for any purpose +providing that this copyright notice is included with it. +SoftSurfer makes no warranty for this code, and cannot be held +liable for any real or imagined damage resulting from its use. +Users of this code must verify correctness for their application. + + +AUTHORS File Information: + +Main Author +------------ +Marti Maria + + +Contributors +------------ +Bob Friesenhahn +Kai-Uwe Behrmann +Stuart Nixon +Jordi Vilar +Richard Hughes +Auke Nauta +Chris Evans (Google) +Lorenzo Ridolfi +Robin Watts (Artifex) +Shawn Pedersen +Andrew Brygin +Samuli Suominen +Florian Hˆch +Aurelien Jarno +Claudiu Cebuc +Michael Vhrel (Artifex) +Michal Cihar +Daniel Kaneider +Mateusz Jurczyk (Google) +Paul Miller +SÈbastien LÈon +Christian Schmitz +XhmikosR +Stanislav Brabec (SuSe) +Leonhard Gruenschloss (Google) +Patrick Noffke +Christopher James Halse Rogers +John Hein +Thomas Weber (Debian) +Mark Allen +Noel Carboni +Sergei Trofimovic +Philipp Knechtges + +Special Thanks +-------------- +Artifex software +AlienSkin software +Jan Morovic +Jos Vernon (WebSupergoo) +Harald Schneider (Maxon) +Christian Albrecht +Dimitrios Anastassakis +Lemke Software +Tim Zaman -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. --- end of LICENSE --- diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/UPDATING.txt b/jdk/src/share/native/sun/java2d/cmm/lcms/UPDATING.txt new file mode 100644 index 00000000000..01d8b65d2b6 --- /dev/null +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/UPDATING.txt @@ -0,0 +1,23 @@ +# Tips and tasks when updating LittleCMS sources to a newer version. + +Download and unzip latest release from https://sourceforge.net/projects/lcms/files/ +Replace files in jdk/src/share/native/sun/java2d/cmm/lcms with files from unzipped src and include folders +Replace is important because the lcms sources here are just the subset needed by JDK. +This is deliberate, so when updating be sure to import only the same files. +If a file has been removed from upstream you will notice it during the copy. +It should then be removed from the JDK sources. +If a new file is needed then the build will fail. Manually copy that in. + +Some re-editing of these updated files will be needed. +Use "expand" and "sed" to remove tabs and trailing white space from the imported files. +Re-apply the GPL headers used by the JDK. If done correctly these should then not +show up in the PR diff. + +Update THIRD_PARTY_README per the current license/copyrights/attributions etc. + +Build on all platforms. +If there are compiler warnings causing build failures, update the disabled warnings in +jdk/make/lib/Awt2dLibraries.gmk +Run all automated client tests on all platforms. +Also run J2Ddemo and pay particular attention to the "color" tab. +Visually verify the color transforms against the same with the current/previous JDK diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c index 49ff22df764..c6a37e79727 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -220,21 +220,21 @@ static void fromFLTto8(void* dst, const void* src) { cmsFloat32Number n = *(cmsFloat32Number*)src; - *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0); } static void fromFLTto16(void* dst, const void* src) { cmsFloat32Number n = *(cmsFloat32Number*)src; - *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0); } static void fromFLTto16SE(void* dst, const void* src) { cmsFloat32Number n = *(cmsFloat32Number*)src; - cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); + cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0); *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); } @@ -272,7 +272,7 @@ void fromHLFto8(void* dst, const void* src) { #ifndef CMS_NO_HALF_SUPPORT cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); - *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0f); + *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0); #else cmsUNUSED_PARAMETER(dst); cmsUNUSED_PARAMETER(src); @@ -285,7 +285,7 @@ void fromHLFto16(void* dst, const void* src) { #ifndef CMS_NO_HALF_SUPPORT cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); - *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f); + *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0); #else cmsUNUSED_PARAMETER(dst); cmsUNUSED_PARAMETER(src); @@ -297,7 +297,7 @@ void fromHLFto16SE(void* dst, const void* src) { #ifndef CMS_NO_HALF_SUPPORT cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src); - cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f); + cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0); *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i); #else cmsUNUSED_PARAMETER(dst); @@ -443,9 +443,9 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, cmsUInt32Number channelSize = trueBytesSize(Format); cmsUInt32Number pixelSize = channelSize * total_chans; - // Sanity check - if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) - return; + // Sanity check + if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) + return; memset(channels, 0, sizeof(channels)); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c index ba902e06709..23f12419676 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c index 07109b1e449..61d5533e540 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -162,9 +162,18 @@ typedef struct _FileContext { FILE* Stream; // File stream or NULL if holded in memory } FILECTX; -// This struct hold all information about an open IT8 handler. +//Very simple string typedef struct { + struct struct_it8* it8; + cmsInt32Number max; + cmsInt32Number len; + char* begin; + } string; + + +// This struct hold all information about an open IT8 handler. +typedef struct struct_it8 { cmsUInt32Number TablesCount; // How many tables in this stream cmsUInt32Number nTable; // The actual table @@ -182,8 +191,8 @@ typedef struct { cmsInt32Number inum; // integer value cmsFloat64Number dnum; // real value - char id[MAXID]; // identifier - char str[MAXSTR]; // string + string* id; // identifier + string* str; // string // Allowed keywords & datasets. They have visibility on whole stream KEYVALUE* ValidKeywords; @@ -268,7 +277,7 @@ static PROPERTY PredefinedProperties[] = { {"MATERIAL", WRITE_STRINGIFY}, // Identifies the material on which the target was produced using a code // uniquely identifying th e material. This is intend ed to be used for IT8.7 - // physical targets only (i.e . IT8.7/1 a nd IT8.7/2). + // physical targets only (i.e . IT8.7/1 and IT8.7/2). {"INSTRUMENTATION", WRITE_STRINGIFY}, // Used to report the specific instrumentation used (manufacturer and // model number) to generate the data reported. This data will often @@ -383,6 +392,65 @@ static const char* PredefinedSampleID[] = { //Forward declaration of some internal functions static void* AllocChunk(cmsIT8* it8, cmsUInt32Number size); +static +string* StringAlloc(cmsIT8* it8, int max) +{ + string* s = (string*) AllocChunk(it8, sizeof(string)); + if (s == NULL) return NULL; + + s->it8 = it8; + s->max = max; + s->len = 0; + s->begin = (char*) AllocChunk(it8, s->max); + + return s; +} + +static +void StringClear(string* s) +{ + s->len = 0; +} + +static +void StringAppend(string* s, char c) +{ + if (s->len + 1 >= s->max) + { + char* new_ptr; + + s->max *= 10; + 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; + } + + if (s->begin != NULL) + { + s->begin[s->len++] = c; + s->begin[s->len] = 0; + } +} + +static +char* StringPtr(string* s) +{ + return s->begin; +} + +static +void StringCat(string* s, const char* c) +{ + while (*c) + { + StringAppend(s, *c); + c++; + } +} + + // Checks whatever c is a separator static cmsBool isseparator(int c) @@ -708,14 +776,44 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer) } +// Reads a string, special case to avoid infinite resursion on .include +static +void InStringSymbol(cmsIT8* it8) +{ + while (isseparator(it8->ch)) + NextCh(it8); + + if (it8->ch == '\'' || it8->ch == '\"') + { + int sng; + + sng = it8->ch; + StringClear(it8->str); + + NextCh(it8); + + while (it8->ch != sng) { + + if (it8->ch == '\n' || it8->ch == '\r' || it8->ch == 0) break; + else { + StringAppend(it8->str, (char)it8->ch); + NextCh(it8); + } + } + + it8->sy = SSTRING; + NextCh(it8); + } + else + SynError(it8, "String expected"); + +} + // Reads next symbol static void InSymbol(cmsIT8* it8) { - CMSREGISTER char *idptr; - CMSREGISTER int k; SYMBOL key; - int sng; do { @@ -724,21 +822,18 @@ void InSymbol(cmsIT8* it8) if (isfirstidchar(it8->ch)) { // Identifier - k = 0; - idptr = it8->id; + StringClear(it8->id); do { - if (++k < MAXID) *idptr++ = (char) it8->ch; + StringAppend(it8->id, (char) it8->ch); NextCh(it8); } while (isidchar(it8->ch)); - *idptr = '\0'; - - key = BinSrchKey(it8->id); + key = BinSrchKey(StringPtr(it8->id)); if (key == SUNDEFINED) it8->sy = SIDENT; else it8->sy = key; @@ -773,6 +868,7 @@ void InSymbol(cmsIT8* it8) if ((cmsFloat64Number) it8->inum * 16.0 + (cmsFloat64Number) j > (cmsFloat64Number)+2147483647.0) { SynError(it8, "Invalid hexadecimal number"); + it8->sy = SEOF; return; } @@ -794,6 +890,7 @@ void InSymbol(cmsIT8* it8) if ((cmsFloat64Number) it8->inum * 2.0 + j > (cmsFloat64Number)+2147483647.0) { SynError(it8, "Invalid binary number"); + it8->sy = SEOF; return; } @@ -834,26 +931,27 @@ void InSymbol(cmsIT8* it8) if (isidchar(it8 ->ch)) { + char buffer[127]; + if (it8 ->sy == SINUM) { - snprintf(it8->id, 127, "%d", it8->inum); + snprintf(buffer, sizeof(buffer), "%d", it8->inum); } else { - snprintf(it8->id, 127, it8 ->DoubleFormatter, it8->dnum); + snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum); } - k = (int) strlen(it8 ->id); - idptr = it8 ->id + k; + StringCat(it8->id, buffer); + do { - if (++k < MAXID) *idptr++ = (char) it8->ch; + StringAppend(it8->id, (char) it8->ch); NextCh(it8); } while (isidchar(it8->ch)); - *idptr = '\0'; it8->sy = SIDENT; } return; @@ -862,12 +960,8 @@ void InSymbol(cmsIT8* it8) 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; @@ -901,29 +995,13 @@ void InSymbol(cmsIT8* it8) // String. case '\'': case '\"': - idptr = it8->str; - sng = it8->ch; - k = 0; - NextCh(it8); - - while (k < (MAXSTR-1) && it8->ch != sng) { - - if (it8->ch == '\n'|| it8->ch == '\r') k = MAXSTR+1; - else { - *idptr++ = (char) it8->ch; - NextCh(it8); - k++; - } - } - - it8->sy = SSTRING; - *idptr = '\0'; - NextCh(it8); + InStringSymbol(it8); break; default: SynError(it8, "Unrecognized character: 0x%x", it8 ->ch); + it8->sy = SEOF; return; } @@ -938,24 +1016,33 @@ void InSymbol(cmsIT8* it8) if(it8 -> IncludeSP >= (MAXINCLUDE-1)) { SynError(it8, "Too many recursion levels"); + it8->sy = SEOF; return; } - InSymbol(it8); - if (!Check(it8, SSTRING, "Filename expected")) return; + InStringSymbol(it8); + 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(it8->str, + 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; } @@ -963,6 +1050,7 @@ void InSymbol(cmsIT8* it8) if (FileNest->Stream == NULL) { SynError(it8, "File %s not found", FileNest->FileName); + it8->sy = SEOF; return; } it8->IncludeSP++; @@ -1013,12 +1101,12 @@ cmsBool GetVal(cmsIT8* it8, char* Buffer, cmsUInt32Number max, const char* Error case SEOLN: // Empty value Buffer[0]=0; break; - case SIDENT: strncpy(Buffer, it8->id, max); + case SIDENT: strncpy(Buffer, StringPtr(it8->id), max); Buffer[max-1]=0; break; case SINUM: snprintf(Buffer, max, "%d", it8 -> inum); break; case SDNUM: snprintf(Buffer, max, it8->DoubleFormatter, it8 -> dnum); break; - case SSTRING: strncpy(Buffer, it8->str, max); + case SSTRING: strncpy(Buffer, StringPtr(it8->str), max); Buffer[max-1] = 0; break; @@ -1123,9 +1211,12 @@ void* AllocChunk(cmsIT8* it8, cmsUInt32Number size) 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; @@ -1143,7 +1234,7 @@ char *AllocString(cmsIT8* it8, const char* str) ptr = (char *) AllocChunk(it8, Size); - if (ptr) strncpy (ptr, str, Size-1); + if (ptr) memcpy(ptr, str, Size-1); return ptr; } @@ -1342,6 +1433,9 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) it8->IncludeSP = 0; it8 -> lineno = 1; + it8->id = StringAlloc(it8, MAXSTR); + it8->str = StringAlloc(it8, MAXSTR); + strcpy(it8->DoubleFormatter, DEFAULT_DBL_FORMAT); cmsIT8SetSheetType((cmsHANDLE) it8, "CGATS.17"); @@ -1463,28 +1557,45 @@ const char* CMSEXPORT cmsIT8GetPropertyMulti(cmsHANDLE hIT8, const char* Key, co // ----------------------------------------------------------------- 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 @@ -1503,8 +1614,11 @@ cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) { 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."); @@ -1513,6 +1627,7 @@ cmsBool SetDataFormat(cmsIT8* it8, int n, const char *label) if (t->DataFormat) { t->DataFormat[n] = AllocString(it8, label); + if (t->DataFormat[n] == NULL) return FALSE; } return TRUE; @@ -1525,20 +1640,31 @@ cmsBool CMSEXPORT cmsIT8SetDataFormat(cmsHANDLE h, int n, const char *Sample) return SetDataFormat(it8, n, Sample); } -// A safe atoi that returns 0 when NULL input is given +// Convert to binary static -cmsInt32Number satoi(const char* b) +const char* satob(const char* v) { - if (b == NULL) return 0; - return atoi(b); + cmsUInt32Number x; + static char buf[33]; + char *s = buf + 33; + + if (v == NULL) return "0"; + + x = atoi(v); + *--s = 0; + if (!x) *--s = '0'; + for (; x; x /= 2) *--s = '0' + x%2; + + return s; } + 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")); @@ -1546,6 +1672,7 @@ void AllocateDataSet(cmsIT8* it8) 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. @@ -1553,9 +1680,11 @@ void AllocateDataSet(cmsIT8* it8) if (t->Data == NULL) { SynError(it8, "AllocateDataSet: Unable to allocate data array"); + return FALSE; } } + return TRUE; } static @@ -1577,8 +1706,9 @@ cmsBool SetData(cmsIT8* it8, int nSet, int nField, const char *Val) { TABLE* t = GetTable(it8); - if (!t->Data) - AllocateDataSet(it8); + if (!t->Data) { + if (!AllocateDataSet(it8)) return FALSE; + } if (!t->Data) return FALSE; @@ -1718,7 +1848,7 @@ void WriteHeader(cmsIT8* it8, SAVESTREAM* fp) break; case WRITE_BINARY: - Writef(fp, "\t0x%B", satoi(p ->Value)); + Writef(fp, "\t0b%s", satob(p ->Value)); break; case WRITE_PAIR: @@ -1888,7 +2018,7 @@ cmsBool DataFormatSection(cmsIT8* it8) return SynError(it8, "Sample type expected"); } - if (!SetDataFormat(it8, iField, it8->id)) return FALSE; + if (!SetDataFormat(it8, iField, StringPtr(it8->id))) return FALSE; iField++; InSymbol(it8); @@ -1921,8 +2051,9 @@ cmsBool DataSection (cmsIT8* it8) 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) { @@ -1934,11 +2065,28 @@ cmsBool DataSection (cmsIT8* it8) if (it8->sy != SEND_DATA && it8->sy != SEOF) { + switch (it8->sy) + { + + // To keep very long data + case SIDENT: + if (!SetData(it8, iSet, iField, StringPtr(it8->id))) + return FALSE; + break; + + case SSTRING: + if (!SetData(it8, iSet, iField, StringPtr(it8->str))) + return FALSE; + break; + + default: + if (!GetVal(it8, Buffer, 255, "Sample data expected")) return FALSE; if (!SetData(it8, iSet, iField, Buffer)) return FALSE; + } iField++; @@ -1994,7 +2142,7 @@ cmsBool HeaderSection(cmsIT8* it8) case SIDENT: - strncpy(VarName, it8->id, MAXID - 1); + strncpy(VarName, StringPtr(it8->id), MAXID - 1); VarName[MAXID - 1] = 0; if (!IsAvailableOnList(it8->ValidKeywords, VarName, NULL, &Key)) { @@ -2138,7 +2286,7 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) // If a newline is found, then this is a type string if (it8 ->ch == '\n' || it8->ch == '\r') { - cmsIT8SetSheetType(it8, it8 ->id); + cmsIT8SetSheetType(it8, StringPtr(it8 ->id)); InSymbol(it8); } else @@ -2150,7 +2298,7 @@ cmsBool ParseIT8(cmsIT8* it8, cmsBool nosheet) else // Validate quoted strings if (it8 ->sy == SSTRING) { - cmsIT8SetSheetType(it8, it8 ->str); + cmsIT8SetSheetType(it8, StringPtr(it8 ->str)); InSymbol(it8); } } @@ -2452,15 +2600,18 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN } - 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; } @@ -2492,12 +2643,14 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumPropertyMulti(cmsHANDLE hIT8, const char* cP 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; @@ -2673,8 +2826,12 @@ cmsBool CMSEXPORT cmsIT8SetData(cmsHANDLE hIT8, const char* cPatch, const char* if (t-> nPatches == 0) { - AllocateDataFormat(it8); - AllocateDataSet(it8); + if (!AllocateDataFormat(it8)) + return FALSE; + + if (!AllocateDataSet(it8)) + return FALSE; + CookPointers(it8); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c index 4bee13d6491..535a9e12d7e 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -415,7 +415,7 @@ cmsBool ComputeConversion(cmsUInt32Number i, 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); @@ -659,7 +659,7 @@ cmsPipeline* DefaultICCintents(cmsContext ContextID, 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c index 999bc493d21..772a0a169e5 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -108,7 +108,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) // User may override this behaviour by using a memory plug-in, which basically replaces // the default memory management functions. In this case, no check is performed and it -// is up to the plug-in writter to keep in the safe side. There are only three functions +// is up to the plug-in writer to keep in the safe side. There are only three functions // required to be implemented: malloc, realloc and free, although the user may want to // replace the optional mallocZero, calloc and dup as well. @@ -337,7 +337,7 @@ void* CMSEXPORT _cmsDupMem(cmsContext ContextID, const void* Org, cmsUInt32Numbe // Sub allocation takes care of many pointers of small size. The memory allocated in // this way have be freed at once. Next function allocates a single chunk for linked list -// I prefer this method over realloc due to the big inpact on xput realloc may have if +// I prefer this method over realloc due to the big impact on xput realloc may have if // memory is being swapped to disk. This approach is safer (although that may not be true on all platforms) static _cmsSubAllocator_chunk* _cmsCreateSubAllocChunk(cmsContext ContextID, cmsUInt32Number Initial) @@ -642,7 +642,6 @@ cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Data) 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; @@ -690,3 +689,47 @@ void CMSEXPORT _cmsUnlockMutex(cmsContext ContextID, void* mtx) 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c index f266f2e05a6..b5fd47a8ed1 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -236,7 +236,7 @@ _cmsParametricCurvesCollection *GetParametricCurveByType(cmsContext ContextID, i } // Low level allocate, which takes care of memory details. nEntries may be zero, and in this case -// no optimation curve is computed. nSegments may also be zero in the inverse case, where only the +// no optimization curve is computed. nSegments may also be zero in the inverse case, where only the // optimization curve is given. Both features simultaneously is an error static cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEntries, @@ -456,8 +456,8 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // 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) @@ -491,7 +491,8 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // X=-b/a | (Y= disc) { + if (R >= disc) { + + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE || + fabs(Params[1]) < MATRIX_DET_TOLERANCE) + Val = 0; + + else Val = (pow(R, 1.0 / Params[0]) - Params[2]) / Params[1]; - } - else { + } + else { + + if (fabs(Params[3]) < MATRIX_DET_TOLERANCE) + Val = 0; + else Val = R / Params[3]; - } } + } break; @@ -584,26 +588,29 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // X=(Y-f)/c | else case -5: { - if (fabs(Params[1]) < MATRIX_DET_TOLERANCE || - fabs(Params[3]) < MATRIX_DET_TOLERANCE) - { - Val = 0; - } - else - { - disc = Params[3] * Params[4] + Params[6]; - if (R >= disc) { + disc = Params[3] * Params[4] + Params[6]; + if (R >= disc) { + + e = R - Params[5]; + if (e < 0) + Val = 0; + else + { + if (fabs(Params[0]) < MATRIX_DET_TOLERANCE || + fabs(Params[1]) < MATRIX_DET_TOLERANCE) - e = R - Params[5]; - if (e < 0) Val = 0; else Val = (pow(e, 1.0 / Params[0]) - Params[2]) / Params[1]; } - else { + } + else { + if (fabs(Params[3]) < MATRIX_DET_TOLERANCE) + Val = 0; + else Val = (R - Params[6]) / Params[3]; - } } + } break; @@ -624,7 +631,8 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu // ((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; } @@ -1496,6 +1504,9 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num } } + // 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c index 34c9a6c1bf6..60a01aa5088 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2021 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -228,15 +228,15 @@ typedef struct { cmsHTRANSFORM hInput; // From whatever input color space. 16 bits to DBL cmsHTRANSFORM hForward, hReverse; // Transforms going from Lab to colorant and back - cmsFloat64Number Thereshold; // The thereshold after which is considered out of gamut + cmsFloat64Number Threshold; // The threshold after which is considered out of gamut } GAMUTCHAIN; // This sampler does compute gamut boundaries by comparing original -// values with a transform going back and forth. Values above ERR_THERESHOLD +// values with a transform going back and forth. Values above ERR_THRESHOLD // of maximum are considered out of gamut. -#define ERR_THERESHOLD 5 +#define ERR_THRESHOLD 5 static @@ -275,17 +275,17 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu // if dE1 is small and dE2 is small, value is likely to be in gamut - if (dE1 < t->Thereshold && dE2 < t->Thereshold) + if (dE1 < t->Threshold && dE2 < t->Threshold) Out[0] = 0; else { // if dE1 is small and dE2 is big, undefined. Assume in gamut - if (dE1 < t->Thereshold && dE2 > t->Thereshold) + if (dE1 < t->Threshold && dE2 > t->Threshold) Out[0] = 0; else // dE1 is big and dE2 is small, clearly out of gamut - if (dE1 > t->Thereshold && dE2 < t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Thereshold) + .5); + if (dE1 > t->Threshold && dE2 < t->Threshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((dE1 - t->Threshold) + .5); else { // dE1 is big and dE2 is also big, could be due to perceptual mapping @@ -295,8 +295,8 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu else ErrorRatio = dE1 / dE2; - if (ErrorRatio > t->Thereshold) - Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Thereshold) + .5); + if (ErrorRatio > t->Threshold) + Out[0] = (cmsUInt16Number) _cmsQuickFloor((ErrorRatio - t->Threshold) + .5); else Out[0] = 0; } @@ -326,7 +326,8 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, cmsStage* CLUT; cmsUInt32Number dwFormat; GAMUTCHAIN Chain; - cmsUInt32Number nChannels, nGridpoints; + cmsUInt32Number nGridpoints; + cmsInt32Number nChannels; cmsColorSpaceSignature ColorSpace; cmsUInt32Number i; cmsHPROFILE ProfileList[256]; @@ -352,10 +353,10 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, if (cmsIsMatrixShaper(hGamut)) { - Chain.Thereshold = 1.0; + Chain.Threshold = 1.0; } else { - Chain.Thereshold = ERR_THERESHOLD; + Chain.Threshold = ERR_THRESHOLD; } @@ -375,8 +376,7 @@ cmsPipeline* _cmsCreateGamutCheckPipeline(cmsContext ContextID, ColorSpace = cmsGetColorSpace(hGamut); - - nChannels = cmsChannelsOf(ColorSpace); + nChannels = cmsChannelsOfColorSpace(ColorSpace); nGridpoints = _cmsReasonableGridpointsByColorspace(ColorSpace, cmsFLAGS_HIGHRESPRECALC); dwFormat = (CHANNELS_SH(nChannels)|BYTES_SH(2)); @@ -501,6 +501,9 @@ cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile) // 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 @@ -617,3 +620,69 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, return TRUE; } + +// Detect whatever a given ICC profile works in linear (gamma 1.0) space +// Actually, doing that "well" is quite hard, since every component may behave completely different. +// Since the true point of this function is to detect suitable optimizations, I am imposing some requirements +// that simplifies things: only RGB, and only profiles that can got in both directions. +// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma. +// For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned. + +cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold) +{ + cmsContext ContextID; + cmsHPROFILE hXYZ; + cmsHTRANSFORM xform; + cmsToneCurve* Y_curve; + cmsUInt16Number rgb[256][3]; + cmsCIEXYZ XYZ[256]; + cmsFloat32Number Y_normalized[256]; + cmsFloat64Number gamma; + cmsProfileClassSignature cl; + int i; + + if (cmsGetColorSpace(hProfile) != cmsSigRgbData) + return -1; + + cl = cmsGetDeviceClass(hProfile); + if (cl != cmsSigInputClass && cl != cmsSigDisplayClass && + cl != cmsSigOutputClass && cl != cmsSigColorSpaceClass) + return -1; + + 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); + + if (xform == NULL) { // If not RGB or forward direction is not supported, regret with the previous error + + cmsCloseProfile(hXYZ); + return -1; + } + + for (i = 0; i < 256; i++) { + rgb[i][0] = rgb[i][1] = rgb[i][2] = FROM_8_TO_16(i); + } + + cmsDoTransform(xform, rgb, XYZ, 256); + + cmsDeleteTransform(xform); + cmsCloseProfile(hXYZ); + + for (i = 0; i < 256; i++) { + Y_normalized[i] = (cmsFloat32Number) XYZ[i].Y; + } + + Y_curve = cmsBuildTabulatedToneCurveFloat(ContextID, 256, Y_normalized); + if (Y_curve == NULL) + return -1; + + gamma = cmsEstimateGamma(Y_curve, threshold); + + cmsFreeToneCurve(Y_curve); + + return gamma; +} + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c index f2e28af400e..eb1d4aa6ea1 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -406,7 +406,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/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c index 8f2d0130e82..7fe74feafd0 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -229,8 +229,8 @@ void LinLerp1D(CMSREGISTER const cmsUInt16Number Value[], int val3; const cmsUInt16Number* LutTable = (cmsUInt16Number*) p ->Table; - // if last value... - if (Value[0] == 0xffff) { + // if last value or just one point + if (Value[0] == 0xffff || p->Domain[0] == 0) { Output[0] = LutTable[p -> Domain[0]]; } @@ -269,7 +269,7 @@ void LinLerp1Dfloat(const cmsFloat32Number Value[], val2 = fclamp(Value[0]); // if last value... - if (val2 == 1.0) { + if (val2 == 1.0 || p->Domain[0] == 0) { Output[0] = LutTable[p -> Domain[0]]; } else @@ -303,20 +303,34 @@ void Eval1Input(CMSREGISTER const cmsUInt16Number Input[], cmsUInt32Number OutChan; const cmsUInt16Number* LutTable = (cmsUInt16Number*) p16 -> Table; - v = Input[0] * p16 -> Domain[0]; - fk = _cmsToFixedDomain(v); - k0 = FIXED_TO_INT(fk); - rk = (cmsUInt16Number) FIXED_REST_TO_INT(fk); + // if last value... + if (Input[0] == 0xffff || p16->Domain[0] == 0) { + + cmsUInt32Number y0 = p16->Domain[0] * p16->opta[0]; + + for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) { + Output[OutChan] = LutTable[y0 + OutChan]; + } + } + else + { + + v = Input[0] * p16->Domain[0]; + fk = _cmsToFixedDomain(v); + + k0 = FIXED_TO_INT(fk); + rk = (cmsUInt16Number)FIXED_REST_TO_INT(fk); - k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); + k1 = k0 + (Input[0] != 0xFFFFU ? 1 : 0); - K0 = p16 -> opta[0] * k0; - K1 = p16 -> opta[0] * k1; + K0 = p16->opta[0] * k0; + K1 = p16->opta[0] * k1; - for (OutChan=0; OutChan < p16->nOutputs; OutChan++) { + for (OutChan = 0; OutChan < p16->nOutputs; OutChan++) { - Output[OutChan] = LinearInterp(rk, LutTable[K0+OutChan], LutTable[K1+OutChan]); + Output[OutChan] = LinearInterp(rk, LutTable[K0 + OutChan], LutTable[K1 + OutChan]); + } } } @@ -337,12 +351,12 @@ void Eval1InputFloat(const cmsFloat32Number Value[], val2 = fclamp(Value[0]); // if last value... - if (val2 == 1.0) { + 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index 70be6a6ad14..75785355901 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -404,6 +404,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha cmsIOHANDLER* iohandler = NULL; FILE* fm = NULL; cmsInt32Number fileLen; + char mode[4] = { 0,0,0,0 }; _cmsAssert(FileName != NULL); _cmsAssert(AccessMode != NULL); @@ -411,16 +412,49 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha iohandler = (cmsIOHANDLER*) _cmsMallocZero(ContextID, sizeof(cmsIOHANDLER)); if (iohandler == NULL) return NULL; - switch (*AccessMode) { + // Validate access mode + while (*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); @@ -428,12 +462,11 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha 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); @@ -443,8 +476,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromFile(cmsContext ContextID, const cha break; default: - _cmsFree(ContextID, iohandler); - cmsSignalError(ContextID, cmsERROR_FILE, "Unknown access mode '%c'", *AccessMode); + _cmsFree(ContextID, iohandler); // Would never reach return NULL; } @@ -471,7 +503,7 @@ cmsIOHANDLER* CMSEXPORT cmsOpenIOhandlerFromStream(cmsContext ContextID, FILE* S cmsIOHANDLER* iohandler = NULL; cmsInt32Number fileSize; - fileSize = cmsfilelength(Stream); + fileSize = (cmsInt32Number)cmsfilelength(Stream); if (fileSize < 0) { cmsSignalError(ContextID, cmsERROR_FILE, "Cannot get size of stream"); @@ -508,16 +540,15 @@ cmsBool CMSEXPORT cmsCloseIOhandler(cmsIOHANDLER* io) cmsIOHANDLER* CMSEXPORT cmsGetProfileIOhandler(cmsHPROFILE hProfile) { - _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile; + _cmsICCPROFILE* Icc = (_cmsICCPROFILE*)hProfile; - if (Icc == NULL) return NULL; - return Icc->IOhandler; + if (Icc == NULL) return NULL; + return Icc->IOhandler; } // Creates an empty structure holding all required parameters cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) { - time_t now = time(NULL); _cmsICCPROFILE* Icc = (_cmsICCPROFILE*) _cmsMallocZero(ContextID, sizeof(_cmsICCPROFILE)); if (Icc == NULL) return NULL; @@ -529,14 +560,22 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set default version Icc ->Version = 0x02100000; + // Set default device class + Icc->DeviceClass = cmsSigDisplayClass; + // Set creation date/time - memmove(&Icc ->Created, gmtime(&now), sizeof(Icc ->Created)); + if (!_cmsGetTime(&Icc->Created)) + goto Error; // Create a mutex if the user provided proper plugin. NULL otherwise Icc ->UsrMutex = _cmsCreateMutex(ContextID); // Return the handle return (cmsHPROFILE) Icc; + +Error: + _cmsFree(ContextID, Icc); + return NULL; } cmsContext CMSEXPORT cmsGetProfileContextID(cmsHPROFILE hProfile) @@ -682,6 +721,27 @@ cmsBool CMSEXPORT cmsIsTag(cmsHPROFILE hProfile, cmsTagSignature sig) 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. @@ -707,6 +767,29 @@ cmsUInt32Number _validatedVersion(cmsUInt32Number DWord) 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) { @@ -743,6 +826,16 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) _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); @@ -776,6 +869,7 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) 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; @@ -790,7 +884,12 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) if ((Icc ->TagOffsets[j] == Tag.offset) && (Icc ->TagSizes[j] == Tag.size)) { - 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]; + } } } @@ -798,6 +897,19 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) 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; } @@ -1459,7 +1571,25 @@ cmsBool CMSEXPORT cmsSaveProfileToMem(cmsHPROFILE hProfile, void *MemPtr, cmsUIn return rc; } +// Free one tag contents +static +void freeOneTag(_cmsICCPROFILE* Icc, cmsUInt32Number i) +{ + if (Icc->TagPtrs[i]) { + + cmsTagTypeHandler* TypeHandler = Icc->TagTypeHandlers[i]; + if (TypeHandler != NULL) { + cmsTagTypeHandler LocalTypeHandler = *TypeHandler; + + LocalTypeHandler.ContextID = Icc->ContextID; + LocalTypeHandler.ICCVersion = Icc->Version; + LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc->TagPtrs[i]); + } + else + _cmsFree(Icc->ContextID, Icc->TagPtrs[i]); + } +} // Closes a profile freeing any involved resources cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) @@ -1479,20 +1609,7 @@ cmsBool CMSEXPORT cmsCloseProfile(cmsHPROFILE hProfile) for (i=0; i < Icc -> TagCount; i++) { - if (Icc -> TagPtrs[i]) { - - cmsTagTypeHandler* TypeHandler = Icc ->TagTypeHandlers[i]; - - if (TypeHandler != NULL) { - cmsTagTypeHandler LocalTypeHandler = *TypeHandler; - - LocalTypeHandler.ContextID = Icc ->ContextID; // As an additional parameters - LocalTypeHandler.ICCVersion = Icc ->Version; - LocalTypeHandler.FreePtr(&LocalTypeHandler, Icc -> TagPtrs[i]); - } - else - _cmsFree(Icc ->ContextID, Icc ->TagPtrs[i]); - } + freeOneTag(Icc, i); } if (Icc ->IOhandler != NULL) { @@ -1544,8 +1661,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) if (!_cmsLockMutex(Icc->ContextID, Icc ->UsrMutex)) return NULL; n = _cmsSearchTag(Icc, sig, TRUE); - if (n < 0) goto Error; // Not found, return NULL - + if (n < 0) + { + // Not found, return NULL + _cmsUnlockMutex(Icc->ContextID, Icc->UsrMutex); + return NULL; + } // If the element is already in memory, return the pointer if (Icc -> TagPtrs[n]) { @@ -1573,6 +1694,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) if (TagSize < 8) goto Error; + 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; @@ -1640,8 +1767,12 @@ void* CMSEXPORT cmsReadTag(cmsHPROFILE hProfile, cmsTagSignature sig) return Icc -> TagPtrs[n]; - // Return error and unlock tha data + // Return error and unlock the data Error: + + freeOneTag(Icc, n); + Icc->TagPtrs[n] = NULL; + _cmsUnlockMutex(Icc->ContextID, Icc ->UsrMutex); return NULL; } @@ -1780,11 +1911,9 @@ cmsBool CMSEXPORT cmsWriteTag(cmsHPROFILE hProfile, cmsTagSignature sig, const v } -// 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) { @@ -1798,24 +1927,29 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si 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, // It is already read? if (Icc -> TagPtrs[i] == NULL) { - // No yet, get original position + // Not yet, get original position Offset = Icc ->TagOffsets[i]; 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; @@ -1830,13 +1964,14 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si // 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); @@ -1849,7 +1984,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si } // 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); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c index 23f32108a81..85d9f6788b5 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -289,7 +289,7 @@ cmsPipeline* BuildRGBInputMatrixShaper(cmsHPROFILE hProfile) -// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded +// Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed static cmsPipeline* _cmsReadFloatInputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) { @@ -351,10 +351,8 @@ cmsPipeline* CMSEXPORT _cmsReadInputLUT(cmsHPROFILE hProfile, cmsUInt32Number In if (nc == NULL) return NULL; Lut = cmsPipelineAlloc(ContextID, 0, 0); - if (Lut == NULL) { - cmsFreeNamedColorList(nc); + if (Lut == NULL) return NULL; - } if (!cmsPipelineInsertStage(Lut, cmsAT_BEGIN, _cmsStageAllocNamedColor(nc, TRUE)) || !cmsPipelineInsertStage(Lut, cmsAT_END, _cmsStageAllocLabV2ToV4(ContextID))) { @@ -565,7 +563,7 @@ void ChangeInterpolationToTrilinear(cmsPipeline* Lut) } -// Read the DToAX tag, adjusting the encoding of Lab or XYZ if neded +// Read the DToAX tag, adjusting the encoding of Lab or XYZ if needed static cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) { @@ -690,7 +688,7 @@ cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number I // --------------------------------------------------------------------------------------------------------------- -// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if neded +// Read the AToD0 tag, adjusting the encoding of Lab or XYZ if needed static cmsPipeline* _cmsReadFloatDevicelinkTag(cmsHPROFILE hProfile, cmsTagSignature tagFloat) { @@ -769,7 +767,6 @@ cmsPipeline* CMSEXPORT _cmsReadDevicelinkLUT(cmsHPROFILE hProfile, cmsUInt32Numb return Lut; Error: cmsPipelineFree(Lut); - cmsFreeNamedColorList(nc); return NULL; } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c index 6eb803fe558..457ab6ecf5c 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -496,7 +496,7 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) for (rv = 1; b > 0; b--) { dim = Dims[b-1]; - if (dim == 0) return 0; // Error + if (dim <= 1) return 0; // Error rv *= dim; @@ -1255,6 +1255,11 @@ void* CMSEXPORT cmsStageData(const cmsStage* mpe) return mpe -> Data; } +cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe) +{ + return mpe -> ContextID; +} + cmsStage* CMSEXPORT cmsStageNext(const cmsStage* mpe) { return mpe -> Next; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c index 2c37b34ea15..ea97c0d8774 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c index 6bf18e0b798..9bbe82871f5 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c index 95a3b5ef8e1..c710ba39372 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -233,7 +233,7 @@ void strFrom16(char str[3], cmsUInt16Number n) } // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) -// In the case the user explicitely sets an empty string, we force a \0 +// In the case the user explicitly sets an empty string, we force a \0 cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) { cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); @@ -571,8 +571,12 @@ cmsBool GrowNamedColorList(cmsNAMEDCOLORLIST* v) // 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; @@ -670,7 +674,7 @@ cmsUInt32Number CMSEXPORT cmsNamedColorCount(const cmsNAMEDCOLORLIST* NamedColor return NamedColorList ->nColors; } -// Info aboout a given color +// Info about a given color cmsBool CMSEXPORT cmsNamedColorInfo(const cmsNAMEDCOLORLIST* NamedColorList, cmsUInt32Number nColor, char* Name, char* Prefix, diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c index e83b2e0be6d..e32f73b86ee 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -676,7 +676,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 { cmsPipeline* Src = NULL; cmsPipeline* Dest = NULL; - cmsStage* mpe; cmsStage* CLUT; cmsStage *KeepPreLin = NULL, *KeepPostLin = NULL; cmsUInt32Number nGridPoints; @@ -698,7 +697,7 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 if (ColorSpace == (cmsColorSpaceSignature)0 || OutputColorSpace == (cmsColorSpaceSignature)0) return FALSE; - nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); + nGridPoints = _cmsReasonableGridpointsByColorspace(ColorSpace, *dwFlags); // For empty LUTs, 2 points are enough if (cmsPipelineStageCount(*Lut) == 0) @@ -706,13 +705,6 @@ cmsBool OptimizeByResampling(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 Src = *Lut; - // Named color pipelines cannot be optimized either - for (mpe = cmsPipelineGetPtrToFirstStage(Src); - mpe != NULL; - mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; - } - // Allocate an empty LUT Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels); if (!Dest) return FALSE; @@ -1080,7 +1072,6 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte cmsStage* OptimizedCLUTmpe; cmsColorSpaceSignature ColorSpace, OutputColorSpace; cmsStage* OptimizedPrelinMpe; - cmsStage* mpe; cmsToneCurve** OptimizedPrelinCurves; _cmsStageCLutData* OptimizedPrelinCLUT; @@ -1102,13 +1093,6 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte OriginalLut = *Lut; - // Named color pipelines cannot be optimized either - for (mpe = cmsPipelineGetPtrToFirstStage(OriginalLut); - mpe != NULL; - mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; - } - ColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*InputFormat)); OutputColorSpace = _cmsICCcolorSpace((int) T_COLORSPACE(*OutputFormat)); @@ -1562,10 +1546,10 @@ void* DupMatShaper(cmsContext ContextID, const void* Data) } -// 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) @@ -1947,6 +1931,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, _cmsOptimizationPluginChunkType* ctx = ( _cmsOptimizationPluginChunkType*) _cmsContextGetClientChunk(ContextID, OptimizationPlugin); _cmsOptimizationCollection* Opts; cmsBool AnySuccess = FALSE; + cmsStage* mpe; // A CLUT is being asked, so force this specific optimization if (*dwFlags & cmsFLAGS_FORCE_CLUT) { @@ -1961,6 +1946,13 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, return TRUE; } + // Named color pipelines cannot be optimized + for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut); + mpe != NULL; + mpe = cmsStageNext(mpe)) { + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + } + // Try to get rid of identities and trivial conversions. AnySuccess = PreOptimize(*PtrLut); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c index 0ec3edab5d5..e90e45656fc 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -108,6 +108,7 @@ typedef struct { #define ANYSWAP DOSWAP_SH(1) #define ANYSWAPFIRST SWAPFIRST_SH(1) #define ANYFLAVOR FLAVOR_SH(1) +#define ANYPREMUL PREMUL_SH(1) // Suppress waning about info never being used @@ -131,20 +132,40 @@ cmsUInt8Number* UnrollChunkyBytes(CMSREGISTER _cmsTRANSFORM* info, cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number Premul = T_PREMUL(info->InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; - cmsUInt16Number v; + cmsUInt32Number v; cmsUInt32Number i; + cmsUInt32Number alpha_factor = 1; if (ExtraFirst) { + + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0])); + accum += Extra; } + else + { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[nChan])); + } for (i=0; i < nChan; i++) { + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; v = FROM_8_TO_16(*accum); v = Reverse ? REVERSE_FLAVOR_16(v) : v; - wIn[index] = v; + + if (Premul && alpha_factor > 0) + { + v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor); + if (v > 0xffff) v = 0xffff; + } + + wIn[index] = (cmsUInt16Number) v; accum++; } @@ -166,6 +187,7 @@ cmsUInt8Number* UnrollChunkyBytes(CMSREGISTER _cmsTRANSFORM* info, } + // Extra channels are just ignored because come in the next planes static cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, @@ -178,24 +200,47 @@ cmsUInt8Number* UnrollPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->InputFormat); cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); cmsUInt32Number i; + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Extra = T_EXTRA(info->InputFormat); + cmsUInt32Number Premul = T_PREMUL(info->InputFormat); cmsUInt8Number* Init = accum; + cmsUInt32Number alpha_factor = 1; - if (DoSwap ^ SwapFirst) { - accum += T_EXTRA(info -> InputFormat) * Stride; + if (ExtraFirst) { + + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[0])); + + + accum += Extra * Stride; + } + else + { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(accum[(nChan) * Stride])); } for (i=0; i < nChan; i++) { cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; - cmsUInt16Number v = FROM_8_TO_16(*accum); + cmsUInt32Number v = FROM_8_TO_16(*accum); - wIn[index] = Reverse ? REVERSE_FLAVOR_16(v) : v; + v = Reverse ? REVERSE_FLAVOR_16(v) : v; + + if (Premul && alpha_factor > 0) + { + v = ((cmsUInt32Number)((cmsUInt32Number)v << 16) / alpha_factor); + if (v > 0xffff) v = 0xffff; + } + + wIn[index] = (cmsUInt16Number) v; accum += Stride; } return (Init + 1); } + // Special cases, provided for performance static cmsUInt8Number* Unroll4Bytes(CMSREGISTER _cmsTRANSFORM* info, @@ -546,6 +591,58 @@ cmsUInt8Number* UnrollAnyWords(CMSREGISTER _cmsTRANSFORM* info, cmsUNUSED_PARAMETER(Stride); } + +static +cmsUInt8Number* UnrollAnyWordsPremul(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number i; + + cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[nChan - 1]); + cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha)); + + if (ExtraFirst) { + accum += sizeof(cmsUInt16Number); + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + cmsUInt32Number v = *(cmsUInt16Number*) accum; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + if (alpha_factor > 0) { + + v = (v << 16) / alpha_factor; + if (v > 0xffff) v = 0xffff; + } + + wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v); + + accum += sizeof(cmsUInt16Number); + } + + if (!ExtraFirst) { + accum += sizeof(cmsUInt16Number); + } + + return accum; + + cmsUNUSED_PARAMETER(Stride); +} + + + static cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info, CMSREGISTER cmsUInt16Number wIn[], @@ -579,6 +676,49 @@ cmsUInt8Number* UnrollPlanarWords(CMSREGISTER _cmsTRANSFORM* info, return (Init + sizeof(cmsUInt16Number)); } +static +cmsUInt8Number* UnrollPlanarWordsPremul(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wIn[], + CMSREGISTER cmsUInt8Number* accum, + CMSREGISTER cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); + cmsUInt32Number DoSwap= T_DOSWAP(info ->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat); + cmsUInt32Number Reverse= T_FLAVOR(info ->InputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info -> InputFormat); + cmsUInt32Number i; + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt8Number* Init = accum; + + cmsUInt16Number alpha = (ExtraFirst ? accum[0] : accum[(nChan - 1) * Stride]); + cmsUInt32Number alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(alpha)); + + if (ExtraFirst) { + accum += Stride; + } + + for (i=0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + cmsUInt32Number v = (cmsUInt32Number) *(cmsUInt16Number*) accum; + + if (SwapEndian) + v = CHANGE_ENDIAN(v); + + if (alpha_factor > 0) { + + v = (v << 16) / alpha_factor; + if (v > 0xffff) v = 0xffff; + } + + wIn[index] = (cmsUInt16Number) (Reverse ? REVERSE_FLAVOR_16(v) : v); + + accum += Stride; + } + + return (Init + sizeof(cmsUInt16Number)); +} static cmsUInt8Number* Unroll4Words(CMSREGISTER _cmsTRANSFORM* info, @@ -1116,6 +1256,110 @@ cmsUInt8Number* UnrollDouble1Chan(CMSREGISTER _cmsTRANSFORM* info, //------------------------------------------------------------------------------------------------------------------- +// For anything going from cmsUInt8Number +static +cmsUInt8Number* Unroll8ToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info->InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat); + cmsUInt32Number Extra = T_EXTRA(info->InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info->InputFormat); + cmsFloat32Number v; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->InputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[(i + start) * Stride]; + else + v = (cmsFloat32Number) ((cmsUInt8Number *)accum)[i + start]; + + v /= 255.0F; + + wIn[index] = Reverse ? 1 - v : v; + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number)); + wIn[nChan - 1] = tmp; + } + + if (T_PLANAR(info->InputFormat)) + return accum + sizeof(cmsUInt8Number); + else + return accum + (nChan + Extra) * sizeof(cmsUInt8Number); +} + + +// For anything going from cmsUInt16Number +static +cmsUInt8Number* Unroll16ToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + + cmsUInt32Number nChan = T_CHANNELS(info->InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat); + cmsUInt32Number Extra = T_EXTRA(info->InputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Planar = T_PLANAR(info->InputFormat); + cmsFloat32Number v; + cmsUInt32Number i, start = 0; + + Stride /= PixelSize(info->InputFormat); + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + if (Planar) + v = (cmsFloat32Number)((cmsUInt16Number*)accum)[(i + start) * Stride]; + else + v = (cmsFloat32Number)((cmsUInt16Number*)accum)[i + start]; + + v /= 65535.0F; + + wIn[index] = Reverse ? 1 - v : v; + } + + + if (Extra == 0 && SwapFirst) { + cmsFloat32Number tmp = wIn[0]; + + memmove(&wIn[0], &wIn[1], (nChan - 1) * sizeof(cmsFloat32Number)); + wIn[nChan - 1] = tmp; + } + + if (T_PLANAR(info->InputFormat)) + return accum + sizeof(cmsUInt16Number); + else + return accum + (nChan + Extra) * sizeof(cmsUInt16Number); +} + + // For anything going from cmsFloat32Number static cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, @@ -1124,19 +1368,30 @@ cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, cmsUInt32Number Stride) { - cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); - cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); - cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); - cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); - cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number nChan = T_CHANNELS(info->InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat); + cmsUInt32Number Extra = T_EXTRA(info->InputFormat); cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; - cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsUInt32Number Planar = T_PLANAR(info->InputFormat); + cmsUInt32Number Premul = T_PREMUL(info->InputFormat); cmsFloat32Number v; cmsUInt32Number i, start = 0; - cmsFloat32Number maximum = IsInkSpace(info ->InputFormat) ? 100.0F : 1.0F; + cmsFloat32Number maximum = IsInkSpace(info->InputFormat) ? 100.0F : 1.0F; + cmsFloat32Number alpha_factor = 1.0f; + cmsFloat32Number* ptr = (cmsFloat32Number*)accum; Stride /= PixelSize(info->InputFormat); + if (Premul && Extra) + { + if (Planar) + alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan * Stride]) / maximum; + else + alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum; + } + if (ExtraFirst) start = Extra; @@ -1145,9 +1400,12 @@ cmsUInt8Number* UnrollFloatsToFloat(_cmsTRANSFORM* info, cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; if (Planar) - v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[(i + start) * Stride]; + v = ptr[(i + start) * Stride]; else - v = (cmsFloat32Number) ((cmsFloat32Number*) accum)[i + start]; + v = ptr[i + start]; + + if (Premul && alpha_factor > 0) + v /= alpha_factor; v /= maximum; @@ -1177,19 +1435,30 @@ cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, cmsUInt32Number Stride) { - cmsUInt32Number nChan = T_CHANNELS(info -> InputFormat); - cmsUInt32Number DoSwap = T_DOSWAP(info ->InputFormat); - cmsUInt32Number Reverse = T_FLAVOR(info ->InputFormat); - cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> InputFormat); - cmsUInt32Number Extra = T_EXTRA(info -> InputFormat); + cmsUInt32Number nChan = T_CHANNELS(info->InputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->InputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->InputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->InputFormat); + cmsUInt32Number Extra = T_EXTRA(info->InputFormat); cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; - cmsUInt32Number Planar = T_PLANAR(info -> InputFormat); + cmsUInt32Number Planar = T_PLANAR(info->InputFormat); + cmsUInt32Number Premul = T_PREMUL(info->InputFormat); cmsFloat64Number v; cmsUInt32Number i, start = 0; cmsFloat64Number maximum = IsInkSpace(info ->InputFormat) ? 100.0 : 1.0; + cmsFloat64Number alpha_factor = 1.0; + cmsFloat64Number* ptr = (cmsFloat64Number*)accum; Stride /= PixelSize(info->InputFormat); + if (Premul && Extra) + { + if (Planar) + alpha_factor = (ExtraFirst ? ptr[0] : ptr[(nChan) * Stride]) / maximum; + else + alpha_factor = (ExtraFirst ? ptr[0] : ptr[nChan]) / maximum; + } + if (ExtraFirst) start = Extra; @@ -1202,6 +1471,10 @@ cmsUInt8Number* UnrollDoublesToFloat(_cmsTRANSFORM* info, else v = (cmsFloat64Number) ((cmsFloat64Number*) accum)[i + start]; + + if (Premul && alpha_factor > 0) + v /= alpha_factor; + v /= maximum; wIn[index] = (cmsFloat32Number) (Reverse ? 1.0 - v : v); @@ -1283,8 +1556,6 @@ cmsUInt8Number* UnrollLabFloatToFloat(_cmsTRANSFORM* info, } } - - // 1.15 fixed point, that means maximum value is MAX_ENCODEABLE_XYZ (0xFFFF) static cmsUInt8Number* UnrollXYZDoubleToFloat(_cmsTRANSFORM* info, @@ -1345,44 +1616,132 @@ cmsUInt8Number* UnrollXYZFloatToFloat(_cmsTRANSFORM* info, } +cmsINLINE void lab4toFloat(cmsFloat32Number wIn[], cmsUInt16Number lab4[3]) +{ + cmsFloat32Number L = (cmsFloat32Number) lab4[0] / 655.35F; + cmsFloat32Number a = ((cmsFloat32Number) lab4[1] / 257.0F) - 128.0F; + cmsFloat32Number b = ((cmsFloat32Number) lab4[2] / 257.0F) - 128.0F; + + wIn[0] = (L / 100.0F); // from 0..100 to 0..1 + wIn[1] = ((a + 128.0F) / 255.0F); // form -128..+127 to 0..1 + wIn[2] = ((b + 128.0F) / 255.0F); + +} + +static +cmsUInt8Number* UnrollLabV2_8ToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsUInt16Number lab4[3]; + + lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L + lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a + lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b + + lab4toFloat(wIn, lab4); + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* UnrollALabV2_8ToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsUInt16Number lab4[3]; + + accum++; // A + lab4[0] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // L + lab4[1] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // a + lab4[2] = FomLabV2ToLabV4(FROM_8_TO_16(*accum)); accum++; // b + + lab4toFloat(wIn, lab4); + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + +static +cmsUInt8Number* UnrollLabV2_16ToFloat(_cmsTRANSFORM* info, + cmsFloat32Number wIn[], + cmsUInt8Number* accum, + cmsUInt32Number Stride) +{ + cmsUInt16Number lab4[3]; + + lab4[0] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // L + lab4[1] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // a + lab4[2] = FomLabV2ToLabV4(*(cmsUInt16Number*) accum); accum += 2; // b + + lab4toFloat(wIn, lab4); + + return accum; + + cmsUNUSED_PARAMETER(info); + cmsUNUSED_PARAMETER(Stride); +} + // Packing routines ----------------------------------------------------------------------------------------------------------- // Generic chunky for byte - static -cmsUInt8Number* PackAnyBytes(CMSREGISTER _cmsTRANSFORM* info, - CMSREGISTER cmsUInt16Number wOut[], - CMSREGISTER cmsUInt8Number* output, - CMSREGISTER cmsUInt32Number Stride) +cmsUInt8Number* PackChunkyBytes(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) { - cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); - cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); - cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); - cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat); - cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat); + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Premul = T_PREMUL(info->OutputFormat); cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; cmsUInt8Number* swap1; - cmsUInt8Number v = 0; + cmsUInt16Number v = 0; cmsUInt32Number i; + cmsUInt32Number alpha_factor = 0; swap1 = output; if (ExtraFirst) { + + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0])); + output += Extra; } + else + { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan])); + } for (i=0; i < nChan; i++) { cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; - v = FROM_16_TO_8(wOut[index]); + v = wOut[index]; if (Reverse) - v = REVERSE_FLAVOR_8(v); + v = REVERSE_FLAVOR_16(v); + + if (Premul && alpha_factor != 0) + { + v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); + } - *output++ = v; + *output++ = FROM_16_TO_8(v); } if (!ExtraFirst) { @@ -1392,39 +1751,47 @@ cmsUInt8Number* PackAnyBytes(CMSREGISTER _cmsTRANSFORM* info, if (Extra == 0 && SwapFirst) { memmove(swap1 + 1, swap1, nChan-1); - *swap1 = v; + *swap1 = FROM_16_TO_8(v); } - return output; cmsUNUSED_PARAMETER(Stride); } - - static -cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info, - CMSREGISTER cmsUInt16Number wOut[], - CMSREGISTER cmsUInt8Number* output, - CMSREGISTER cmsUInt32Number Stride) +cmsUInt8Number* PackChunkyWords(CMSREGISTER _cmsTRANSFORM* info, + CMSREGISTER cmsUInt16Number wOut[], + CMSREGISTER cmsUInt8Number* output, + CMSREGISTER cmsUInt32Number Stride) { - cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); - cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat); - cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); - cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); - cmsUInt32Number Extra = T_EXTRA(info -> OutputFormat); - cmsUInt32Number SwapFirst = T_SWAPFIRST(info -> OutputFormat); + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Premul = T_PREMUL(info->OutputFormat); cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; cmsUInt16Number* swap1; cmsUInt16Number v = 0; cmsUInt32Number i; + cmsUInt32Number alpha_factor = 0; swap1 = (cmsUInt16Number*) output; if (ExtraFirst) { + + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(*(cmsUInt16Number*) output); + output += Extra * sizeof(cmsUInt16Number); } + else + { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[nChan]); + } for (i=0; i < nChan; i++) { @@ -1438,6 +1805,11 @@ cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); + if (Premul && alpha_factor != 0) + { + v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); + } + *(cmsUInt16Number*) output = v; output += sizeof(cmsUInt16Number); @@ -1453,38 +1825,60 @@ cmsUInt8Number* PackAnyWords(CMSREGISTER _cmsTRANSFORM* info, *swap1 = v; } - return output; cmsUNUSED_PARAMETER(Stride); } + static cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, CMSREGISTER cmsUInt16Number wOut[], CMSREGISTER cmsUInt8Number* output, CMSREGISTER cmsUInt32Number Stride) { - cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); - cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); - cmsUInt32Number SwapFirst = T_SWAPFIRST(info ->OutputFormat); - cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Premul = T_PREMUL(info->OutputFormat); cmsUInt32Number i; cmsUInt8Number* Init = output; + cmsUInt32Number alpha_factor = 0; + + + if (ExtraFirst) { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[0])); - if (DoSwap ^ SwapFirst) { - output += T_EXTRA(info -> OutputFormat) * Stride; + output += Extra * Stride; + } + else + { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(FROM_8_TO_16(output[nChan * Stride])); } for (i=0; i < nChan; i++) { cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; - cmsUInt8Number v = FROM_16_TO_8(wOut[index]); + cmsUInt16Number v = wOut[index]; + + if (Reverse) + v = REVERSE_FLAVOR_16(v); + + if (Premul && alpha_factor != 0) + { + v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); + } + + *(cmsUInt8Number*)output = FROM_16_TO_8(v); - *(cmsUInt8Number*) output = (cmsUInt8Number) (Reverse ? REVERSE_FLAVOR_8(v) : v); output += Stride; } @@ -1500,16 +1894,30 @@ cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info, CMSREGISTER cmsUInt8Number* output, CMSREGISTER cmsUInt32Number Stride) { - cmsUInt32Number nChan = T_CHANNELS(info -> OutputFormat); - cmsUInt32Number DoSwap = T_DOSWAP(info ->OutputFormat); - cmsUInt32Number Reverse = T_FLAVOR(info ->OutputFormat); - cmsUInt32Number SwapEndian = T_ENDIAN16(info -> OutputFormat); + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt32Number Premul = T_PREMUL(info->OutputFormat); + cmsUInt32Number SwapEndian = T_ENDIAN16(info->OutputFormat); cmsUInt32Number i; cmsUInt8Number* Init = output; cmsUInt16Number v; + cmsUInt32Number alpha_factor = 0; - if (DoSwap) { - output += T_EXTRA(info -> OutputFormat) * Stride; + if (ExtraFirst) { + + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*) output)[0]); + + output += Extra * Stride; + } + else + { + if (Premul && Extra) + alpha_factor = _cmsToFixedDomain(((cmsUInt16Number*)output)[nChan * Stride]); } for (i=0; i < nChan; i++) { @@ -1524,6 +1932,11 @@ cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); + if (Premul && alpha_factor != 0) + { + v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); + } + *(cmsUInt16Number*) output = v; output += Stride; } @@ -2670,10 +3083,6 @@ cmsUInt8Number* PackDoublesFromFloat(_cmsTRANSFORM* info, } - - - - static cmsUInt8Number* PackLabFloatFromFloat(_cmsTRANSFORM* Info, cmsFloat32Number wOut[], @@ -3058,10 +3467,10 @@ static const cmsFormatters16 InputFormatters16[] = { { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Unroll4BytesSwap}, { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Unroll4BytesSwapSwapFirst}, - { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST| + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYPREMUL| ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarBytes}, - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP| + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYPREMUL| ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollChunkyBytes}, { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Unroll1Word}, @@ -3083,6 +3492,10 @@ static const cmsFormatters16 InputFormatters16[] = { { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollPlanarWords}, { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, UnrollAnyWords}, + + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1), UnrollPlanarWordsPremul}, + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE|PREMUL_SH(1), UnrollAnyWordsPremul} + }; @@ -3098,13 +3511,23 @@ static const cmsFormattersFloat InputFormattersFloat[] = { { TYPE_XYZ_FLT, ANYPLANAR|ANYEXTRA, UnrollXYZFloatToFloat}, { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| - ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, + ANYPREMUL|ANYCHANNELS|ANYSPACE, UnrollFloatsToFloat}, { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| - ANYCHANNELS|ANYSPACE, UnrollDoublesToFloat}, + ANYCHANNELS|ANYSPACE|ANYPREMUL, UnrollDoublesToFloat}, + + { TYPE_LabV2_8, 0, UnrollLabV2_8ToFloat }, + { TYPE_ALabV2_8, 0, UnrollALabV2_8ToFloat }, + { TYPE_LabV2_16, 0, UnrollLabV2_16ToFloat }, + + { BYTES_SH(1), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, Unroll8ToFloat}, + + { BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE, Unroll16ToFloat}, #ifndef CMS_NO_HALF_SUPPORT { FLOAT_SH(1)|BYTES_SH(2), ANYPLANAR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| - ANYCHANNELS|ANYSPACE, UnrollHalfToFloat}, + ANYCHANNELS|ANYSPACE, UnrollHalfToFloat}, #endif }; @@ -3198,16 +3621,20 @@ static const cmsFormatters16 OutputFormatters16[] = { ANYSPACE, Pack3BytesAndSkip1SwapSwapFirst}, { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|EXTRA_SH(1), ANYSPACE, Pack3BytesAndSkip1Swap}, { CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack3BytesSwap}, - { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes}, - { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap}, { CHANNELS_SH(4)|BYTES_SH(1), ANYSPACE, Pack4Bytes}, { CHANNELS_SH(4)|BYTES_SH(1)|FLAVOR_SH(1), ANYSPACE, Pack4BytesReverse}, { CHANNELS_SH(4)|BYTES_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapFirst}, { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack4BytesSwap}, { CHANNELS_SH(4)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1), ANYSPACE, Pack4BytesSwapSwapFirst}, + { CHANNELS_SH(6)|BYTES_SH(1), ANYSPACE, Pack6Bytes}, + { CHANNELS_SH(6)|BYTES_SH(1)|DOSWAP_SH(1), ANYSPACE, Pack6BytesSwap}, + + { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS| + ANYSPACE|ANYPREMUL, PackChunkyBytes}, + + { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarBytes}, - { BYTES_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyBytes}, - { BYTES_SH(1)|PLANAR_SH(1), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarBytes}, { CHANNELS_SH(1)|BYTES_SH(2), ANYSPACE, Pack1Word}, { CHANNELS_SH(1)|BYTES_SH(2)|EXTRA_SH(1), ANYSPACE, Pack1WordSkip1}, @@ -3232,8 +3659,10 @@ static const cmsFormatters16 OutputFormatters16[] = { { CHANNELS_SH(6)|BYTES_SH(2), ANYSPACE, Pack6Words}, { CHANNELS_SH(6)|BYTES_SH(2)|DOSWAP_SH(1), ANYSPACE, Pack6WordsSwap}, - { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackPlanarWords}, - { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackAnyWords} + { BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYENDIAN| + ANYEXTRA|ANYCHANNELS|ANYSPACE|ANYPREMUL, PackChunkyWords}, + { BYTES_SH(2)|PLANAR_SH(1), ANYFLAVOR|ANYENDIAN|ANYSWAP|ANYEXTRA| + ANYCHANNELS|ANYSPACE|ANYPREMUL, PackPlanarWords} }; @@ -3405,6 +3834,11 @@ cmsFormatter CMSEXPORT _cmsGetFormatter(cmsContext ContextID, _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); @@ -3439,9 +3873,12 @@ cmsUInt32Number CMSEXPORT cmsFormatterForColorspaceOfProfile(cmsHPROFILE hProfil 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); } @@ -3456,6 +3893,9 @@ 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c index 6c628ed5e46..f17c74b4b2d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -903,7 +903,7 @@ int CMSEXPORT _cmsLCMScolorSpace(cmsColorSpaceSignature ProfileSpace) } -cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) +cmsInt32Number CMSEXPORT cmsChannelsOfColorSpace(cmsColorSpaceSignature ColorSpace) { switch (ColorSpace) { @@ -964,6 +964,16 @@ cmsUInt32Number CMSEXPORT cmsChannelsOf(cmsColorSpaceSignature ColorSpace) 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c index 037e6cbcdf1..87c74390bdb 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -197,17 +197,20 @@ cmsBool CMSEXPORT _cmsReadUInt32Number(cmsIOHANDLER* io, cmsUInt32Number* n) 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; @@ -334,13 +337,14 @@ cmsBool CMSEXPORT _cmsWriteUInt32Number(cmsIOHANDLER* io, cmsUInt32Number n) cmsBool CMSEXPORT _cmsWriteFloat32Number(cmsIOHANDLER* io, cmsFloat32Number n) { - cmsUInt32Number tmp; - - _cmsAssert(io != NULL); - - tmp = *(cmsUInt32Number*) (void*) &n; - tmp = _cmsAdjustEndianess32(tmp); - if (io -> Write(io, sizeof(cmsUInt32Number), &tmp) != 1) + union typeConverter { + cmsUInt32Number integer; + cmsFloat32Number floating_point; + } tmp; + + tmp.floating_point = n; + tmp.integer = _cmsAdjustEndianess32(tmp.integer); + if (io -> Write(io, sizeof(cmsUInt32Number), &tmp.integer) != 1) return FALSE; return TRUE; @@ -650,6 +654,10 @@ cmsBool CMSEXPORT cmsPluginTHR(cmsContext id, void* Plug_in) 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; @@ -672,24 +680,25 @@ void CMSEXPORT cmsUnregisterPlugins(void) // pointers structure. All global vars are referenced here. static struct _cmsContext_struct globalContext = { - NULL, // Not in the linked list - NULL, // No suballocator + 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, // 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 @@ -700,17 +709,65 @@ static struct _cmsContext_struct globalContext = { static _cmsMutex _cmsContextPoolHeadMutex = CMS_MUTEX_INITIALIZER; static struct _cmsContext_struct* _cmsContextPoolHead = NULL; + +// Make sure context is initialized (needed on windows) +static +cmsBool InitContextMutex(void) +{ + // See the comments regarding locking in lcms2_internal.h + // for an explanation of why we need the following code. +#ifndef CMS_NO_PTHREADS +#ifdef CMS_IS_WINDOWS_ +#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT + + static cmsBool already_initialized = FALSE; + + if (!already_initialized) + { + static HANDLE _cmsWindowsInitMutex = NULL; + static volatile HANDLE* mutex = &_cmsWindowsInitMutex; + + if (*mutex == NULL) + { + HANDLE p = CreateMutex(NULL, FALSE, NULL); + if (p && InterlockedCompareExchangePointer((void**)mutex, (void*)p, NULL) != NULL) + CloseHandle(p); + } + if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) + { + cmsSignalError(0, cmsERROR_INTERNAL, "Mutex lock failed"); + return FALSE; + } + if (((void**)&_cmsContextPoolHeadMutex)[0] == NULL) + InitializeCriticalSection(&_cmsContextPoolHeadMutex); + if (*mutex == NULL || !ReleaseMutex(*mutex)) + { + cmsSignalError(0, cmsERROR_INTERNAL, "Mutex unlock failed"); + return FALSE; + } + already_initialized = TRUE; + } +#endif +#endif +#endif + + return TRUE; +} + + + // Internal, get associated pointer, with guessing. Never returns NULL. struct _cmsContext_struct* _cmsGetContext(cmsContext ContextID) { struct _cmsContext_struct* id = (struct _cmsContext_struct*) ContextID; struct _cmsContext_struct* ctx; - // On 0, use global settings if (id == NULL) return &globalContext; + InitContextMutex(); + // Search _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); @@ -768,6 +825,8 @@ void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) // 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); @@ -779,6 +838,11 @@ void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) _cmsRegisterOptimizationPlugin(ContextID, NULL); _cmsRegisterTransformPlugin(ContextID, NULL); _cmsRegisterMutexPlugin(ContextID, NULL); + _cmsRegisterParallelizationPlugin(ContextID, NULL); + + if (ctx->MemPool != NULL) + _cmsSubAllocDestroy(ctx->MemPool); + ctx->MemPool = NULL; } @@ -813,31 +877,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) struct _cmsContext_struct* ctx; struct _cmsContext_struct fakeContext; - // See the comments regarding locking in lcms2_internal.h - // for an explanation of why we need the following code. -#ifndef CMS_NO_PTHREADS -#ifdef CMS_IS_WINDOWS_ -#ifndef CMS_RELY_ON_WINDOWS_STATIC_MUTEX_INIT - { - static HANDLE _cmsWindowsInitMutex = NULL; - static volatile HANDLE* mutex = &_cmsWindowsInitMutex; - - if (*mutex == NULL) - { - HANDLE p = CreateMutex(NULL, FALSE, NULL); - if (p && InterlockedCompareExchangePointer((void **)mutex, (void*)p, NULL) != NULL) - CloseHandle(p); - } - if (*mutex == NULL || WaitForSingleObject(*mutex, INFINITE) == WAIT_FAILED) - return NULL; - if (((void **)&_cmsContextPoolHeadMutex)[0] == NULL) - InitializeCriticalSection(&_cmsContextPoolHeadMutex); - if (*mutex == NULL || !ReleaseMutex(*mutex)) - return NULL; - } -#endif -#endif -#endif + if (!InitContextMutex()) return NULL; _cmsInstallAllocFunctions(_cmsFindMemoryPlugin(Plugin), &fakeContext.DefaultMemoryManager); @@ -886,6 +926,7 @@ cmsContext CMSEXPORT cmsCreateContext(void* Plugin, void* UserData) _cmsAllocOptimizationPluginChunk(ctx, NULL); _cmsAllocTransformPluginChunk(ctx, NULL); _cmsAllocMutexPluginChunk(ctx, NULL); + _cmsAllocParallelizationPluginChunk(ctx, NULL); // Setup the plug-ins if (!cmsPluginTHR(ctx, Plugin)) { @@ -913,6 +954,8 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) if (ctx == NULL) return NULL; // Something very wrong happened + if (!InitContextMutex()) return NULL; + // Setup default memory allocators memcpy(&ctx->DefaultMemoryManager, &src->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); @@ -947,6 +990,7 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) _cmsAllocOptimizationPluginChunk(ctx, src); _cmsAllocTransformPluginChunk(ctx, src); _cmsAllocMutexPluginChunk(ctx, src); + _cmsAllocParallelizationPluginChunk(ctx, src); // Make sure no one failed for (i=Logger; i < MemoryClientMax; i++) { @@ -972,6 +1016,9 @@ void CMSEXPORT cmsDeleteContext(cmsContext ContextID) struct _cmsContext_struct fakeContext; struct _cmsContext_struct* prev; + + InitContextMutex(); + memcpy(&fakeContext.DefaultMemoryManager, &ctx->DefaultMemoryManager, sizeof(ctx->DefaultMemoryManager)); fakeContext.chunks[UserPtr] = ctx ->chunks[UserPtr]; @@ -1018,3 +1065,32 @@ void* CMSEXPORT cmsGetContextUserData(cmsContext ContextID) } +// Use context mutex to provide thread-safe time +cmsBool _cmsGetTime(struct tm* ptr_time) +{ + struct tm* t; +#if defined(HAVE_GMTIME_R) || defined(HAVE_GMTIME_S) + struct tm tm; +#endif + + time_t now = time(NULL); + +#ifdef HAVE_GMTIME_R + t = gmtime_r(&now, &tm); +#elif defined(HAVE_GMTIME_S) + t = gmtime_s(&tm, &now) == 0 ? &tm : NULL; +#else + if (!InitContextMutex()) return FALSE; + + _cmsEnterCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); + t = gmtime(&now); + _cmsLeaveCriticalSectionPrimitive(&_cmsContextPoolHeadMutex); +#endif + + if (t == NULL) + return FALSE; + else { + *ptr_time = *t; + return TRUE; + } +} diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c index e5274540064..c0816347d24 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -504,7 +504,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) _cmsIOPrintf(m, "/lcms2gammatable ["); for (i=0; i < Table->nEntries; i++) { - if (i % 10 == 0) + if (i % 10 == 0) _cmsIOPrintf(m, "\n "); _cmsIOPrintf(m, "%d ", Table->Table16[i]); } @@ -583,7 +583,7 @@ void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const cha } else { snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i); - buffer[sizeof(buffer)-1] = '\0'; + buffer[sizeof(buffer)-1] = '\0'; Emit1Gamma(m, g[i], buffer); } } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c index d3836420b3f..cf4a13968d1 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -155,6 +155,7 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, // 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); @@ -351,6 +352,7 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[] if (fabs(a) < 1.0E-10) { + if (fabs(b) < 1.0E-10) return 0; return cmsmin(0, cmsmax(50, -c/b )); } else { @@ -361,7 +363,11 @@ cmsFloat64Number RootOfLeastSquaresFitQuadraticCurve(int n, cmsFloat64Number x[] } 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c index 3d898d2c82a..4300d164df6 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c index 006f98b084d..898b5e8ffd6 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -163,15 +163,62 @@ cmsBool _cmsWriteWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, const wchar_t* return TRUE; } +// Try to promote correctly to wchar_t when 32 bits +cmsINLINE cmsBool is_surrogate(cmsUInt32Number uc) { return (uc - 0xd800u) < 2048u; } +cmsINLINE cmsBool is_high_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xd800; } +cmsINLINE cmsBool is_low_surrogate(cmsUInt32Number uc) { return (uc & 0xfffffc00) == 0xdc00; } + +cmsINLINE cmsUInt32Number surrogate_to_utf32(cmsUInt32Number high, cmsUInt32Number low) +{ + return (high << 10) + low - 0x35fdc00; +} + +cmsINLINE cmsBool convert_utf16_to_utf32(cmsIOHANDLER* io, cmsInt32Number n, wchar_t* output) +{ + cmsUInt16Number uc; + + while (n > 0) + { + if (!_cmsReadUInt16Number(io, &uc)) return FALSE; + n--; + + if (!is_surrogate(uc)) + { + *output++ = (wchar_t)uc; + } + else { + + cmsUInt16Number low; + + if (!_cmsReadUInt16Number(io, &low)) return FALSE; + n--; + + if (is_high_surrogate(uc) && is_low_surrogate(low)) + *output++ = (wchar_t)surrogate_to_utf32(uc, low); + else + return FALSE; // Corrupted string, just ignore + } + } + + return TRUE; +} + + // Auxiliary to read an array of wchar_t static cmsBool _cmsReadWCharArray(cmsIOHANDLER* io, cmsUInt32Number n, wchar_t* Array) { cmsUInt32Number i; cmsUInt16Number tmp; + cmsBool is32 = sizeof(wchar_t) > sizeof(cmsUInt16Number); _cmsAssert(io != NULL); + if (is32 && Array != NULL) + { + return convert_utf16_to_utf32(io, n, Array); + } + for (i=0; i < n; i++) { if (Array != NULL) { @@ -1336,7 +1383,7 @@ void Type_ParametricCurve_Free(struct _cms_typehandler_struct* self, void* Ptr) // // All the dateTimeNumber values in a profile shall be in Coordinated Universal Time // (UTC, also known as GMT or ZULU Time). Profile writers are required to convert local -// time to UTC when setting these values. Programmes that display these values may show +// time to UTC when setting these values. Programs that display these values may show // the dateTimeNumber as UTC, show the equivalent local time (at current locale), or // display both UTC and local versions of the dateTimeNumber. @@ -1532,7 +1579,10 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU 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; @@ -1775,7 +1825,7 @@ cmsUInt32Number uipow(cmsUInt32Number n, cmsUInt32Number a, cmsUInt32Number b) // That will create a MPE LUT with Matrix, pre tables, CLUT and post tables. -// 8 bit lut may be scaled easely to v4 PCS, but we need also to properly adjust +// 8 bit lut may be scaled easily to v4 PCS, but we need also to properly adjust // PCS on BToAxx tags and AtoB if abstract. We need to fix input direction. static @@ -1882,7 +1932,7 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms static cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { - cmsUInt32Number j, nTabSize, i, n; + cmsUInt32Number j, nTabSize, i; cmsUInt8Number val; cmsPipeline* NewLUT = (cmsPipeline*) Ptr; cmsStage* mpe; @@ -1917,28 +1967,34 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // 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]; + 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) NewLUT ->InputChannels)) return FALSE; - if (!_cmsWriteUInt8Number(io, (cmsUInt8Number) NewLUT ->OutputChannels)) 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 - n = NewLUT->InputChannels * NewLUT->OutputChannels; - 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 { @@ -2056,10 +2112,10 @@ cmsBool Write16bitTables(cmsContext ContextID, cmsIOHANDLER* io, _cmsStageToneCu _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]; @@ -2202,7 +2258,7 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // 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; } @@ -2211,8 +2267,16 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, 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; @@ -2221,10 +2285,10 @@ cmsBool Type_LUT16_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, 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 { @@ -2570,31 +2634,31 @@ void* Type_LUTA2B_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, c 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; - } + 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; - } + } + else { + for (i = 0; i < mpe->OutputChannels; i++) + { + if (!_cmsWrite15Fixed16Number(io, 0)) return FALSE; } + } return TRUE; @@ -3125,7 +3189,6 @@ void Type_ColorantTable_Free(struct _cms_typehandler_struct* self, void* Ptr) 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 @@ -3197,8 +3260,8 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER if (!_cmsWriteUInt32Number(io, nColors)) return FALSE; if (!_cmsWriteUInt32Number(io, NamedColorList ->ColorantCount)) return FALSE; - strncpy(prefix, (const char*) NamedColorList->Prefix, 32); - strncpy(suffix, (const char*) NamedColorList->Suffix, 32); + memcpy(prefix, (const char*) NamedColorList->Prefix, sizeof(prefix)); + memcpy(suffix, (const char*) NamedColorList->Suffix, sizeof(suffix)); suffix[32] = prefix[32] = 0; @@ -3211,6 +3274,10 @@ cmsBool Type_NamedColor_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER cmsUInt16Number Colorant[cmsMAXCHANNELS]; char Root[cmsMAX_PATH]; + memset(Root, 0, sizeof(Root)); + memset(PCS, 0, sizeof(PCS)); + memset(Colorant, 0, sizeof(Colorant)); + if (!cmsNamedColorInfo(NamedColorList, i, Root, NULL, NULL, PCS, Colorant)) return 0; Root[32] = 0; if (!io ->Write(io, 32 , Root)) return FALSE; @@ -3451,7 +3518,6 @@ void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHAN // Get table count if (!_cmsReadUInt32Number(io, &Count)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); // Allocate an empty structure OutSeq = cmsAllocProfileSequenceDescription(self ->ContextID, Count); @@ -3469,6 +3535,7 @@ void *Type_ProfileSequenceId_Read(struct _cms_typehandler_struct* self, cmsIOHAN *nItems = 1; return OutSeq; + cmsUNUSED_PARAMETER(SizeOfTag); } @@ -3544,47 +3611,68 @@ void *Type_UcrBg_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cm { cmsUcrBg* n = (cmsUcrBg*) _cmsMallocZero(self ->ContextID, sizeof(cmsUcrBg)); cmsUInt32Number CountUcr, CountBg; + cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag; char* ASCIIString; *nItems = 0; if (n == NULL) return NULL; // First curve is Under color removal + + if (SignedSizeOfTag < (cmsInt32Number) sizeof(cmsUInt32Number)) return NULL; if (!_cmsReadUInt32Number(io, &CountUcr)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); + SignedSizeOfTag -= sizeof(cmsUInt32Number); n ->Ucr = cmsBuildTabulatedToneCurve16(self ->ContextID, CountUcr, NULL); - if (n ->Ucr == NULL) return NULL; + if (n ->Ucr == NULL) goto error; - if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= CountUcr * sizeof(cmsUInt16Number); + if (SignedSizeOfTag < (cmsInt32Number)(CountUcr * sizeof(cmsUInt16Number))) goto error; + if (!_cmsReadUInt16Array(io, CountUcr, n ->Ucr->Table16)) goto error; + + SignedSizeOfTag -= CountUcr * sizeof(cmsUInt16Number); // Second curve is Black generation - if (!_cmsReadUInt32Number(io, &CountBg)) return NULL; - if (SizeOfTag < sizeof(cmsUInt32Number)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); + + if (SignedSizeOfTag < (cmsInt32Number)sizeof(cmsUInt32Number)) goto error; + if (!_cmsReadUInt32Number(io, &CountBg)) goto error; + SignedSizeOfTag -= sizeof(cmsUInt32Number); n ->Bg = cmsBuildTabulatedToneCurve16(self ->ContextID, CountBg, NULL); - if (n ->Bg == NULL) return NULL; - if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) return NULL; - if (SizeOfTag < CountBg * sizeof(cmsUInt16Number)) return NULL; - SizeOfTag -= CountBg * sizeof(cmsUInt16Number); - if (SizeOfTag == UINT_MAX) return NULL; + if (n ->Bg == NULL) goto error; + + if (SignedSizeOfTag < (cmsInt32Number) (CountBg * sizeof(cmsUInt16Number))) goto error; + if (!_cmsReadUInt16Array(io, CountBg, n ->Bg->Table16)) goto error; + SignedSizeOfTag -= CountBg * sizeof(cmsUInt16Number); + + if (SignedSizeOfTag < 0 || SignedSizeOfTag > 32000) goto error; // Now comes the text. The length is specified by the tag size n ->Desc = cmsMLUalloc(self ->ContextID, 1); - if (n ->Desc == NULL) return NULL; + if (n ->Desc == NULL) goto error; - ASCIIString = (char*) _cmsMalloc(self ->ContextID, SizeOfTag + 1); - if (io ->Read(io, ASCIIString, sizeof(char), SizeOfTag) != SizeOfTag) return NULL; - ASCIIString[SizeOfTag] = 0; + ASCIIString = (char*) _cmsMalloc(self ->ContextID, SignedSizeOfTag + 1); + if (io->Read(io, ASCIIString, sizeof(char), SignedSizeOfTag) != (cmsUInt32Number)SignedSizeOfTag) + { + _cmsFree(self->ContextID, ASCIIString); + goto error; + } + + ASCIIString[SignedSizeOfTag] = 0; cmsMLUsetASCII(n ->Desc, cmsNoLanguage, cmsNoCountry, ASCIIString); _cmsFree(self ->ContextID, ASCIIString); *nItems = 1; return (void*) n; + +error: + + if (n->Ucr) cmsFreeToneCurve(n->Ucr); + if (n->Bg) cmsFreeToneCurve(n->Bg); + if (n->Desc) cmsMLUfree(n->Desc); + _cmsFree(self->ContextID, n); + *nItems = 0; + return NULL; + } static @@ -3665,7 +3753,7 @@ country varies for each element: // 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; @@ -3695,7 +3783,7 @@ cmsBool ReadCountAndSting(struct _cms_typehandler_struct* self, cmsIOHANDLER* i } 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; @@ -3719,11 +3807,11 @@ void *Type_CrdInfo_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, 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; @@ -3740,11 +3828,11 @@ cmsBool Type_CrdInfo_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* 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; @@ -3998,41 +4086,44 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND switch (ElementSig) { - case cmsSigFormulaCurveSeg: { + case cmsSigFormulaCurveSeg: { - cmsUInt16Number Type; - cmsUInt32Number ParamsByType[] = {4, 5, 5 }; + cmsUInt16Number Type; + cmsUInt32Number ParamsByType[] = { 4, 5, 5 }; - if (!_cmsReadUInt16Number(io, &Type)) goto Error; - if (!_cmsReadUInt16Number(io, NULL)) goto Error; + if (!_cmsReadUInt16Number(io, &Type)) goto Error; + if (!_cmsReadUInt16Number(io, NULL)) goto Error; - Segments[i].Type = Type + 6; - if (Type > 2) goto Error; + Segments[i].Type = Type + 6; + if (Type > 2) goto Error; - for (j=0; j < ParamsByType[Type]; j++) { + for (j = 0; j < ParamsByType[Type]; j++) { - cmsFloat32Number f; - if (!_cmsReadFloat32Number(io, &f)) goto Error; - Segments[i].Params[j] = f; - } - } - break; + cmsFloat32Number f; + if (!_cmsReadFloat32Number(io, &f)) goto Error; + Segments[i].Params[j] = f; + } + } + break; - case cmsSigSampledCurveSeg: { - cmsUInt32Number Count; + case cmsSigSampledCurveSeg: { + cmsUInt32Number Count; - if (!_cmsReadUInt32Number(io, &Count)) goto Error; + if (!_cmsReadUInt32Number(io, &Count)) goto Error; - Segments[i].nGridPoints = Count; - Segments[i].SampledPoints = (cmsFloat32Number*) _cmsCalloc(self ->ContextID, Count, sizeof(cmsFloat32Number)); - if (Segments[i].SampledPoints == NULL) goto Error; + // The first point is implicit in the last stage, we allocate an extra note to be populated latter on + Count++; + Segments[i].nGridPoints = Count; + Segments[i].SampledPoints = (cmsFloat32Number*)_cmsCalloc(self->ContextID, Count, sizeof(cmsFloat32Number)); + if (Segments[i].SampledPoints == NULL) goto Error; - for (j=0; j < Count; j++) { - if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; - } - } - break; + Segments[i].SampledPoints[0] = 0; + for (j = 1; j < Count; j++) { + if (!_cmsReadFloat32Number(io, &Segments[i].SampledPoints[j])) goto Error; + } + } + break; default: { @@ -4052,6 +4143,17 @@ cmsToneCurve* ReadSegmentedCurve(struct _cms_typehandler_struct* self, cmsIOHAND if (Segments[i].SampledPoints) _cmsFree(self ->ContextID, Segments[i].SampledPoints); } _cmsFree(self ->ContextID, Segments); + + // Explore for missing implicit points + for (i = 0; i < nSegments; i++) { + + // If sampled curve, fix it + if (Curve->Segments[i].Type == 0) { + + Curve->Segments[i].SampledPoints[0] = cmsEvalToneCurveFloat(Curve, Curve->Segments[i].x0); + } + } + return Curve; Error: @@ -4146,12 +4248,12 @@ cmsBool WriteSegmentedCurve(cmsIOHANDLER* io, cmsToneCurve* g) if (ActualSeg -> Type == 0) { - // This is a sampled curve + // This is a sampled curve. First point is implicit in the ICC format, but not in our representation if (!_cmsWriteUInt32Number(io, (cmsUInt32Number) cmsSigSampledCurveSeg)) goto Error; if (!_cmsWriteUInt32Number(io, 0)) goto Error; - if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints)) goto Error; + if (!_cmsWriteUInt32Number(io, ActualSeg -> nGridPoints - 1)) goto Error; - for (j=0; j < g ->Segments[i].nGridPoints; j++) { + for (j=1; j < g ->Segments[i].nGridPoints; j++) { if (!_cmsWriteFloat32Number(io, ActualSeg -> SampledPoints[j])) goto Error; } @@ -4528,7 +4630,7 @@ void *Type_MPE_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU -// This one is a liitle bit more complex, so we don't use position tables this time. +// This one is a little bit more complex, so we don't use position tables this time. static cmsBool Type_MPE_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { @@ -4960,7 +5062,7 @@ cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUIn if (!_cmsReadUInt32Number(io, &e->Offsets[i])) return FALSE; if (!_cmsReadUInt32Number(io, &e ->Sizes[i])) return FALSE; - // An offset of zero has special meaning and shal be preserved + // An offset of zero has special meaning and shall be preserved if (e ->Offsets[i] > 0) e ->Offsets[i] += BaseOffset; return TRUE; @@ -4968,27 +5070,41 @@ cmsBool ReadOneElem(cmsIOHANDLER* io, _cmsDICelem* e, cmsUInt32Number i, cmsUIn static -cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset) +cmsBool ReadOffsetArray(cmsIOHANDLER* io, _cmsDICarray* a, + cmsUInt32Number Count, cmsUInt32Number Length, cmsUInt32Number BaseOffset, + cmsInt32Number* SignedSizeOfTagPtr) { cmsUInt32Number i; + cmsInt32Number SignedSizeOfTag = *SignedSizeOfTagPtr; // Read column arrays for (i=0; i < Count; i++) { + if (SignedSizeOfTag < 4 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE; + SignedSizeOfTag -= 4 * sizeof(cmsUInt32Number); + if (!ReadOneElem(io, &a -> Name, i, BaseOffset)) return FALSE; if (!ReadOneElem(io, &a -> Value, i, BaseOffset)) return FALSE; if (Length > 16) { + if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE; + SignedSizeOfTag -= 2 * sizeof(cmsUInt32Number); + if (!ReadOneElem(io, &a ->DisplayName, i, BaseOffset)) return FALSE; } if (Length > 24) { + if (SignedSizeOfTag < 2 * (cmsInt32Number) sizeof(cmsUInt32Number)) return FALSE; + SignedSizeOfTag -= 2 * (cmsInt32Number) sizeof(cmsUInt32Number); + if (!ReadOneElem(io, & a -> DisplayValue, i, BaseOffset)) return FALSE; } } + + *SignedSizeOfTagPtr = SignedSizeOfTag; return TRUE; } @@ -5136,26 +5252,31 @@ cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _c static void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { - cmsHANDLE hDict; + cmsHANDLE hDict = NULL; cmsUInt32Number i, Count, Length; cmsUInt32Number BaseOffset; _cmsDICarray a; wchar_t *NameWCS = NULL, *ValueWCS = NULL; cmsMLU *DisplayNameMLU = NULL, *DisplayValueMLU=NULL; cmsBool rc; + cmsInt32Number SignedSizeOfTag = (cmsInt32Number)SizeOfTag; *nItems = 0; + memset(&a, 0, sizeof(a)); // Get actual position as a basis for element offsets BaseOffset = io ->Tell(io) - sizeof(_cmsTagBase); // Get name-value record count + SignedSizeOfTag -= sizeof(cmsUInt32Number); + if (SignedSizeOfTag < 0) goto Error; if (!_cmsReadUInt32Number(io, &Count)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); // Get rec length + SignedSizeOfTag -= sizeof(cmsUInt32Number); + if (SignedSizeOfTag < 0) goto Error; if (!_cmsReadUInt32Number(io, &Length)) return NULL; - SizeOfTag -= sizeof(cmsUInt32Number); + // Check for valid lengths if (Length != 16 && Length != 24 && Length != 32) { @@ -5171,7 +5292,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i if (!AllocArray(self -> ContextID, &a, Count, Length)) goto Error; // Read column arrays - if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset)) goto Error; + if (!ReadOffsetArray(io, &a, Count, Length, BaseOffset, &SignedSizeOfTag)) goto Error; // Seek to each element and read it for (i=0; i < Count; i++) { @@ -5211,7 +5332,7 @@ void *Type_Dictionary_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* i Error: FreeArray(&a); - cmsDictFree(hDict); + if (hDict != NULL) cmsDictFree(hDict); return NULL; } @@ -5309,6 +5430,64 @@ void Type_Dictionary_Free(struct _cms_typehandler_struct* self, void* Ptr) 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 @@ -5348,6 +5527,7 @@ static const _cmsTagTypeLinkedList SupportedTagTypes[] = { {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 } }; @@ -5542,6 +5722,8 @@ static _cmsTagLinkedList SupportedTags[] = { { 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c index c185b347efb..6d15f1fde13 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -143,7 +143,7 @@ cmsHPROFILE CMSEXPORT cmsCreateRGBProfileTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.3); + cmsSetProfileVersion(hICC, 4.4); cmsSetDeviceClass(hICC, cmsSigDisplayClass); cmsSetColorSpace(hICC, cmsSigRgbData); @@ -264,7 +264,7 @@ cmsHPROFILE CMSEXPORT cmsCreateGrayProfileTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.3); + cmsSetProfileVersion(hICC, 4.4); cmsSetDeviceClass(hICC, cmsSigDisplayClass); cmsSetColorSpace(hICC, cmsSigGrayData); @@ -320,13 +320,13 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, { 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); @@ -335,7 +335,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLinearizationDeviceLinkTHR(cmsContext ContextID, 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 @@ int InkLimitingSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUI InkLimit = (InkLimit * 655.35); - SumCMY = In[0] + In[1] + In[2]; + SumCMY = (cmsFloat64Number) In[0] + In[1] + In[2]; SumCMYK = SumCMY + In[3]; if (SumCMYK > InkLimit) { @@ -426,7 +426,7 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, cmsHPROFILE hICC; cmsPipeline* LUT; cmsStage* CLUT; - cmsUInt32Number nChannels; + cmsInt32Number nChannels; if (ColorSpace != cmsSigCmykData) { cmsSignalError(ContextID, cmsERROR_COLORSPACE_CHECK, "InkLimiting: Only CMYK currently supported"); @@ -445,7 +445,7 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, if (!hICC) // can't allocate return NULL; - cmsSetProfileVersion(hICC, 4.3); + cmsSetProfileVersion(hICC, 4.4); cmsSetDeviceClass(hICC, cmsSigLinkClass); cmsSetColorSpace(hICC, ColorSpace); @@ -555,7 +555,7 @@ cmsHPROFILE CMSEXPORT cmsCreateLab4ProfileTHR(cmsContext ContextID, const cmsCIE 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); @@ -601,7 +601,7 @@ cmsHPROFILE CMSEXPORT cmsCreateXYZProfileTHR(cmsContext ContextID) 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); @@ -868,7 +868,7 @@ cmsHPROFILE CMSEXPORT cmsCreateNULLProfileTHR(cmsContext ContextID) 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; @@ -1003,7 +1003,7 @@ cmsHPROFILE CreateNamedColorDevicelink(cmsHTRANSFORM xform) // 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++) { @@ -1091,8 +1091,9 @@ const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTa 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; @@ -1143,8 +1144,8 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat // 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/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c index d93889114e6..96bad5de7ca 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -293,16 +293,16 @@ cmsBool _cmsAdaptMatrixToD50(cmsMAT3* r, const cmsCIExyY* SourceWhitePt) // Build a White point, primary chromas transfer matrix from RGB to CIE XYZ // This is just an approximation, I am not handling all the non-linear -// aspects of the RGB to XYZ process, and assumming that the gamma correction +// aspects of the RGB to XYZ process, and assuming that the gamma correction // has transitive property in the transformation chain. // -// the alghoritm: +// the algorithm: // // - First I build the absolute conversion matrix using // primaries in XYZ. This matrix is next inverted // - Then I eval the source white point across this matrix -// obtaining the coeficients of the transformation -// - Then, I apply these coeficients to the original matrix +// obtaining the coefficients of the transformation +// - Then, I apply these coefficients to the original matrix // cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePt, const cmsCIExyYTRIPLE* Primrs) { diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c index 6a2170c8fd2..8b8f831f0af 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -313,7 +313,7 @@ void FloatXFORM(_cmsTRANSFORM* p, accum = p->FromInputFloat(p, fIn, accum, Stride->BytesPerPlaneIn); - // Any gamut chack to do? + // Any gamut check to do? if (p->GamutCheck != NULL) { // Evaluate gamut marker. @@ -810,6 +810,73 @@ cmsUInt32Number CMSEXPORT _cmsGetTransformFlags(struct _cmstransform_struct* CMM 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 @@ -865,6 +932,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, p->xform = _cmsTransform2toTransformAdaptor; } + ParalellizeIfSuitable(p); return p; } } @@ -875,7 +943,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, } // Check whatever this is a true floating point transform - if (_cmsFormatterIsFloat(*InputFormat) && _cmsFormatterIsFloat(*OutputFormat)) { + if (_cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; @@ -901,8 +969,10 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, } 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 { @@ -919,7 +989,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, return NULL; } - BytesPerPixelInput = T_BYTES(p ->InputFormat); + BytesPerPixelInput = T_BYTES(*InputFormat); if (BytesPerPixelInput == 0 || BytesPerPixelInput >= 2) *dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER; @@ -953,6 +1023,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, p ->dwOriginalFlags = *dwFlags; p ->ContextID = ContextID; p ->UserData = NULL; + ParalellizeIfSuitable(p); return p; } @@ -1110,6 +1181,15 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, return NULL; } + // Check whatever the transform is 16 bits and involves linear RGB in first profile. If so, disable optimizations + if (EntryColorSpace == cmsSigRgbData && T_BYTES(InputFormat) == 2 && !(dwFlags & cmsFLAGS_NOOPTIMIZE)) + { + cmsFloat64Number gamma = cmsDetectRGBProfileGamma(hProfiles[0], 0.1); + + if (gamma > 0 && gamma < 1.6) + dwFlags |= cmsFLAGS_NOOPTIMIZE; + } + // Create a pipeline with all transformations Lut = _cmsLinkProfiles(ContextID, nProfiles, Intents, hProfiles, BPC, AdaptationStates, dwFlags); if (Lut == NULL) { @@ -1118,8 +1198,8 @@ cmsHTRANSFORM CMSEXPORT cmsCreateExtendedTransform(cmsContext ContextID, } // 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/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h index 69ada9ede64..ab122f3b342 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2021 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.12 +// Version 2.14 // #ifndef _lcms2_H @@ -110,7 +110,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2120 +#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 @@ -181,7 +181,7 @@ typedef double cmsFloat64Number; #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 @@ -319,6 +319,7 @@ typedef int cmsBool; // Base ICC type definitions typedef enum { cmsSigChromaticityType = 0x6368726D, // 'chrm' + cmsSigcicpType = 0x63696370, // 'cicp' cmsSigColorantOrderType = 0x636C726F, // 'clro' cmsSigColorantTableType = 0x636C7274, // 'clrt' cmsSigCrdInfoType = 0x63726469, // 'crdi' @@ -430,6 +431,7 @@ typedef enum { cmsSigViewingConditionsTag = 0x76696577, // 'view' cmsSigVcgtTag = 0x76636774, // 'vcgt' cmsSigMetaTag = 0x6D657461, // 'meta' + cmsSigcicpTag = 0x63696370, // 'cicp' cmsSigArgyllArtsTag = 0x61727473 // 'arts' } cmsTagSignature; @@ -695,9 +697,10 @@ typedef void* cmsHTRANSFORM; // Format of pixel is defined by one cmsUInt32Number, using bit fields as follows // // 2 1 0 -// 3 2 10987 6 5 4 3 2 1 098 7654 321 -// A O TTTTT U Y F P X S EEE CCCC BBB +// 4 3 2 10987 6 5 4 3 2 1 098 7654 321 +// M A O TTTTT U Y F P X S EEE CCCC BBB // +// M: Premultiplied alpha (only works when extra samples is 1) // A: Floating point -- With this flag we can differentiate 16 bits as float and as int // O: Optimized -- previous optimization already returns the final 8-bit value // T: Pixeltype @@ -710,6 +713,7 @@ typedef void* cmsHTRANSFORM; // B: bytes per sample // Y: Swap first - changes ABGR to BGRA and KCMY to CMYK +#define PREMUL_SH(m) ((m) << 23) #define FLOAT_SH(a) ((a) << 22) #define OPTIMIZED_SH(s) ((s) << 21) #define COLORSPACE_SH(s) ((s) << 16) @@ -723,6 +727,7 @@ typedef void* cmsHTRANSFORM; #define BYTES_SH(b) (b) // These macros unpack format specifiers into integers +#define T_PREMUL(m) (((m)>>23)&1) #define T_FLOAT(a) (((a)>>22)&1) #define T_OPTIMIZED(o) (((o)>>21)&1) #define T_COLORSPACE(s) (((s)>>16)&31) @@ -751,7 +756,6 @@ typedef void* cmsHTRANSFORM; #define PT_HSV 12 #define PT_HLS 13 #define PT_Yxy 14 - #define PT_MCH1 15 #define PT_MCH2 16 #define PT_MCH3 17 @@ -767,7 +771,6 @@ typedef void* cmsHTRANSFORM; #define PT_MCH13 27 #define PT_MCH14 28 #define PT_MCH15 29 - #define PT_LabV2 30 // Identical to PT_Lab, but using the V2 old encoding // Some (not all!) representations @@ -781,7 +784,9 @@ typedef void* cmsHTRANSFORM; #define TYPE_GRAY_16_REV (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|FLAVOR_SH(1)) #define TYPE_GRAY_16_SE (COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) #define TYPE_GRAYA_8 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)) +#define TYPE_GRAYA_8_PREMUL (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PREMUL_SH(1)) #define TYPE_GRAYA_16 (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)) +#define TYPE_GRAYA_16_PREMUL (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PREMUL_SH(1)) #define TYPE_GRAYA_16_SE (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|ENDIAN16_SH(1)) #define TYPE_GRAYA_8_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(1)|PLANAR_SH(1)) #define TYPE_GRAYA_16_PLANAR (COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2)|PLANAR_SH(1)) @@ -798,24 +803,32 @@ typedef void* cmsHTRANSFORM; #define TYPE_BGR_16_SE (COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) #define TYPE_RGBA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)) +#define TYPE_RGBA_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PREMUL_SH(1)) #define TYPE_RGBA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|PLANAR_SH(1)) #define TYPE_RGBA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)) +#define TYPE_RGBA_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PREMUL_SH(1)) #define TYPE_RGBA_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) #define TYPE_RGBA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) #define TYPE_ARGB_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1)) #define TYPE_ARGB_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1)) #define TYPE_ARGB_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|SWAPFIRST_SH(1)|PREMUL_SH(1)) #define TYPE_ABGR_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)) +#define TYPE_ABGR_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PREMUL_SH(1)) #define TYPE_ABGR_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|PLANAR_SH(1)) #define TYPE_ABGR_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)) +#define TYPE_ABGR_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PREMUL_SH(1)) #define TYPE_ABGR_16_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|PLANAR_SH(1)) #define TYPE_ABGR_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|ENDIAN16_SH(1)) #define TYPE_BGRA_8 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_8_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1)) #define TYPE_BGRA_8_PLANAR (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PLANAR_SH(1)) #define TYPE_BGRA_16 (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_16_PREMUL (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1)) #define TYPE_BGRA_16_SE (COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) #define TYPE_CMY_8 (COLORSPACE_SH(PT_CMY)|CHANNELS_SH(3)|BYTES_SH(1)) @@ -932,7 +945,7 @@ typedef void* cmsHTRANSFORM; #define TYPE_HSV_16_PLANAR (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|PLANAR_SH(1)) #define TYPE_HSV_16_SE (COLORSPACE_SH(PT_HSV)|CHANNELS_SH(3)|BYTES_SH(2)|ENDIAN16_SH(1)) -// Named color index. Only 16 bits allowed (don't check colorspace) +// Named color index. Only 16 bits is allowed (don't check colorspace) #define TYPE_NAMED_COLOR_INDEX (CHANNELS_SH(1)|BYTES_SH(2)) // Float formatters. @@ -940,13 +953,19 @@ typedef void* cmsHTRANSFORM; #define TYPE_Lab_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_LabA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_Lab)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_GRAY_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)) +#define TYPE_GRAYA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)|EXTRA_SH(1)) +#define TYPE_GRAYA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(4)|EXTRA_SH(1)|PREMUL_SH(1)) #define TYPE_RGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)) #define TYPE_RGBA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)) +#define TYPE_RGBA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|PREMUL_SH(1)) #define TYPE_ARGB_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)) +#define TYPE_ARGB_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|SWAPFIRST_SH(1)|PREMUL_SH(1)) #define TYPE_BGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) #define TYPE_BGRA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)) +#define TYPE_BGRA_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|SWAPFIRST_SH(1)|PREMUL_SH(1)) #define TYPE_ABGR_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)) +#define TYPE_ABGR_FLT_PREMUL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(4)|DOSWAP_SH(1)|PREMUL_SH(1)) #define TYPE_CMYK_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(4)) @@ -1050,6 +1069,16 @@ typedef struct { } 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); @@ -1285,6 +1314,7 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsStageInputChannels(const cmsStage* mpe); CMSAPI cmsUInt32Number CMSEXPORT cmsStageOutputChannels(const cmsStage* mpe); CMSAPI cmsStageSignature CMSEXPORT cmsStageType(const cmsStage* mpe); CMSAPI void* CMSEXPORT cmsStageData(const cmsStage* mpe); +CMSAPI cmsContext CMSEXPORT cmsGetStageContextID(const cmsStage* mpe); // Sampling typedef cmsInt32Number (* cmsSAMPLER16) (CMSREGISTER const cmsUInt16Number In[], @@ -1531,8 +1561,12 @@ CMSAPI cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Numb 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); @@ -1935,6 +1969,8 @@ CMSAPI cmsBool CMSEXPORT cmsDetectDestinationBlackPoint(cmsCIEXYZ* Blac // Estimate total area coverage CMSAPI cmsFloat64Number CMSEXPORT cmsDetectTAC(cmsHPROFILE hProfile); +// Estimate gamma space, always positive. Returns -1 on error. +CMSAPI cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold); // Poor man's gamut mapping CMSAPI cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h index d1c78208b82..3999e24d771 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h @@ -30,7 +30,7 @@ // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -312,38 +312,38 @@ typedef CRITICAL_SECTION _cmsMutex; 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 @@ -357,32 +357,32 @@ typedef pthread_mutex_t _cmsMutex; 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 @@ -395,37 +395,37 @@ typedef int _cmsMutex; 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 @@ -467,6 +467,9 @@ cmsBool _cmsRegisterTransformPlugin(cmsContext ContextID, cmsPluginBase* Plugin // Mutex cmsBool _cmsRegisterMutexPlugin(cmsContext ContextID, cmsPluginBase* Plugin); +// Paralellization +cmsBool _cmsRegisterParallelizationPlugin(cmsContext ContextID, cmsPluginBase* Plugin); + // --------------------------------------------------------------------------------------------------------- // Suballocators. @@ -514,6 +517,7 @@ typedef enum { OptimizationPlugin, TransformPlugin, MutexPlugin, + ParallelizationPlugin, // Last in list MemoryClientMax @@ -749,6 +753,24 @@ extern _cmsMutexPluginChunkType _cmsMutexPluginChunk; 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 { @@ -1110,6 +1132,11 @@ typedef struct _cmstransform_struct { // 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 @@ -1147,5 +1174,8 @@ cmsBool _cmsAdaptationMatrix(cmsMAT3* r, const cmsMAT3* ConeMatrix, const cmsC cmsBool _cmsBuildRGB2XYZtransferMatrix(cmsMAT3* r, const cmsCIExyY* WhitePoint, const cmsCIExyYTRIPLE* Primaries); +// thread-safe gettime +cmsBool _cmsGetTime(struct tm* ptr_time); + #define _lcms_internal_H #endif diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h index 61e963ff5f8..1dc1a4661e2 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2020 Marti Maria Saguer +// Copyright (c) 1998-2022 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -53,7 +53,7 @@ //--------------------------------------------------------------------------------- // // This is the plug-in header file. Normal LittleCMS clients should not use it. -// It is provided for plug-in writters that may want to access the support +// It is provided for plug-in writers that may want to access the support // functions to do low level operations. All plug-in related structures // are defined here. Including this file forces to include the standard API too. @@ -238,6 +238,7 @@ typedef void* (* _cmsDupUserDataFn)(cmsContext ContextID, const void* Data); #define cmsPluginOptimizationSig 0x6F707448 // 'optH' #define cmsPluginTransformSig 0x7A666D48 // 'xfmH' #define cmsPluginMutexSig 0x6D747A48 // 'mtxH' +#define cmsPluginParalellizationSig 0x70726C48 // 'prlH typedef struct _cmsPluginBaseStruct { @@ -625,7 +626,7 @@ typedef void (* _cmsTransformFn)(struct _cmstransform_struct *CMMcargo, // 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, @@ -698,6 +699,25 @@ CMSAPI void CMSEXPORT _cmsDestroyMutex(cmsContext ContextID, void* mtx); 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 From 5517fec4d0717ca20505950eb528eafce515c224 Mon Sep 17 00:00:00 2001 From: Ekaterina Vergizova Date: Thu, 21 Aug 2025 23:41:28 +0300 Subject: [PATCH 2/3] Backport e28b210d5020fc7cc3a52c58f0a8ce14e16dd5fb --- THIRD_PARTY_README | 12 +++++++----- .../share/native/sun/java2d/cmm/lcms/cmsalpha.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmscam02.c | 4 ++-- .../share/native/sun/java2d/cmm/lcms/cmscgats.c | 10 ++++++---- .../share/native/sun/java2d/cmm/lcms/cmscnvrt.c | 10 +++++----- .../share/native/sun/java2d/cmm/lcms/cmserr.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsgamma.c | 6 +++++- .../share/native/sun/java2d/cmm/lcms/cmshalf.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsintrp.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsio0.c | 8 ++++---- .../share/native/sun/java2d/cmm/lcms/cmsio1.c | 6 +++++- .../share/native/sun/java2d/cmm/lcms/cmslut.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsmd5.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsmtrx.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsnamed.c | 12 ++++++++++-- .../share/native/sun/java2d/cmm/lcms/cmsopt.c | 6 +++++- .../share/native/sun/java2d/cmm/lcms/cmspack.c | 10 +++++----- .../share/native/sun/java2d/cmm/lcms/cmspcs.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmsplugin.c | 16 +++++++++------- .../share/native/sun/java2d/cmm/lcms/cmsps2.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmssamp.c | 7 +++---- jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmstypes.c | 14 ++++++++++++-- .../share/native/sun/java2d/cmm/lcms/cmsvirt.c | 2 +- .../share/native/sun/java2d/cmm/lcms/cmswtpnt.c | 7 +++++-- .../share/native/sun/java2d/cmm/lcms/cmsxform.c | 2 +- jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h | 8 ++++---- .../native/sun/java2d/cmm/lcms/lcms2_internal.h | 3 +-- .../native/sun/java2d/cmm/lcms/lcms2_plugin.h | 2 +- 29 files changed, 101 insertions(+), 64 deletions(-) diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README index 4e6995948e9..9bf39e98664 100644 --- a/THIRD_PARTY_README +++ b/THIRD_PARTY_README @@ -1725,7 +1725,7 @@ THE SOFTWARE. ------------------------------------------------------------------------------- -%% This notice is provided with respect to Little CMS 2.14, which may be +%% This notice is provided with respect to Little CMS 2.15, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- @@ -1737,7 +1737,7 @@ LittleCMS core is released under MIT License --------------------------------- Little CMS -Copyright (c) 1998-2022 Marti Maria Saguer +Copyright (c) 1998-2023 Marti Maria Saguer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the @@ -1759,7 +1759,6 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------- - The below license applies to the following files: liblcms/cmssm.c @@ -1771,9 +1770,9 @@ SoftSurfer makes no warranty for this code, and cannot be held liable for any real or imagined damage resulting from its use. Users of this code must verify correctness for their application. - AUTHORS File Information: + Main Author ------------ Marti Maria @@ -1814,11 +1813,15 @@ Mark Allen Noel Carboni Sergei Trofimovic Philipp Knechtges +Amyspark +Lovell Fuller +Eli Schwartz Special Thanks -------------- Artifex software AlienSkin software +libVIPS Jan Morovic Jos Vernon (WebSupergoo) Harald Schneider (Maxon) @@ -1827,7 +1830,6 @@ Dimitrios Anastassakis Lemke Software Tim Zaman - --- end of LICENSE --- ------------------------------------------------------------------------------- diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c index c6a37e79727..e69259e8a51 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c index 23f12419676..71a48d43de4 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscam02.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -353,7 +353,7 @@ CAM02COLOR HPEtoCAT02(CAM02COLOR clr) M[5] = ((-0.7036 * 0.201908) + (1.6975 * 0.000008) + 0.0061); M[6] = (( 0.0030 * 1.910197) + (0.0136 * 0.370950)); M[7] = (( 0.0030 * -1.112124) + (0.0136 * 0.629054)); - M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834);; + M[8] = (( 0.0030 * 0.201908) + (0.0136 * 0.000008) + 0.9834); clr.RGBc[0] = (clr.RGBp[0] * M[0]) + (clr.RGBp[1] * M[1]) + (clr.RGBp[2] * M[2]); clr.RGBc[1] = (clr.RGBp[0] * M[3]) + (clr.RGBp[1] * M[4]) + (clr.RGBp[2] * M[5]); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c index 61d5533e540..9d0aea27d73 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1968,13 +1968,15 @@ cmsBool CMSEXPORT cmsIT8SaveToMem(cmsHANDLE hIT8, void *MemPtr, cmsUInt32Number* memset(&sd, 0, sizeof(sd)); sd.stream = NULL; - sd.Base = (cmsUInt8Number*) MemPtr; + sd.Base = (cmsUInt8Number*) MemPtr; sd.Ptr = sd.Base; sd.Used = 0; - if (sd.Base) - sd.Max = *BytesNeeded; // Write to memory? + if (sd.Base && (*BytesNeeded > 0)) { + + sd.Max = (*BytesNeeded) - 1; // Write to memory? + } else sd.Max = 0; // Just counting the needed bytes diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c index 535a9e12d7e..b73d594f2ec 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -399,11 +399,11 @@ cmsBool ComputeConversion(cmsUInt32Number i, cmsCIEXYZ WhitePointIn, WhitePointOut; cmsMAT3 ChromaticAdaptationMatrixIn, ChromaticAdaptationMatrixOut; - _cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i-1]); - _cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i-1]); + if (!_cmsReadMediaWhitePoint(&WhitePointIn, hProfiles[i - 1])) return FALSE; + if (!_cmsReadCHAD(&ChromaticAdaptationMatrixIn, hProfiles[i - 1])) return FALSE; - _cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i]); - _cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i]); + if (!_cmsReadMediaWhitePoint(&WhitePointOut, hProfiles[i])) return FALSE; + if (!_cmsReadCHAD(&ChromaticAdaptationMatrixOut, hProfiles[i])) return FALSE; if (!ComputeAbsoluteIntent(AdaptationState, &WhitePointIn, &ChromaticAdaptationMatrixIn, diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c index 772a0a169e5..739cc0b2c98 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c index b5fd47a8ed1..08409434064 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -852,6 +852,10 @@ cmsToneCurve* CMSEXPORT cmsBuildTabulatedToneCurveFloat(cmsContext ContextID, cm { cmsCurveSegment Seg[3]; + // Do some housekeeping + if (nEntries == 0 || values == NULL) + return NULL; + // A segmented tone curve should have function segments in the first and last positions // Initialize segmented curve part up to 0 to constant value = samples[0] Seg[0].x0 = MINUS_INF; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c index eb1d4aa6ea1..5babb063eb0 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmshalf.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c index 7fe74feafd0..9837454df0b 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsintrp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index 75785355901..fe6b3d43a5a 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1949,7 +1949,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si if (data != NULL) { if (BufferSize < TagSize) - goto Error; + TagSize = BufferSize; if (!Icc ->IOhandler ->Seek(Icc ->IOhandler, Offset)) goto Error; if (!Icc ->IOhandler ->Read(Icc ->IOhandler, data, 1, TagSize)) goto Error; @@ -1962,7 +1962,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si return Icc ->TagSizes[i]; } - // The data has been already read, or written. But wait!, maybe the user chose to save as + // The data has been already read, or written. But wait!, maybe the user choose to save as // raw data. In this case, return the raw data directly if (Icc ->TagSaveAsRaw[i]) { @@ -1971,7 +1971,7 @@ cmsUInt32Number CMSEXPORT cmsReadRawTag(cmsHPROFILE hProfile, cmsTagSignature si TagSize = Icc ->TagSizes[i]; if (BufferSize < TagSize) - goto Error; + TagSize = BufferSize; memmove(data, Icc ->TagPtrs[i], TagSize); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c index 85d9f6788b5..bd8a832ac40 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -880,6 +880,10 @@ cmsBool CMSEXPORT cmsIsCLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent, cmsUI return FALSE; } + // Extended intents are not strictly CLUT-based + if (Intent > INTENT_ABSOLUTE_COLORIMETRIC) + return FALSE; + return cmsIsTag(hProfile, TagTable[Intent]); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c index 457ab6ecf5c..24114632ad0 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c index ea97c0d8774..01aa44de85a 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmd5.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c index 9bbe82871f5..599c290bd70 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsmtrx.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c index c710ba39372..04280180230 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -399,6 +399,8 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (len != NULL) *len = v ->Len; + if (v->StrW + v->Len > mlu->PoolSize) return NULL; + return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); } @@ -790,7 +792,13 @@ cmsStage* CMSEXPORT _cmsStageAllocNamedColor(cmsNAMEDCOLORLIST* NamedColorList, cmsNAMEDCOLORLIST* CMSEXPORT cmsGetNamedColorList(cmsHTRANSFORM xform) { _cmsTRANSFORM* v = (_cmsTRANSFORM*) xform; - cmsStage* mpe = v ->Lut->Elements; + cmsStage* mpe; + + if (v == NULL) return NULL; + if (v->Lut == NULL) return NULL; + + mpe = v->Lut->Elements; + if (mpe == NULL) return NULL; if (mpe ->Type != cmsSigNamedColorElemType) return NULL; return (cmsNAMEDCOLORLIST*) mpe ->Data; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c index e32f73b86ee..3e81ae1df1b 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1724,6 +1724,10 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageMatrixData* Data1 = (_cmsStageMatrixData*)cmsStageData(Matrix1); _cmsStageMatrixData* Data2 = (_cmsStageMatrixData*)cmsStageData(Matrix2); + // Only RGB to RGB + if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3 || + Matrix2->InputChannels != 3 || Matrix2->OutputChannels != 3) return FALSE; + // Input offset should be zero if (Data1->Offset != NULL) return FALSE; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c index e90e45656fc..da5fc6019d3 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1736,7 +1736,7 @@ cmsUInt8Number* PackChunkyBytes(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } @@ -1805,7 +1805,7 @@ cmsUInt8Number* PackChunkyWords(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } @@ -1872,7 +1872,7 @@ cmsUInt8Number* PackPlanarBytes(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } @@ -1932,7 +1932,7 @@ cmsUInt8Number* PackPlanarWords(CMSREGISTER _cmsTRANSFORM* info, if (Reverse) v = REVERSE_FLAVOR_16(v); - if (Premul && alpha_factor != 0) + if (Premul) { v = (cmsUInt16Number)((cmsUInt32Number)((cmsUInt32Number)v * alpha_factor + 0x8000) >> 16); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c index f17c74b4b2d..c4739840053 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspcs.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c index 87c74390bdb..c2808bb9278 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -825,8 +825,6 @@ void* _cmsContextGetClientChunk(cmsContext ContextID, _cmsMemoryClient mc) // 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); @@ -840,9 +838,6 @@ void CMSEXPORT cmsUnregisterPluginsTHR(cmsContext ContextID) _cmsRegisterMutexPlugin(ContextID, NULL); _cmsRegisterParallelizationPlugin(ContextID, NULL); - if (ctx->MemPool != NULL) - _cmsSubAllocDestroy(ctx->MemPool); - ctx->MemPool = NULL; } @@ -1010,7 +1005,14 @@ cmsContext CMSEXPORT cmsDupContext(cmsContext ContextID, void* NewUserData) // The ContextID can no longer be used in any THR operation. void CMSEXPORT cmsDeleteContext(cmsContext ContextID) { - if (ContextID != NULL) { + if (ContextID == NULL) { + + cmsUnregisterPlugins(); + if (globalContext.MemPool != NULL) + _cmsSubAllocDestroy(globalContext.MemPool); + globalContext.MemPool = NULL; + } + else { struct _cmsContext_struct* ctx = (struct _cmsContext_struct*) ContextID; struct _cmsContext_struct fakeContext; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c index c0816347d24..537f6854067 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c index cf4a13968d1..8a01f7ec685 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -152,10 +152,9 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Convert black to Lab cmsDoTransform(xform, Black, &Lab, 1); - // Force it to be neutral, clip to max. L* of 50 + // Force it to be neutral, check for inconsistences Lab.a = Lab.b = 0; - if (Lab.L > 50) Lab.L = 50; - if (Lab.L < 0) Lab.L = 0; + if (Lab.L > 50 || Lab.L < 0) Lab.L = 0; // Free the resources cmsDeleteTransform(xform); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c index 4300d164df6..3e1486ae3ae 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssm.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c index 898b5e8ffd6..7b07b6b9cf4 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -1549,6 +1549,12 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU if (!_cmsReadUInt32Number(io, &Len)) goto Error; if (!_cmsReadUInt32Number(io, &Offset)) goto Error; + // Offset MUST be even because it indexes a block of utf16 chars. + // Tricky profiles that uses odd positions will not work anyway + // because the whole utf16 block is previously converted to wchar_t + // and sizeof this type may be of 4 bytes. On Linux systems, for example. + if (Offset & 1) goto Error; + // Check for overflow if (Offset < (SizeOfHeader + 8)) goto Error; if (((Offset + Len) < Len) || ((Offset + Len) > SizeOfTag + 8)) goto Error; @@ -1576,8 +1582,12 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU } else { - Block = (wchar_t*) _cmsMalloc(self ->ContextID, SizeOfTag); + // Make sure this is an even utf16 size. + if (SizeOfTag & 1) goto Error; + + Block = (wchar_t*) _cmsCalloc(self ->ContextID, 1, SizeOfTag); if (Block == NULL) goto Error; + NumOfWchar = SizeOfTag / sizeof(wchar_t); if (!_cmsReadWCharArray(io, NumOfWchar, Block)) { _cmsFree(self->ContextID, Block); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c index 6d15f1fde13..6ce04796174 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c index 96bad5de7ca..27d71803531 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmswtpnt.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -244,12 +244,15 @@ cmsBool ComputeChromaticAdaptation(cmsMAT3* Conversion, _cmsMAT3eval(&ConeSourceRGB, Chad, &ConeSourceXYZ); _cmsMAT3eval(&ConeDestRGB, Chad, &ConeDestXYZ); + if ((fabs(ConeSourceRGB.n[0]) < MATRIX_DET_TOLERANCE) || + (fabs(ConeSourceRGB.n[1]) < MATRIX_DET_TOLERANCE) || + (fabs(ConeSourceRGB.n[2]) < MATRIX_DET_TOLERANCE)) return FALSE; + // Build matrix _cmsVEC3init(&Cone.v[0], ConeDestRGB.n[0]/ConeSourceRGB.n[0], 0.0, 0.0); _cmsVEC3init(&Cone.v[1], 0.0, ConeDestRGB.n[1]/ConeSourceRGB.n[1], 0.0); _cmsVEC3init(&Cone.v[2], 0.0, 0.0, ConeDestRGB.n[2]/ConeSourceRGB.n[2]); - // Normalize _cmsMAT3per(&Tmp, &Cone, Chad); _cmsMAT3per(Conversion, &Chad_Inv, &Tmp); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c index 8b8f831f0af..3f3ad28c6c4 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h index ab122f3b342..d5b8c477f23 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.14 +// Version 2.15 // #ifndef _lcms2_H @@ -110,7 +110,7 @@ extern "C" { #endif // Version/release -#define LCMS_VERSION 2140 +#define LCMS_VERSION 2150 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -256,7 +256,7 @@ typedef int cmsBool; // Calling convention -- this is hardly platform and compiler dependent -#ifdef CMS_IS_WINDOWS_ +#if defined(CMS_IS_WINDOWS_) && !defined(__GNUC__) # if defined(CMS_DLL) || defined(CMS_DLL_BUILD) # ifdef __BORLANDC__ # define CMSEXPORT __stdcall _export diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h index 3999e24d771..4c29a6c0218 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h @@ -27,10 +27,9 @@ // However, the following notice accompanied the original version of this // file: // - // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h index 1dc1a4661e2..e7e7bd1f0ce 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_plugin.h @@ -30,7 +30,7 @@ //--------------------------------------------------------------------------------- // // Little Color Management System -// Copyright (c) 1998-2022 Marti Maria Saguer +// Copyright (c) 1998-2023 Marti Maria Saguer // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the "Software"), From 8bacf0b5911fc65acc518ff12cd776b7fe4c0c8f Mon Sep 17 00:00:00 2001 From: Ekaterina Vergizova Date: Fri, 22 Aug 2025 00:08:38 +0300 Subject: [PATCH 3/3] Backport 2921ad6bb89c91ef7992a1eefa93e9a670512f54 --- THIRD_PARTY_README | 40 +- .../native/sun/java2d/cmm/lcms/cmsalpha.c | 26 +- .../native/sun/java2d/cmm/lcms/cmscgats.c | 487 ++++++++++++++---- .../native/sun/java2d/cmm/lcms/cmscnvrt.c | 41 +- .../share/native/sun/java2d/cmm/lcms/cmserr.c | 7 +- .../native/sun/java2d/cmm/lcms/cmsgamma.c | 28 +- .../share/native/sun/java2d/cmm/lcms/cmsgmt.c | 4 +- .../share/native/sun/java2d/cmm/lcms/cmsio0.c | 27 +- .../share/native/sun/java2d/cmm/lcms/cmsio1.c | 12 +- .../share/native/sun/java2d/cmm/lcms/cmslut.c | 11 +- .../native/sun/java2d/cmm/lcms/cmsnamed.c | 250 ++++++++- .../share/native/sun/java2d/cmm/lcms/cmsopt.c | 14 +- .../native/sun/java2d/cmm/lcms/cmspack.c | 185 ++++++- .../native/sun/java2d/cmm/lcms/cmsplugin.c | 21 +- .../share/native/sun/java2d/cmm/lcms/cmsps2.c | 187 +++---- .../native/sun/java2d/cmm/lcms/cmssamp.c | 2 +- .../native/sun/java2d/cmm/lcms/cmstypes.c | 271 +++++++++- .../native/sun/java2d/cmm/lcms/cmsvirt.c | 137 ++++- .../native/sun/java2d/cmm/lcms/cmsxform.c | 15 +- .../share/native/sun/java2d/cmm/lcms/lcms2.h | 53 +- .../sun/java2d/cmm/lcms/lcms2_internal.h | 7 +- 21 files changed, 1465 insertions(+), 360 deletions(-) diff --git a/THIRD_PARTY_README b/THIRD_PARTY_README index 9bf39e98664..4df2d4ebc53 100644 --- a/THIRD_PARTY_README +++ b/THIRD_PARTY_README @@ -1725,38 +1725,32 @@ THE SOFTWARE. ------------------------------------------------------------------------------- -%% This notice is provided with respect to Little CMS 2.15, which may be +%% This notice is provided with respect to Little CMS 2.16, which may be included with JRE 8, JDK 8, and OpenJDK 8. --- begin of LICENSE --- -README.1ST file information +MIT License -LittleCMS core is released under MIT License - ---------------------------------- - -Little CMS -Copyright (c) 1998-2023 Marti Maria Saguer +Copyright (C) 1998-2023 Marti Maria Saguer Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject -to the following conditions: +a copy of this software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation +the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. --------------------------------- The below license applies to the following files: @@ -1772,7 +1766,6 @@ Users of this code must verify correctness for their application. AUTHORS File Information: - Main Author ------------ Marti Maria @@ -1816,6 +1809,7 @@ Philipp Knechtges Amyspark Lovell Fuller Eli Schwartz +Diogo Teles Sant'Anna Special Thanks -------------- diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c index e69259e8a51..78d3ca6b671 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsalpha.c @@ -431,7 +431,7 @@ static cmsFormatterAlphaFn FormattersAlpha[6][6] = { // This function computes the distance from each component to the next one in bytes. static -void ComputeIncrementsForChunky(cmsUInt32Number Format, +cmsBool ComputeIncrementsForChunky(cmsUInt32Number Format, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) { @@ -445,7 +445,7 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, // Sanity check if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) - return; + return FALSE; memset(channels, 0, sizeof(channels)); @@ -482,13 +482,15 @@ void ComputeIncrementsForChunky(cmsUInt32Number Format, for (i = 0; i < extra; i++) ComponentStartingOrder[i] = channels[i + nchannels]; + + return TRUE; } // On planar configurations, the distance is the stride added to any non-negative static -void ComputeIncrementsForPlanar(cmsUInt32Number Format, +cmsBool ComputeIncrementsForPlanar(cmsUInt32Number Format, cmsUInt32Number BytesPerPlane, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) @@ -502,7 +504,7 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format, // Sanity check if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS) - return; + return FALSE; memset(channels, 0, sizeof(channels)); @@ -538,29 +540,29 @@ void ComputeIncrementsForPlanar(cmsUInt32Number Format, for (i = 0; i < extra; i++) ComponentStartingOrder[i] = channels[i + nchannels]; + + return TRUE; } // Dispatcher por chunky and planar RGB static -void ComputeComponentIncrements(cmsUInt32Number Format, +cmsBool ComputeComponentIncrements(cmsUInt32Number Format, cmsUInt32Number BytesPerPlane, cmsUInt32Number ComponentStartingOrder[], cmsUInt32Number ComponentPointerIncrements[]) { if (T_PLANAR(Format)) { - ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); + return ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements); } else { - ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); + return ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements); } } - - // Handles extra channels copying alpha if requested by the flags void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, void* out, @@ -595,8 +597,10 @@ void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in, return; // Compute the increments - ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements); - ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements); + if (!ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements)) + return; + if (!ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements)) + return; // Check for conversions 8, 16, half, float, dbl copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c index 9d0aea27d73..57725ae4731 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscgats.c @@ -87,7 +87,7 @@ typedef enum { SEOF, // End of stream SSYNERROR, // Syntax error found on stream - // Keywords + // IT8 symbols SBEGIN_DATA, SBEGIN_DATA_FORMAT, @@ -95,7 +95,19 @@ typedef enum { SEND_DATA_FORMAT, SKEYWORD, SDATA_FORMAT_ID, - SINCLUDE + SINCLUDE, + + // Cube symbols + + SDOMAIN_MAX, + SDOMAIN_MIN, + S_LUT1D_SIZE, + S_LUT1D_INPUT_RANGE, + S_LUT3D_SIZE, + S_LUT3D_INPUT_RANGE, + S_LUT_IN_VIDEO_RANGE, + S_LUT_OUT_VIDEO_RANGE, + STITLE } SYMBOL; @@ -178,6 +190,10 @@ typedef struct struct_it8 { cmsUInt32Number TablesCount; // How many tables in this stream cmsUInt32Number nTable; // The actual table + // Partser type + cmsBool IsCUBE; + + // Tables TABLE Tab[MAXTABLES]; // Memory management @@ -237,8 +253,8 @@ typedef struct { } KEYWORD; -// The keyword->symbol translation table. Sorting is required. -static const KEYWORD TabKeys[] = { +// The keyword->symbol translation tables. Sorting is required. +static const KEYWORD TabKeysIT8[] = { {"$INCLUDE", SINCLUDE}, // This is an extension! {".INCLUDE", SINCLUDE}, // This is an extension! @@ -251,7 +267,25 @@ static const KEYWORD TabKeys[] = { {"KEYWORD", SKEYWORD} }; -#define NUMKEYS (sizeof(TabKeys)/sizeof(KEYWORD)) +#define NUMKEYS_IT8 (sizeof(TabKeysIT8)/sizeof(KEYWORD)) + +static const KEYWORD TabKeysCUBE[] = { + + {"DOMAIN_MAX", SDOMAIN_MAX }, + {"DOMAIN_MIN", SDOMAIN_MIN }, + {"LUT_1D_SIZE", S_LUT1D_SIZE }, + {"LUT_1D_INPUT_RANGE", S_LUT1D_INPUT_RANGE }, + {"LUT_3D_SIZE", S_LUT3D_SIZE }, + {"LUT_3D_INPUT_RANGE", S_LUT3D_INPUT_RANGE }, + {"LUT_IN_VIDEO_RANGE", S_LUT_IN_VIDEO_RANGE }, + {"LUT_OUT_VIDEO_RANGE", S_LUT_OUT_VIDEO_RANGE }, + {"TITLE", STITLE } + +}; + +#define NUMKEYS_CUBE (sizeof(TabKeysCUBE)/sizeof(KEYWORD)) + + // Predefined properties @@ -455,7 +489,7 @@ void StringCat(string* s, const char* c) static cmsBool isseparator(int c) { - return (c == ' ') || (c == '\t') ; + return (c == ' ') || (c == '\t'); } // Checks whatever c is a valid identifier char @@ -476,7 +510,7 @@ cmsBool isidchar(int c) static cmsBool isfirstidchar(int c) { - return !isdigit(c) && ismiddle(c); + return c != '-' && !isdigit(c) && ismiddle(c); } // Guess whether the supplied path looks like an absolute path @@ -515,13 +549,13 @@ cmsBool BuildAbsolutePath(const char *relPath, const char *basePath, char *buffe // Already absolute? if (isabsolutepath(relPath)) { - strncpy(buffer, relPath, MaxLen); + memcpy(buffer, relPath, MaxLen); buffer[MaxLen-1] = 0; return TRUE; } // No, search for last - strncpy(buffer, basePath, MaxLen); + memcpy(buffer, basePath, MaxLen); buffer[MaxLen-1] = 0; tail = strrchr(buffer, DIR_CHAR); @@ -603,10 +637,10 @@ void NextCh(cmsIT8* it8) // Try to see if current identifier is a keyword, if so return the referred symbol static -SYMBOL BinSrchKey(const char *id) +SYMBOL BinSrchKey(const char *id, int NumKeys, const KEYWORD* TabKeys) { int l = 1; - int r = NUMKEYS; + int r = NumKeys; int x, res; while (r >= l) @@ -776,7 +810,7 @@ cmsFloat64Number ParseFloatNumber(const char *Buffer) } -// Reads a string, special case to avoid infinite resursion on .include +// Reads a string, special case to avoid infinite recursion on .include static void InStringSymbol(cmsIT8* it8) { @@ -833,7 +867,9 @@ void InSymbol(cmsIT8* it8) } while (isidchar(it8->ch)); - key = BinSrchKey(StringPtr(it8->id)); + key = BinSrchKey(StringPtr(it8->id), + it8->IsCUBE ? NUMKEYS_CUBE : NUMKEYS_IT8, + it8->IsCUBE ? TabKeysCUBE : TabKeysIT8); if (key == SUNDEFINED) it8->sy = SIDENT; else it8->sy = key; @@ -942,6 +978,7 @@ void InSymbol(cmsIT8* it8) snprintf(buffer, sizeof(buffer), it8 ->DoubleFormatter, it8->dnum); } + StringClear(it8->id); StringCat(it8->id, buffer); do { @@ -971,7 +1008,7 @@ void InSymbol(cmsIT8* it8) // Next line case '\r': NextCh(it8); - if (it8 ->ch == '\n') + if (it8->ch == '\n') NextCh(it8); it8->sy = SEOLN; it8->lineno++; @@ -1292,7 +1329,12 @@ KEYVALUE* AddToList(cmsIT8* it8, KEYVALUE** Head, const char *Key, const char *S // This may work for editing properties - // return SynError(it8, "duplicate key <%s>", Key); + if (cmsstrcasecmp(Key, "NUMBER_OF_FIELDS") == 0 || + cmsstrcasecmp(Key, "NUMBER_OF_SETS") == 0) { + + SynError(it8, "duplicate key <%s>", Key); + return NULL; + } } else { @@ -1413,6 +1455,8 @@ cmsHANDLE CMSEXPORT cmsIT8Alloc(cmsContext ContextID) it8->MemoryBlock = NULL; it8->MemorySink = NULL; + it8->IsCUBE = FALSE; + it8 ->nTable = 0; it8->ContextID = ContextID; @@ -1694,7 +1738,7 @@ char* GetData(cmsIT8* it8, int nSet, int nField) int nSamples = t -> nSamples; int nPatches = t -> nPatches; - if (nSet >= nPatches || nField >= nSamples) + if (nSet < 0 || nSet >= nPatches || nField < 0 || nField >= nSamples) return NULL; if (!t->Data) return NULL; @@ -1879,11 +1923,14 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) WriteStr(fp, " "); nSamples = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_FIELDS")); - for (i = 0; i < nSamples; i++) { + if (nSamples <= t->nSamples) { - WriteStr(fp, t->DataFormat[i]); - WriteStr(fp, ((i == (nSamples-1)) ? "\n" : "\t")); - } + for (i = 0; i < nSamples; i++) { + + WriteStr(fp, t->DataFormat[i]); + WriteStr(fp, ((i == (nSamples - 1)) ? "\n" : "\t")); + } + } WriteStr (fp, "END_DATA_FORMAT\n"); } @@ -1893,39 +1940,42 @@ void WriteDataFormat(SAVESTREAM* fp, cmsIT8* it8) static void WriteData(SAVESTREAM* fp, cmsIT8* it8) { - int i, j; + int i, j, nPatches; TABLE* t = GetTable(it8); if (!t->Data) return; WriteStr (fp, "BEGIN_DATA\n"); - t->nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); + nPatches = satoi(cmsIT8GetProperty(it8, "NUMBER_OF_SETS")); - for (i = 0; i < t-> nPatches; i++) { + if (nPatches <= t->nPatches) { - WriteStr(fp, " "); + for (i = 0; i < nPatches; i++) { - for (j = 0; j < t->nSamples; j++) { + WriteStr(fp, " "); - char *ptr = t->Data[i*t->nSamples+j]; + for (j = 0; j < t->nSamples; j++) { - if (ptr == NULL) WriteStr(fp, "\"\""); - else { - // If value contains whitespace, enclose within quote + char* ptr = t->Data[i * t->nSamples + j]; - if (strchr(ptr, ' ') != NULL) { + if (ptr == NULL) WriteStr(fp, "\"\""); + else { + // If value contains whitespace, enclose within quote - WriteStr(fp, "\""); - WriteStr(fp, ptr); - WriteStr(fp, "\""); - } - else - WriteStr(fp, ptr); - } + if (strchr(ptr, ' ') != NULL) { - WriteStr(fp, ((j == (t->nSamples-1)) ? "\n" : "\t")); - } + WriteStr(fp, "\""); + WriteStr(fp, ptr); + WriteStr(fp, "\""); + } + else + WriteStr(fp, ptr); + } + + WriteStr(fp, ((j == (t->nSamples - 1)) ? "\n" : "\t")); + } + } } WriteStr (fp, "END_DATA\n"); } @@ -1946,15 +1996,29 @@ cmsBool CMSEXPORT cmsIT8SaveToFile(cmsHANDLE hIT8, const char* cFileName) for (i=0; i < it8 ->TablesCount; i++) { - cmsIT8SetTable(hIT8, i); - WriteHeader(it8, &sd); - WriteDataFormat(&sd, it8); - WriteData(&sd, it8); + TABLE* t; + + if (cmsIT8SetTable(hIT8, i) < 0) goto Error; + + /** + * Check for wrong data + */ + t = GetTable(it8); + if (t->Data == NULL) goto Error; + if (t->DataFormat == NULL) goto Error; + + WriteHeader(it8, &sd); + WriteDataFormat(&sd, it8); + WriteData(&sd, it8); } if (fclose(sd.stream) != 0) return FALSE; - return TRUE; + +Error: + fclose(sd.stream); + return FALSE; + } @@ -2331,78 +2395,72 @@ void CookPointers(cmsIT8* it8) int idField, i; char* Fld; cmsUInt32Number j; - cmsUInt32Number nOldTable = it8 ->nTable; + cmsUInt32Number nOldTable = it8->nTable; - for (j=0; j < it8 ->TablesCount; j++) { + for (j = 0; j < it8->TablesCount; j++) { - TABLE* t = it8 ->Tab + j; + TABLE* t = it8->Tab + j; - t -> SampleID = 0; - it8 ->nTable = j; + t->SampleID = 0; + it8->nTable = j; - for (idField = 0; idField < t -> nSamples; idField++) - { - if (t ->DataFormat == NULL){ - SynError(it8, "Undefined DATA_FORMAT"); - return; - } + for (idField = 0; idField < t->nSamples; idField++) + { + if (t->DataFormat == NULL) { + SynError(it8, "Undefined DATA_FORMAT"); + return; + } - Fld = t->DataFormat[idField]; - if (!Fld) continue; + Fld = t->DataFormat[idField]; + if (!Fld) continue; - if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { + if (cmsstrcasecmp(Fld, "SAMPLE_ID") == 0) { - t -> SampleID = idField; - } + t->SampleID = idField; + } - // "LABEL" is an extension. It keeps references to forward tables + // "LABEL" is an extension. It keeps references to forward tables - if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') { + if ((cmsstrcasecmp(Fld, "LABEL") == 0) || Fld[0] == '$') { - // Search for table references... - for (i = 0; i < t->nPatches; i++) { + // Search for table references... + for (i = 0; i < t->nPatches; i++) { - char* Label = GetData(it8, i, idField); + char* Label = GetData(it8, i, idField); - if (Label) { + if (Label) { - cmsUInt32Number k; + cmsUInt32Number k; - // This is the label, search for a table containing - // this property + // This is the label, search for a table containing + // this property - for (k = 0; k < it8->TablesCount; k++) { + for (k = 0; k < it8->TablesCount; k++) { - TABLE* Table = it8->Tab + k; - KEYVALUE* p; + TABLE* Table = it8->Tab + k; + KEYVALUE* p; - if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { + if (IsAvailableOnList(Table->HeaderList, Label, NULL, &p)) { - // Available, keep type and table - char Buffer[256]; + // Available, keep type and table + char Buffer[256]; - char* Type = p->Value; - int nTable = (int)k; + char* Type = p->Value; + int nTable = (int)k; - snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type); + snprintf(Buffer, 255, "%s %d %s", Label, nTable, Type); - SetData(it8, i, idField, Buffer); + SetData(it8, i, idField, Buffer); + } } } - - } - } - - } - - } } - it8 ->nTable = nOldTable; + it8->nTable = nOldTable; } // Try to infere if the file is a CGATS/IT8 file at all. Read first line @@ -2493,7 +2551,7 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm if (it8->MemoryBlock == NULL) { cmsIT8Free(hIT8); - return FALSE; + return NULL; } strncpy(it8 ->MemoryBlock, (const char*) Ptr, len); @@ -2505,7 +2563,7 @@ cmsHANDLE CMSEXPORT cmsIT8LoadFromMem(cmsContext ContextID, const void *Ptr, cm if (!ParseIT8(it8, type-1)) { cmsIT8Free(hIT8); - return FALSE; + return NULL; } CookPointers(it8); @@ -2602,17 +2660,17 @@ cmsUInt32Number CMSEXPORT cmsIT8EnumProperties(cmsHANDLE hIT8, char ***PropertyN } - 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; - } + 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; } - *PropertyNames = Props; + + } + *PropertyNames = Props; return n; } @@ -2972,3 +3030,236 @@ void CMSEXPORT cmsIT8DefineDblFormat(cmsHANDLE hIT8, const char* Formatter) it8 ->DoubleFormatter[sizeof(it8 ->DoubleFormatter)-1] = 0; } + +static +cmsBool ReadNumbers(cmsIT8* cube, int n, cmsFloat64Number* arr) +{ + int i; + + for (i = 0; i < n; i++) { + + if (cube->sy == SINUM) + arr[i] = cube->inum; + else + if (cube->sy == SDNUM) + arr[i] = cube->dnum; + else + return SynError(cube, "Number expected"); + + InSymbol(cube); + } + + return CheckEOLN(cube); +} + +static +cmsBool ParseCube(cmsIT8* cube, cmsStage** Shaper, cmsStage** CLUT, char title[]) +{ + cmsFloat64Number domain_min[3] = { 0, 0, 0 }; + cmsFloat64Number domain_max[3] = { 1.0, 1.0, 1.0 }; + cmsFloat64Number check_0_1[2] = { 0, 1.0 }; + int shaper_size = 0; + int lut_size = 0; + int i; + + InSymbol(cube); + + while (cube->sy != SEOF) { + switch (cube->sy) + { + // Set profile description + case STITLE: + InSymbol(cube); + if (!Check(cube, SSTRING, "Title string expected")) return FALSE; + memcpy(title, StringPtr(cube->str), MAXSTR); + title[MAXSTR - 1] = 0; + InSymbol(cube); + break; + + // Define domain + case SDOMAIN_MIN: + InSymbol(cube); + if (!ReadNumbers(cube, 3, domain_min)) return FALSE; + break; + + case SDOMAIN_MAX: + InSymbol(cube); + if (!ReadNumbers(cube, 3, domain_max)) return FALSE; + break; + + // Define shaper + case S_LUT1D_SIZE: + InSymbol(cube); + if (!Check(cube, SINUM, "Shaper size expected")) return FALSE; + shaper_size = cube->inum; + InSymbol(cube); + break; + + // Deefine CLUT + case S_LUT3D_SIZE: + InSymbol(cube); + if (!Check(cube, SINUM, "LUT size expected")) return FALSE; + lut_size = cube->inum; + InSymbol(cube); + break; + + // Range. If present, has to be 0..1.0 + case S_LUT1D_INPUT_RANGE: + case S_LUT3D_INPUT_RANGE: + InSymbol(cube); + if (!ReadNumbers(cube, 2, check_0_1)) return FALSE; + if (check_0_1[0] != 0 || check_0_1[1] != 1.0) { + return SynError(cube, "Unsupported format"); + } + break; + + case SEOLN: + InSymbol(cube); + break; + + default: + case S_LUT_IN_VIDEO_RANGE: + case S_LUT_OUT_VIDEO_RANGE: + return SynError(cube, "Unsupported format"); + + // Read and create tables + case SINUM: + case SDNUM: + + if (shaper_size > 0) { + + cmsToneCurve* curves[3]; + cmsFloat32Number* shapers = (cmsFloat32Number*)_cmsMalloc(cube->ContextID, 3 * shaper_size * sizeof(cmsFloat32Number)); + if (shapers == NULL) return FALSE; + + for (i = 0; i < shaper_size; i++) { + + cmsFloat64Number nums[3]; + + if (!ReadNumbers(cube, 3, nums)) return FALSE; + + shapers[i + 0] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0])); + shapers[i + 1 * shaper_size] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1])); + shapers[i + 2 * shaper_size] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2])); + } + + for (i = 0; i < 3; i++) { + + curves[i] = cmsBuildTabulatedToneCurveFloat(cube->ContextID, shaper_size, + &shapers[i * shaper_size]); + if (curves[i] == NULL) return FALSE; + } + + *Shaper = cmsStageAllocToneCurves(cube->ContextID, 3, curves); + + cmsFreeToneCurveTriple(curves); + } + + if (lut_size > 0) { + + int nodes = lut_size * lut_size * lut_size; + + cmsFloat32Number* lut_table = _cmsMalloc(cube->ContextID, nodes * 3 * sizeof(cmsFloat32Number)); + if (lut_table == NULL) return FALSE; + + for (i = 0; i < nodes; i++) { + + cmsFloat64Number nums[3]; + + if (!ReadNumbers(cube, 3, nums)) return FALSE; + + lut_table[i * 3 + 2] = (cmsFloat32Number) ((nums[0] - domain_min[0]) / (domain_max[0] - domain_min[0])); + lut_table[i * 3 + 1] = (cmsFloat32Number) ((nums[1] - domain_min[1]) / (domain_max[1] - domain_min[1])); + lut_table[i * 3 + 0] = (cmsFloat32Number) ((nums[2] - domain_min[2]) / (domain_max[2] - domain_min[2])); + } + + *CLUT = cmsStageAllocCLutFloat(cube->ContextID, lut_size, 3, 3, lut_table); + _cmsFree(cube->ContextID, lut_table); + } + + if (!Check(cube, SEOF, "Extra symbols found in file")) return FALSE; + } + } + + return TRUE; +} + +// Share the parser to read .cube format and create RGB devicelink profiles +cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName) +{ + cmsHPROFILE hProfile = NULL; + cmsIT8* cube = NULL; + cmsPipeline* Pipeline = NULL; + cmsStage* CLUT = NULL; + cmsStage* Shaper = NULL; + cmsMLU* DescriptionMLU = NULL; + char title[MAXSTR]; + + _cmsAssert(cFileName != NULL); + + cube = (cmsIT8*) cmsIT8Alloc(ContextID); + if (!cube) return NULL; + + cube->IsCUBE = TRUE; + cube->FileStack[0]->Stream = fopen(cFileName, "rt"); + + if (!cube->FileStack[0]->Stream) goto Done; + + strncpy(cube->FileStack[0]->FileName, cFileName, cmsMAX_PATH - 1); + cube->FileStack[0]->FileName[cmsMAX_PATH - 1] = 0; + + if (!ParseCube(cube, &Shaper, &CLUT, title)) goto Done; + + // Success on parsing, let's create the profile + hProfile = cmsCreateProfilePlaceholder(ContextID); + if (!hProfile) goto Done; + + cmsSetProfileVersion(hProfile, 4.4); + + cmsSetDeviceClass(hProfile, cmsSigLinkClass); + cmsSetColorSpace(hProfile, cmsSigRgbData); + cmsSetPCS(hProfile, cmsSigRgbData); + + cmsSetHeaderRenderingIntent(hProfile, INTENT_PERCEPTUAL); + + // Creates a Pipeline to hold CLUT and shaper + Pipeline = cmsPipelineAlloc(ContextID, 3, 3); + if (Pipeline == NULL) goto Done; + + // Populates the pipeline + if (Shaper != NULL) { + if (!cmsPipelineInsertStage(Pipeline, cmsAT_BEGIN, Shaper)) + goto Done; + } + + if (CLUT != NULL) { + if (!cmsPipelineInsertStage(Pipeline, cmsAT_END, CLUT)) + goto Done; + } + + // Propagate the description. We put no copyright because we know + // nothing on the copyrighted state of the .cube + DescriptionMLU = cmsMLUalloc(ContextID, 1); + if (!cmsMLUsetUTF8(DescriptionMLU, cmsNoLanguage, cmsNoCountry, title)) goto Done; + + // Flush the tags + if (!cmsWriteTag(hProfile, cmsSigProfileDescriptionTag, DescriptionMLU)) goto Done; + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, (void*)Pipeline)) goto Done; + +Done: + + if (DescriptionMLU != NULL) + cmsMLUfree(DescriptionMLU); + + if (Pipeline != NULL) + cmsPipelineFree(Pipeline); + + cmsIT8Free((cmsHANDLE) cube); + + return hProfile; +} + +cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName) +{ + return cmsCreateDeviceLinkFromCubeFileTHR(NULL, cFileName); +} diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c index b73d594f2ec..d18865b15b9 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmscnvrt.c @@ -263,7 +263,7 @@ cmsFloat64Number CHAD2Temp(const cmsMAT3* Chad) // Compute a CHAD based on a given temperature static - void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) +void Temp2CHAD(cmsMAT3* Chad, cmsFloat64Number Temp) { cmsCIEXYZ White; cmsCIExyY ChromaticityOfWhite; @@ -744,6 +744,16 @@ int BlackPreservingGrayOnlySampler(CMSREGISTER const cmsUInt16Number In[], CMSRE return TRUE; } + +// Check whatever the profile is a CMYK->CMYK devicelink +static +cmsBool is_cmyk_devicelink(cmsHPROFILE hProfile) +{ + return cmsGetDeviceClass(hProfile) == cmsSigLinkClass && + cmsGetColorSpace(hProfile) == cmsSigCmykData && + cmsGetColorSpace(hProfile) == cmsSigCmykData; +} + // This is the entry for black-preserving K-only intents, which are non-ICC static cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, @@ -776,14 +786,16 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, lastProfilePos = nProfiles - 1; hLastProfile = hProfiles[lastProfilePos]; - while (lastProfilePos > 1) + // Skip CMYK->CMYK devicelinks on ending + while (is_cmyk_devicelink(hLastProfile)) { - hLastProfile = hProfiles[--lastProfilePos]; - if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData || - cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass) + if (lastProfilePos < 2) break; + + hLastProfile = hProfiles[--lastProfilePos]; } + preservationProfilesCount = lastProfilePos + 1; // Check for non-cmyk profiles @@ -800,7 +812,7 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, // Create a LUT holding normal ICC transform bp.cmyk2cmyk = DefaultICCintents(ContextID, - preservationProfilesCount, + preservationProfilesCount, ICCIntents, hProfiles, BPC, @@ -812,7 +824,7 @@ cmsPipeline* BlackPreservingKOnlyIntents(cmsContext ContextID, // Now, compute the tone curve bp.KTone = _cmsBuildKToneCurve(ContextID, 4096, - preservationProfilesCount, + preservationProfilesCount, ICCIntents, hProfiles, BPC, @@ -1002,12 +1014,13 @@ cmsPipeline* BlackPreservingKPlaneIntents(cmsContext ContextID, lastProfilePos = nProfiles - 1; hLastProfile = hProfiles[lastProfilePos]; - while (lastProfilePos > 1) + // Skip CMYK->CMYK devicelinks on ending + while (is_cmyk_devicelink(hLastProfile)) { - hLastProfile = hProfiles[--lastProfilePos]; - if (cmsGetColorSpace(hLastProfile) != cmsSigCmykData || - cmsGetDeviceClass(hLastProfile) != cmsSigLinkClass) + if (lastProfilePos < 2) break; + + hLastProfile = hProfiles[--lastProfilePos]; } preservationProfilesCount = lastProfilePos + 1; @@ -1177,8 +1190,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn cmsIntentsList* pt; cmsUInt32Number nIntents; - - for (nIntents=0, pt = ctx->Intents; pt != NULL; pt = pt -> Next) + for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1191,7 +1203,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn nIntents++; } - for (nIntents=0, pt = DefaultIntents; pt != NULL; pt = pt -> Next) + for (pt = ctx->Intents; pt != NULL; pt = pt -> Next) { if (nIntents < nMax) { if (Codes != NULL) @@ -1203,6 +1215,7 @@ cmsUInt32Number CMSEXPORT cmsGetSupportedIntentsTHR(cmsContext ContextID, cmsUIn nIntents++; } + return nIntents; } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c index 739cc0b2c98..9fb7db89c9a 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmserr.c @@ -101,7 +101,7 @@ long int CMSEXPORT cmsfilelength(FILE* f) // // This is the interface to low-level memory management routines. By default a simple // wrapping to malloc/free/realloc is provided, although there is a limit on the max -// amount of memoy that can be reclaimed. This is mostly as a safety feature to prevent +// amount of memory that can be reclaimed. This is mostly as a safety feature to prevent // bogus or evil code to allocate huge blocks that otherwise lcms would never need. #define MAX_MEMORY_FOR_ALLOC ((cmsUInt32Number)(1024U*1024U*512U)) @@ -121,7 +121,8 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase* Plug static void* _cmsMallocDefaultFn(cmsContext ContextID, cmsUInt32Number size) { - if (size > MAX_MEMORY_FOR_ALLOC) return NULL; // Never allow over maximum + // Never allow 0 or over maximum + if (size == 0 || size > MAX_MEMORY_FOR_ALLOC) return NULL; return (void*) malloc(size); @@ -263,7 +264,7 @@ cmsBool _cmsRegisterMemHandlerPlugin(cmsContext ContextID, cmsPluginBase *Data) // NULL forces to reset to defaults. In this special case, the defaults are stored in the context structure. // Remaining plug-ins does NOT have any copy in the context structure, but this is somehow special as the - // context internal data should be malloce'd by using those functions. + // context internal data should be malloc'ed by using those functions. if (Data == NULL) { struct _cmsContext_struct* ctx = ( struct _cmsContext_struct*) ContextID; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c index 08409434064..8e489a43c55 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgamma.c @@ -329,6 +329,10 @@ cmsToneCurve* AllocateToneCurveStruct(cmsContext ContextID, cmsUInt32Number nEnt return p; Error: + for (i=0; i < nSegments; i++) { + if (p ->Segments && p ->Segments[i].SampledPoints) _cmsFree(ContextID, p ->Segments[i].SampledPoints); + if (p ->SegInterp && p ->SegInterp[i]) _cmsFree(ContextID, p ->SegInterp[i]); + } if (p -> SegInterp) _cmsFree(ContextID, p -> SegInterp); if (p -> Segments) _cmsFree(ContextID, p -> Segments); if (p -> Evals) _cmsFree(ContextID, p -> Evals); @@ -622,10 +626,16 @@ cmsFloat64Number DefaultEvalParametricFn(cmsInt32Number Type, const cmsFloat64Nu case 6: e = Params[1]*R + Params[2]; - if (e < 0) - Val = Params[3]; - else - Val = pow(e, Params[0]) + Params[3]; + // On gamma 1.0, don't clamp + if (Params[0] == 1.0) { + Val = e + Params[3]; + } + else { + if (e < 0) + Val = Params[3]; + else + Val = pow(e, Params[0]) + Params[3]; + } break; // ((Y - c) ^1/Gamma - b) / a @@ -1520,13 +1530,13 @@ cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Num return (sum / n); // The mean } +// Retrieve segments on tone curves -// Retrieve parameters on one-segment tone curves - -cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t) +const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t) { _cmsAssert(t != NULL); - if (t->nSegments != 1) return NULL; - return t->Segments[0].Params; + if (n < 0 || n >= (cmsInt32Number) t->nSegments) return NULL; + return t->Segments + n; } + diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c index 60a01aa5088..e9ee73b52cd 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsgmt.c @@ -248,7 +248,7 @@ int GamutSampler(CMSREGISTER const cmsUInt16Number In[], CMSREGISTER cmsUInt16Nu cmsUInt16Number Proof[cmsMAXCHANNELS], Proof2[cmsMAXCHANNELS]; cmsFloat64Number dE1, dE2, ErrorRatio; - // Assume in-gamut by default. + // Assume in-gamut by default. NEVER READ, USED FOR DEBUG PURPOSES. ErrorRatio = 1.0; // Convert input to Lab @@ -625,7 +625,7 @@ cmsBool CMSEXPORT cmsDesaturateLab(cmsCIELab* Lab, // Actually, doing that "well" is quite hard, since every component may behave completely different. // Since the true point of this function is to detect suitable optimizations, I am imposing some requirements // that simplifies things: only RGB, and only profiles that can got in both directions. -// The algorithm obtains Y from a syntetical gray R=G=B. Then least squares fitting is used to estimate gamma. +// The algorithm obtains Y from a synthetical gray R=G=B. Then least squares fitting is used to estimate gamma. // For gamma close to 1.0, RGB is linear. On profiles not supported, -1 is returned. cmsFloat64Number CMSEXPORT cmsDetectRGBProfileGamma(cmsHPROFILE hProfile, cmsFloat64Number threshold) diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c index fe6b3d43a5a..1b32f9f4159 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio0.c @@ -560,6 +560,20 @@ cmsHPROFILE CMSEXPORT cmsCreateProfilePlaceholder(cmsContext ContextID) // Set default version Icc ->Version = 0x02100000; + // Set default CMM (that's me!) + Icc ->CMM = lcmsSignature; + + // Set default creator + // Created by LittleCMS (that's me!) + Icc ->creator = lcmsSignature; + + // Set default platform +#ifdef CMS_IS_WINDOWS_ + Icc ->platform = cmsSigMicrosoft; +#else + Icc ->platform = cmsSigMacintosh; +#endif + // Set default device class Icc->DeviceClass = cmsSigDisplayClass; @@ -813,11 +827,13 @@ cmsBool _cmsReadHeader(_cmsICCPROFILE* Icc) } // Adjust endianness of the used parameters + Icc -> CMM = _cmsAdjustEndianess32(Header.cmmId); Icc -> DeviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Header.deviceClass); Icc -> ColorSpace = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.colorSpace); Icc -> PCS = (cmsColorSpaceSignature) _cmsAdjustEndianess32(Header.pcs); Icc -> RenderingIntent = _cmsAdjustEndianess32(Header.renderingIntent); + Icc -> platform = (cmsPlatformSignature)_cmsAdjustEndianess32(Header.platform); Icc -> flags = _cmsAdjustEndianess32(Header.flags); Icc -> manufacturer = _cmsAdjustEndianess32(Header.manufacturer); Icc -> model = _cmsAdjustEndianess32(Header.model); @@ -922,7 +938,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) cmsUInt32Number Count; Header.size = _cmsAdjustEndianess32(UsedSpace); - Header.cmmId = _cmsAdjustEndianess32(lcmsSignature); + Header.cmmId = _cmsAdjustEndianess32(Icc ->CMM); Header.version = _cmsAdjustEndianess32(Icc ->Version); Header.deviceClass = (cmsProfileClassSignature) _cmsAdjustEndianess32(Icc -> DeviceClass); @@ -934,11 +950,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.magic = _cmsAdjustEndianess32(cmsMagicNumber); -#ifdef CMS_IS_WINDOWS_ - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMicrosoft); -#else - Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(cmsSigMacintosh); -#endif + Header.platform = (cmsPlatformSignature) _cmsAdjustEndianess32(Icc -> platform); Header.flags = _cmsAdjustEndianess32(Icc -> flags); Header.manufacturer = _cmsAdjustEndianess32(Icc -> manufacturer); @@ -954,8 +966,7 @@ cmsBool _cmsWriteHeader(_cmsICCPROFILE* Icc, cmsUInt32Number UsedSpace) Header.illuminant.Y = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Y)); Header.illuminant.Z = (cmsS15Fixed16Number) _cmsAdjustEndianess32((cmsUInt32Number) _cmsDoubleTo15Fixed16(cmsD50_XYZ()->Z)); - // Created by LittleCMS (that's me!) - Header.creator = _cmsAdjustEndianess32(lcmsSignature); + Header.creator = _cmsAdjustEndianess32(Icc ->creator); memset(&Header.reserved, 0, sizeof(Header.reserved)); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c index bd8a832ac40..e42d4d38987 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsio1.c @@ -607,7 +607,7 @@ cmsPipeline* _cmsReadFloatOutputTag(cmsHPROFILE hProfile, cmsTagSignature tagFlo return NULL; } -// Create an output MPE LUT from agiven profile. Version mismatches are handled here +// Create an output MPE LUT from a given profile. Version mismatches are handled here cmsPipeline* CMSEXPORT _cmsReadOutputLUT(cmsHPROFILE hProfile, cmsUInt32Number Intent) { cmsTagTypeSignature OriginalType; @@ -1056,3 +1056,13 @@ cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, cmsInfoT return cmsMLUgetASCII(mlu, LanguageCode, CountryCode, Buffer, BufferSize); } + +cmsUInt32Number CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const cmsMLU* mlu = GetInfo(hProfile, Info); + if (mlu == NULL) return 0; + + return cmsMLUgetUTF8(mlu, LanguageCode, CountryCode, Buffer, BufferSize); +} diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c index 24114632ad0..b544c948625 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmslut.c @@ -504,6 +504,9 @@ cmsUInt32Number CubeSize(const cmsUInt32Number Dims[], cmsUInt32Number b) if (rv > UINT_MAX / dim) return 0; } + // Again, prevent overflow + if (rv > UINT_MAX / 15) return 0; + return rv; } @@ -843,7 +846,13 @@ cmsBool CMSEXPORT cmsStageSampleCLutFloat(cmsStage* mpe, cmsSAMPLERFLOAT Sampler cmsUInt32Number nInputs, nOutputs; cmsUInt32Number* nSamples; cmsFloat32Number In[MAX_INPUT_DIMENSIONS+1], Out[MAX_STAGE_CHANNELS]; - _cmsStageCLutData* clut = (_cmsStageCLutData*) mpe->Data; + _cmsStageCLutData* clut; + + if (mpe == NULL) return FALSE; + + clut = (_cmsStageCLutData*)mpe->Data; + + if (clut == NULL) return FALSE; nSamples = clut->Params ->nSamples; nInputs = clut->Params ->nInputs; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c index 04280180230..d3cd97d4aea 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsnamed.c @@ -229,17 +229,145 @@ void strFrom16(char str[3], cmsUInt16Number n) str[0] = (char)(n >> 8); str[1] = (char)n; str[2] = (char)0; +} + + +// Convert from UTF8 to wchar, returns len. +static +cmsUInt32Number decodeUTF8(wchar_t* out, const char* in) +{ + cmsUInt32Number codepoint = 0; + cmsUInt32Number size = 0; + + while (*in) + { + cmsUInt8Number ch = (cmsUInt8Number) *in; + + if (ch <= 0x7f) + { + codepoint = ch; + } + else if (ch <= 0xbf) + { + codepoint = (codepoint << 6) | (ch & 0x3f); + } + else if (ch <= 0xdf) + { + codepoint = ch & 0x1f; + } + else if (ch <= 0xef) + { + codepoint = ch & 0x0f; + } + else + { + codepoint = ch & 0x07; + } + + in++; + if (((*in & 0xc0) != 0x80) && (codepoint <= 0x10ffff)) + { + if (sizeof(wchar_t) > 2) + { + if (out) *out++ = (wchar_t) codepoint; + size++; + } + else + if (codepoint > 0xffff) + { + if (out) + { + *out++ = (wchar_t)(0xd800 + (codepoint >> 10)); + *out++ = (wchar_t)(0xdc00 + (codepoint & 0x03ff)); + size += 2; + } + } + else + if (codepoint < 0xd800 || codepoint >= 0xe000) + { + if (out) *out++ = (wchar_t) codepoint; + size++; + } + } + } + + return size; +} + +// Convert from wchar_t to UTF8 +static +cmsUInt32Number encodeUTF8(char* out, const wchar_t* in, cmsUInt32Number max_wchars, cmsUInt32Number max_chars) +{ + cmsUInt32Number codepoint = 0; + cmsUInt32Number size = 0; + cmsUInt32Number len_w = 0; + + while (*in && len_w < max_wchars) + { + if (*in >= 0xd800 && *in <= 0xdbff) + codepoint = ((*in - 0xd800) << 10) + 0x10000; + else + { + if (*in >= 0xdc00 && *in <= 0xdfff) + codepoint |= *in - 0xdc00; + else + codepoint = *in; + + if (codepoint <= 0x7f) + { + if (out && (size + 1 < max_chars)) *out++ = (char)codepoint; + size++; + } + + else if (codepoint <= 0x7ff) + { + if (out && (max_chars > 0) && (size + 2 < max_chars)) + { + *out++ = (char)(cmsUInt32Number)(0xc0 | ((codepoint >> 6) & 0x1f)); + *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); + } + size += 2; + } + else if (codepoint <= 0xffff) + { + if (out && (max_chars > 0) && (size + 3 < max_chars)) + { + *out++ = (char)(cmsUInt32Number)(0xe0 | ((codepoint >> 12) & 0x0f)); + *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f)); + *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); + } + size += 3; + } + else + { + if (out && (max_chars > 0) && (size + 4 < max_chars)) + { + *out++ = (char)(cmsUInt32Number)(0xf0 | ((codepoint >> 18) & 0x07)); + *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 12) & 0x3f)); + *out++ = (char)(cmsUInt32Number)(0x80 | ((codepoint >> 6) & 0x3f)); + *out++ = (char)(cmsUInt32Number)(0x80 | (codepoint & 0x3f)); + } + size += 4; + } + + codepoint = 0; + } + + in++; len_w++; + } + + return size; } // Add an ASCII entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) // In the case the user explicitly sets an empty string, we force a \0 cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* ASCIIString) { - cmsUInt32Number i, len = (cmsUInt32Number) strlen(ASCIIString); + cmsUInt32Number i, len = (cmsUInt32Number)strlen(ASCIIString); wchar_t* WStr; cmsBool rc; - cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Lang = strTo16(LanguageCode); cmsUInt16Number Cntry = strTo16(CountryCode); if (mlu == NULL) return FALSE; @@ -247,22 +375,56 @@ cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, const char LanguageCode[3], const // len == 0 would prevent operation, so we set a empty string pointing to zero if (len == 0) { - len = 1; + wchar_t empty = 0; + return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry); } - WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, len, sizeof(wchar_t)); + WStr = (wchar_t*)_cmsCalloc(mlu->ContextID, len, sizeof(wchar_t)); if (WStr == NULL) return FALSE; - for (i=0; i < len; i++) - WStr[i] = (wchar_t) ASCIIString[i]; + for (i = 0; i < len; i++) + WStr[i] = (wchar_t)ASCIIString[i]; - rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); + rc = AddMLUBlock(mlu, len * sizeof(wchar_t), WStr, Lang, Cntry); - _cmsFree(mlu ->ContextID, WStr); + _cmsFree(mlu->ContextID, WStr); return rc; } +// Add an UTF8 entry. Do not add any \0 termination (ICC1v43_2010-12.pdf page 61) +// In the case the user explicitly sets an empty string, we force a \0 +cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const char* UTF8String) +{ + cmsUInt32Number UTF8len; + wchar_t* WStr; + cmsBool rc; + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + if (mlu == NULL) return FALSE; + + if (*UTF8String == '\0') + { + wchar_t empty = 0; + return AddMLUBlock(mlu, sizeof(wchar_t), &empty, Lang, Cntry); + } + + // Len excluding terminator 0 + UTF8len = decodeUTF8(NULL, UTF8String); + + // Get space for dest + WStr = (wchar_t*) _cmsCalloc(mlu ->ContextID, UTF8len, sizeof(wchar_t)); + if (WStr == NULL) return FALSE; + + decodeUTF8(WStr, UTF8String); + + rc = AddMLUBlock(mlu, UTF8len * sizeof(wchar_t), WStr, Lang, Cntry); + + _cmsFree(mlu ->ContextID, WStr); + return rc; +} + // We don't need any wcs support library static cmsUInt32Number mywcslen(const wchar_t *s) @@ -401,7 +563,7 @@ const wchar_t* _cmsMLUgetWide(const cmsMLU* mlu, if (v->StrW + v->Len > mlu->PoolSize) return NULL; - return(wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); + return (wchar_t*) ((cmsUInt8Number*) mlu ->MemPool + v ->StrW); } @@ -439,10 +601,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, // Precess each character for (i=0; i < ASCIIlen; i++) { - if (Wide[i] == 0) - Buffer[i] = 0; + wchar_t wc = Wide[i]; + + if (wc < 0xff) + Buffer[i] = (char)wc; else - Buffer[i] = (char) Wide[i]; + Buffer[i] = '?'; } // We put a termination "\0" @@ -450,6 +614,46 @@ cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, return ASCIIlen + 1; } + +// Obtain a UTF8 representation of the wide string. Setting buffer to NULL returns the len +cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize) +{ + const wchar_t *Wide; + cmsUInt32Number StrLen = 0; + cmsUInt32Number UTF8len; + + cmsUInt16Number Lang = strTo16(LanguageCode); + cmsUInt16Number Cntry = strTo16(CountryCode); + + // Sanitize + if (mlu == NULL) return 0; + + // Get WideChar + Wide = _cmsMLUgetWide(mlu, &StrLen, Lang, Cntry, NULL, NULL); + if (Wide == NULL) return 0; + + UTF8len = encodeUTF8(NULL, Wide, StrLen / sizeof(wchar_t), BufferSize); + + // Maybe we want only to know the len? + if (Buffer == NULL) return UTF8len + 1; // Note the zero at the end + + // No buffer size means no data + if (BufferSize <= 0) return 0; + + // Some clipping may be required + if (BufferSize < UTF8len + 1) + UTF8len = BufferSize - 1; + + // Process it + encodeUTF8(Buffer, Wide, StrLen / sizeof(wchar_t), BufferSize); + + // We put a termination "\0" + Buffer[UTF8len] = 0; + return UTF8len + 1; +} + // Obtain a wide representation of the MLU, on depending on current locale settings cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], @@ -470,12 +674,12 @@ cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, // Maybe we want only to know the len? if (Buffer == NULL) return StrLen + sizeof(wchar_t); - // No buffer size means no data - if (BufferSize <= 0) return 0; + // Invalid buffer size means no data + if (BufferSize < sizeof(wchar_t)) return 0; // Some clipping may be required if (BufferSize < StrLen + sizeof(wchar_t)) - StrLen = BufferSize - + sizeof(wchar_t); + StrLen = BufferSize - sizeof(wchar_t); memmove(Buffer, Wide, StrLen); Buffer[StrLen / sizeof(wchar_t)] = 0; @@ -843,13 +1047,19 @@ void CMSEXPORT cmsFreeProfileSequenceDescription(cmsSEQ* pseq) { cmsUInt32Number i; - for (i=0; i < pseq ->n; i++) { - if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); - if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); - if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); + if (pseq == NULL) + return; + + if (pseq ->seq != NULL) { + for (i=0; i < pseq ->n; i++) { + if (pseq ->seq[i].Manufacturer != NULL) cmsMLUfree(pseq ->seq[i].Manufacturer); + if (pseq ->seq[i].Model != NULL) cmsMLUfree(pseq ->seq[i].Model); + if (pseq ->seq[i].Description != NULL) cmsMLUfree(pseq ->seq[i].Description); + } + + _cmsFree(pseq ->ContextID, pseq ->seq); } - if (pseq ->seq != NULL) _cmsFree(pseq ->ContextID, pseq ->seq); _cmsFree(pseq -> ContextID, pseq); } diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c index 3e81ae1df1b..421a4f4a701 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsopt.c @@ -212,6 +212,7 @@ cmsBool isFloatMatrixIdentity(const cmsMAT3* a) return TRUE; } + // if two adjacent matrices are found, multiply them. static cmsBool _MultiplyMatrix(cmsPipeline* Lut) @@ -1142,14 +1143,17 @@ cmsBool OptimizeByComputingLinearization(cmsPipeline** Lut, cmsUInt32Number Inte // Store result in curve for (t=0; t < OriginalLut ->InputChannels; t++) - Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); + { + if (Trans[t]->Table16 != NULL) + Trans[t] ->Table16[i] = _cmsQuickSaturateWord(Out[t] * 65535.0); + } } // Slope-limit the obtained curves for (t = 0; t < OriginalLut ->InputChannels; t++) SlopeLimiting(Trans[t]); - // Check for validity + // Check for validity. lIsLinear is here for debug purposes lIsSuitable = TRUE; lIsLinear = TRUE; for (t=0; (lIsSuitable && (t < OriginalLut ->InputChannels)); t++) { @@ -1753,6 +1757,8 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1); + if (Matrix1->InputChannels != 3 || Matrix1->OutputChannels != 3) return FALSE; + // Copy the matrix to our result memcpy(&res, Data->Double, sizeof(res)); @@ -1797,7 +1803,7 @@ cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt3 _cmsStageToneCurvesData* mpeC2 = (_cmsStageToneCurvesData*) cmsStageData(Curve2); // In this particular optimization, cache does not help as it takes more time to deal with - // the cache that with the pixel handling + // the cache than with the pixel handling *dwFlags |= cmsFLAGS_NOCACHE; // Setup the optimizarion routines @@ -1954,7 +1960,7 @@ cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID, for (mpe = cmsPipelineGetPtrToFirstStage(*PtrLut); mpe != NULL; mpe = cmsStageNext(mpe)) { - if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; + if (cmsStageType(mpe) == cmsSigNamedColorElemType) return FALSE; } // Try to get rid of identities and trivial conversions. diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c index da5fc6019d3..fc875995a80 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmspack.c @@ -2980,6 +2980,108 @@ cmsUInt8Number* PackFloatFrom16(CMSREGISTER _cmsTRANSFORM* info, // -------------------------------------------------------------------------------------------------------- +static +cmsUInt8Number* PackBytesFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt8Number* swap1 = (cmsUInt8Number*)output; + cmsFloat64Number v = 0; + cmsUInt8Number vv = 0; + cmsUInt32Number i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * 65535.0; + + if (Reverse) + v = 65535.0 - v; + + vv = FROM_16_TO_8(_cmsQuickSaturateWord(v)); + + if (Planar) + ((cmsUInt8Number*)output)[(i + start) * Stride] = vv; + else + ((cmsUInt8Number*)output)[i + start] = vv; + } + + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt8Number)); + *swap1 = vv; + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt8Number); + else + return output + (nChan + Extra) * sizeof(cmsUInt8Number); +} + +static +cmsUInt8Number* PackWordsFromFloat(_cmsTRANSFORM* info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsUInt32Number nChan = T_CHANNELS(info->OutputFormat); + cmsUInt32Number DoSwap = T_DOSWAP(info->OutputFormat); + cmsUInt32Number Reverse = T_FLAVOR(info->OutputFormat); + cmsUInt32Number Extra = T_EXTRA(info->OutputFormat); + cmsUInt32Number SwapFirst = T_SWAPFIRST(info->OutputFormat); + cmsUInt32Number Planar = T_PLANAR(info->OutputFormat); + cmsUInt32Number ExtraFirst = DoSwap ^ SwapFirst; + cmsUInt16Number* swap1 = (cmsUInt16Number*)output; + cmsFloat64Number v = 0; + cmsUInt16Number vv = 0; + cmsUInt32Number i, start = 0; + + if (ExtraFirst) + start = Extra; + + for (i = 0; i < nChan; i++) { + + cmsUInt32Number index = DoSwap ? (nChan - i - 1) : i; + + v = wOut[index] * 65535.0; + + if (Reverse) + v = 65535.0 - v; + + vv = _cmsQuickSaturateWord(v); + + if (Planar) + ((cmsUInt16Number*)output)[(i + start) * Stride] = vv; + else + ((cmsUInt16Number*)output)[i + start] = vv; + } + + if (Extra == 0 && SwapFirst) { + + memmove(swap1 + 1, swap1, (nChan - 1) * sizeof(cmsUInt16Number)); + *swap1 = vv; + } + + if (T_PLANAR(info->OutputFormat)) + return output + sizeof(cmsUInt16Number); + else + return output + (nChan + Extra) * sizeof(cmsUInt16Number); +} + + static cmsUInt8Number* PackFloatsFromFloat(_cmsTRANSFORM* info, cmsFloat32Number wOut[], @@ -3143,6 +3245,77 @@ cmsUInt8Number* PackLabDoubleFromFloat(_cmsTRANSFORM* Info, } +static +cmsUInt8Number* PackEncodedBytesLabV2FromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsUInt16Number wlab[3]; + + Lab.L = (cmsFloat64Number)(wOut[0] * 100.0); + Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0); + Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0); + + cmsFloat2LabEncoded(wlab, &Lab); + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + output[0] = wlab[0] >> 8; + output[Stride] = wlab[1] >> 8; + output[Stride*2] = wlab[2] >> 8; + + return output + 1; + } + else { + + output[0] = wlab[0] >> 8; + output[1] = wlab[1] >> 8; + output[2] = wlab[2] >> 8; + + return output + (3 + T_EXTRA(Info ->OutputFormat)); + } +} + +static +cmsUInt8Number* PackEncodedWordsLabV2FromFloat(_cmsTRANSFORM* Info, + cmsFloat32Number wOut[], + cmsUInt8Number* output, + cmsUInt32Number Stride) +{ + cmsCIELab Lab; + cmsUInt16Number wlab[3]; + + Lab.L = (cmsFloat64Number)(wOut[0] * 100.0); + Lab.a = (cmsFloat64Number)(wOut[1] * 255.0 - 128.0); + Lab.b = (cmsFloat64Number)(wOut[2] * 255.0 - 128.0); + + cmsFloat2LabEncodedV2(wlab, &Lab); + + if (T_PLANAR(Info -> OutputFormat)) { + + Stride /= PixelSize(Info->OutputFormat); + + ((cmsUInt16Number*) output)[0] = wlab[0]; + ((cmsUInt16Number*) output)[Stride] = wlab[1]; + ((cmsUInt16Number*) output)[Stride*2] = wlab[2]; + + return output + sizeof(cmsUInt16Number); + } + else { + + ((cmsUInt16Number*) output)[0] = wlab[0]; + ((cmsUInt16Number*) output)[1] = wlab[1]; + ((cmsUInt16Number*) output)[2] = wlab[2]; + + return output + (3 + T_EXTRA(Info ->OutputFormat)) * sizeof(cmsUInt16Number); + } +} + + // From 0..1 range to 0..MAX_ENCODEABLE_XYZ static cmsUInt8Number* PackXYZFloatFromFloat(_cmsTRANSFORM* Info, @@ -3676,10 +3849,20 @@ static const cmsFormattersFloat OutputFormattersFloat[] = { { TYPE_Lab_DBL, ANYPLANAR|ANYEXTRA, PackLabDoubleFromFloat}, { TYPE_XYZ_DBL, ANYPLANAR|ANYEXTRA, PackXYZDoubleFromFloat}, + { TYPE_LabV2_8, ANYPLANAR|ANYEXTRA, PackEncodedBytesLabV2FromFloat}, + { TYPE_LabV2_16, ANYPLANAR|ANYEXTRA, PackEncodedWordsLabV2FromFloat}, + { FLOAT_SH(1)|BYTES_SH(4), ANYPLANAR| ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackFloatsFromFloat }, { FLOAT_SH(1)|BYTES_SH(0), ANYPLANAR| ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackDoublesFromFloat }, + + { BYTES_SH(2), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackWordsFromFloat }, + + { BYTES_SH(1), ANYPLANAR| + ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackBytesFromFloat }, + #ifndef CMS_NO_HALF_SUPPORT { FLOAT_SH(1)|BYTES_SH(2), ANYFLAVOR|ANYSWAPFIRST|ANYSWAP|ANYEXTRA|ANYCHANNELS|ANYSPACE, PackHalfFromFloat }, @@ -3890,7 +4073,7 @@ cmsUInt32Number CMSEXPORT cmsFormatterForPCSOfProfile(cmsHPROFILE hProfile, cmsU cmsColorSpaceSignature ColorSpace = cmsGetPCS(hProfile); cmsUInt32Number ColorSpaceBits = (cmsUInt32Number) _cmsLCMScolorSpace(ColorSpace); - cmsUInt32Number nOutputChans = cmsChannelsOf(ColorSpace); + cmsInt32Number nOutputChans = cmsChannelsOfColorSpace(ColorSpace); cmsUInt32Number Float = lIsFloat ? 1U : 0; // Unsupported color space? diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c index c2808bb9278..f84e0172c81 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsplugin.c @@ -393,12 +393,7 @@ cmsBool CMSEXPORT _cmsWriteXYZNumber(cmsIOHANDLER* io, const cmsCIEXYZ* XYZ) // from Fixed point 8.8 to double cmsFloat64Number CMSEXPORT _cms8Fixed8toDouble(cmsUInt16Number fixed8) { - cmsUInt8Number msb, lsb; - - lsb = (cmsUInt8Number) (fixed8 & 0xff); - msb = (cmsUInt8Number) (((cmsUInt16Number) fixed8 >> 8) & 0xff); - - return (cmsFloat64Number) ((cmsFloat64Number) msb + ((cmsFloat64Number) lsb / 256.0)); + return fixed8 / 256.0; } cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) @@ -410,19 +405,7 @@ cmsUInt16Number CMSEXPORT _cmsDoubleTo8Fixed8(cmsFloat64Number val) // from Fixed point 15.16 to double cmsFloat64Number CMSEXPORT _cms15Fixed16toDouble(cmsS15Fixed16Number fix32) { - cmsFloat64Number floater, sign, mid; - int Whole, FracPart; - - sign = (fix32 < 0 ? -1 : 1); - fix32 = abs(fix32); - - Whole = (cmsUInt16Number)(fix32 >> 16) & 0xffff; - FracPart = (cmsUInt16Number)(fix32 & 0xffff); - - mid = (cmsFloat64Number) FracPart / 65536.0; - floater = (cmsFloat64Number) Whole + mid; - - return sign * floater; + return fix32 / 65536.0; } // from double to Fixed point 15.16 diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c index 537f6854067..9a2ab464f31 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsps2.c @@ -460,48 +460,46 @@ void EmitLab2XYZ(cmsIOHANDLER* m) _cmsIOPrintf(m, "]\n"); } -static -void EmitSafeGuardBegin(cmsIOHANDLER* m, const char* name) -{ - _cmsIOPrintf(m, "%%LCMS2: Save previous definition of %s on the operand stack\n", name); - _cmsIOPrintf(m, "currentdict /%s known { /%s load } { null } ifelse\n", name, name); -} -static -void EmitSafeGuardEnd(cmsIOHANDLER* m, const char* name, int depth) -{ - _cmsIOPrintf(m, "%%LCMS2: Restore previous definition of %s\n", name); - if (depth > 1) { - // cycle topmost items on the stack to bring the previous definition to the front - _cmsIOPrintf(m, "%d -1 roll ", depth); - } - _cmsIOPrintf(m, "dup null eq { pop currentdict /%s undef } { /%s exch def } ifelse\n", name, name); -} // Outputs a table of words. It does use 16 bits static -void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) +void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table) { cmsUInt32Number i; cmsFloat64Number gamma; - if (Table == NULL) return; // Error + /** + * On error, empty tables or lienar assume gamma 1.0 + */ + if (Table == NULL || + Table->nEntries <= 0 || + cmsIsToneCurveLinear(Table)) { - if (Table ->nEntries <= 0) return; // Empty table + _cmsIOPrintf(m, "{ 1 } bind "); + return; + } - // Suppress whole if identity - if (cmsIsToneCurveLinear(Table)) return; // Check if is really an exponential. If so, emit "exp" gamma = cmsEstimateGamma(Table, 0.001); if (gamma > 0) { - _cmsIOPrintf(m, "/%s { %g exp } bind def\n", name, gamma); + _cmsIOPrintf(m, "{ %g exp } bind ", gamma); return; } - EmitSafeGuardBegin(m, "lcms2gammatable"); - _cmsIOPrintf(m, "/lcms2gammatable ["); + _cmsIOPrintf(m, "{ "); + + // Bounds check + EmitRangeCheck(m); + + // Emit intepolation code + + // PostScript code Stack + // =============== ======================== + // v + _cmsIOPrintf(m, " ["); for (i=0; i < Table->nEntries; i++) { if (i % 10 == 0) @@ -509,20 +507,8 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) _cmsIOPrintf(m, "%d ", Table->Table16[i]); } - _cmsIOPrintf(m, "] def\n"); + _cmsIOPrintf(m, "] "); // v tab - - // Emit interpolation code - - // PostScript code Stack - // =============== ======================== - // v - _cmsIOPrintf(m, "/%s {\n ", name); - - // Bounds check - EmitRangeCheck(m); - - _cmsIOPrintf(m, "\n //lcms2gammatable "); // v tab _cmsIOPrintf(m, "dup "); // v tab tab _cmsIOPrintf(m, "length 1 sub "); // v tab dom _cmsIOPrintf(m, "3 -1 roll "); // tab dom v @@ -549,9 +535,7 @@ void Emit1Gamma(cmsIOHANDLER* m, cmsToneCurve* Table, const char* name) _cmsIOPrintf(m, "add "); // y _cmsIOPrintf(m, "65535 div\n"); // result - _cmsIOPrintf(m, "} bind def\n"); - - EmitSafeGuardEnd(m, "lcms2gammatable", 1); + _cmsIOPrintf(m, " } bind "); } @@ -568,10 +552,10 @@ cmsBool GammaTableEquals(cmsUInt16Number* g1, cmsUInt16Number* g2, cmsUInt32Numb // Does write a set of gamma curves static -void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const char* nameprefix) +void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[]) { cmsUInt32Number i; - static char buffer[2048]; + for( i=0; i < n; i++ ) { @@ -579,12 +563,10 @@ void EmitNGamma(cmsIOHANDLER* m, cmsUInt32Number n, cmsToneCurve* g[], const cha if (i > 0 && GammaTableEquals(g[i-1]->Table16, g[i]->Table16, g[i-1]->nEntries, g[i]->nEntries)) { - _cmsIOPrintf(m, "/%s%d /%s%d load def\n", nameprefix, i, nameprefix, i-1); + _cmsIOPrintf(m, "dup "); } else { - snprintf(buffer, sizeof(buffer), "%s%d", nameprefix, (int) i); - buffer[sizeof(buffer)-1] = '\0'; - Emit1Gamma(m, g[i], buffer); + Emit1Gamma(m, g[i]); } } @@ -708,18 +690,21 @@ void WriteCLUT(cmsIOHANDLER* m, cmsStage* mpe, const char* PreMaj, sc.FixWhite = FixWhite; sc.ColorSpace = ColorSpace; - _cmsIOPrintf(m, "["); + if (sc.Pipeline != NULL && sc.Pipeline->Params != NULL) { - for (i=0; i < sc.Pipeline->Params->nInputs; i++) - _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); + _cmsIOPrintf(m, "["); - _cmsIOPrintf(m, " [\n"); + for (i = 0; i < sc.Pipeline->Params->nInputs; i++) + _cmsIOPrintf(m, " %d ", sc.Pipeline->Params->nSamples[i]); - cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*) &sc, SAMPLER_INSPECT); + _cmsIOPrintf(m, " [\n"); - _cmsIOPrintf(m, PostMin); - _cmsIOPrintf(m, PostMaj); - _cmsIOPrintf(m, "] "); + cmsStageSampleCLut16bit(mpe, OutputValueSampler, (void*)&sc, SAMPLER_INSPECT); + + _cmsIOPrintf(m, PostMin); + _cmsIOPrintf(m, PostMaj); + _cmsIOPrintf(m, "] "); + } } @@ -733,11 +718,11 @@ int EmitCIEBasedA(cmsIOHANDLER* m, cmsToneCurve* Curve, cmsCIEXYZ* BlackPoint) _cmsIOPrintf(m, "[ /CIEBasedA\n"); _cmsIOPrintf(m, " <<\n"); - EmitSafeGuardBegin(m, "lcms2gammaproc"); - Emit1Gamma(m, Curve, "lcms2gammaproc"); + _cmsIOPrintf(m, "/DecodeA "); + + Emit1Gamma(m, Curve); - _cmsIOPrintf(m, "/DecodeA /lcms2gammaproc load\n"); - EmitSafeGuardEnd(m, "lcms2gammaproc", 3); + _cmsIOPrintf(m, " \n"); _cmsIOPrintf(m, "/MatrixA [ 0.9642 1.0000 0.8249 ]\n"); _cmsIOPrintf(m, "/RangeLMN [ 0.0 0.9642 0.0 1.0000 0.0 0.8249 ]\n"); @@ -761,19 +746,11 @@ int EmitCIEBasedABC(cmsIOHANDLER* m, cmsFloat64Number* Matrix, cmsToneCurve** Cu _cmsIOPrintf(m, "[ /CIEBasedABC\n"); _cmsIOPrintf(m, "<<\n"); + _cmsIOPrintf(m, "/DecodeABC [ "); + + EmitNGamma(m, 3, CurveSet); - EmitSafeGuardBegin(m, "lcms2gammaproc0"); - EmitSafeGuardBegin(m, "lcms2gammaproc1"); - EmitSafeGuardBegin(m, "lcms2gammaproc2"); - EmitNGamma(m, 3, CurveSet, "lcms2gammaproc"); - _cmsIOPrintf(m, "/DecodeABC [\n"); - _cmsIOPrintf(m, " /lcms2gammaproc0 load\n"); - _cmsIOPrintf(m, " /lcms2gammaproc1 load\n"); - _cmsIOPrintf(m, " /lcms2gammaproc2 load\n"); _cmsIOPrintf(m, "]\n"); - EmitSafeGuardEnd(m, "lcms2gammaproc2", 3); - EmitSafeGuardEnd(m, "lcms2gammaproc1", 3); - EmitSafeGuardEnd(m, "lcms2gammaproc0", 3); _cmsIOPrintf(m, "/MatrixABC [ " ); @@ -805,10 +782,8 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte { const char* PreMaj; const char* PostMaj; - const char* PreMin, * PostMin; + const char* PreMin, *PostMin; cmsStage* mpe; - int i, numchans; - static char buffer[2048]; mpe = Pipeline->Elements; @@ -837,34 +812,18 @@ int EmitCIEBasedDEF(cmsIOHANDLER* m, cmsPipeline* Pipeline, cmsUInt32Number Inte if (cmsStageType(mpe) == cmsSigCurveSetElemType) { - numchans = (int) cmsStageOutputChannels(mpe); - for (i = 0; i < numchans; ++i) { - snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i); - buffer[sizeof(buffer) - 1] = '\0'; - EmitSafeGuardBegin(m, buffer); - } - EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe), "lcms2gammaproc"); - _cmsIOPrintf(m, "/DecodeDEF [\n"); - for (i = 0; i < numchans; ++i) { - snprintf(buffer, sizeof(buffer), " /lcms2gammaproc%d load\n", i); - buffer[sizeof(buffer) - 1] = '\0'; - _cmsIOPrintf(m, buffer); - } + _cmsIOPrintf(m, "/DecodeDEF [ "); + EmitNGamma(m, cmsStageOutputChannels(mpe), _cmsStageGetPtrToCurveSet(mpe)); _cmsIOPrintf(m, "]\n"); - for (i = numchans - 1; i >= 0; --i) { - snprintf(buffer, sizeof(buffer), "lcms2gammaproc%d", i); - buffer[sizeof(buffer) - 1] = '\0'; - EmitSafeGuardEnd(m, buffer, 3); - } - mpe = mpe->Next; + mpe = mpe ->Next; } if (cmsStageType(mpe) == cmsSigCLutElemType) { - _cmsIOPrintf(m, "/Table "); - WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature)0); - _cmsIOPrintf(m, "]\n"); + _cmsIOPrintf(m, "/Table "); + WriteCLUT(m, mpe, PreMaj, PostMaj, PreMin, PostMin, FALSE, (cmsColorSpaceSignature) 0); + _cmsIOPrintf(m, "]\n"); } EmitLab2XYZ(m); @@ -1024,9 +983,9 @@ int WriteInputMatrixShaper(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsStage* Matr for (j = 0; j < 3; j++) Mat.v[i].n[j] *= MAX_ENCODEABLE_XYZ; - rc = EmitCIEBasedABC(m, (cmsFloat64Number *)&Mat, - _cmsStageGetPtrToCurveSet(Shaper), - &BlackPointAdaptedToD50); + rc = EmitCIEBasedABC(m, (cmsFloat64Number *) &Mat, + _cmsStageGetPtrToCurveSet(Shaper), + &BlackPointAdaptedToD50); } else { @@ -1053,10 +1012,15 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); xform = cmsCreateTransform(hNamedColor, TYPE_NAMED_COLOR_INDEX, hLab, TYPE_Lab_DBL, Intent, 0); + cmsCloseProfile(hLab); + if (xform == NULL) return 0; NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; + if (NamedColorList == NULL) { + cmsDeleteTransform(xform); + return 0; + } _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s)\n", "Named color CSA"); @@ -1065,7 +1029,6 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number nColors = cmsNamedColorCount(NamedColorList); - for (i=0; i < nColors; i++) { cmsUInt16Number In[1]; @@ -1080,12 +1043,9 @@ int WriteNamedColorCSA(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number _cmsIOPrintf(m, " (%s) [ %.3f %.3f %.3f ]\n", ColorName, Lab.L, Lab.a, Lab.b); } - - _cmsIOPrintf(m, ">>\n"); cmsDeleteTransform(xform); - cmsCloseProfile(hLab); return 1; } @@ -1339,7 +1299,7 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent cmsUInt32Number InFrm = TYPE_Lab_16; cmsUInt32Number RelativeEncodingIntent; cmsColorSpaceSignature ColorSpace; - + cmsStage* first; hLab = cmsCreateLab4ProfileTHR(m ->ContextID, NULL); if (hLab == NULL) return 0; @@ -1366,7 +1326,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent cmsCloseProfile(hLab); if (xform == NULL) { - cmsSignalError(m ->ContextID, cmsERROR_COLORSPACE_CHECK, "Cannot create transform Lab -> Profile in CRD creation"); return 0; } @@ -1374,10 +1333,12 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent // Get a copy of the internal devicelink v = (_cmsTRANSFORM*) xform; DeviceLink = cmsPipelineDup(v ->Lut); - if (DeviceLink == NULL) return 0; - + if (DeviceLink == NULL) { + cmsDeleteTransform(xform); + return 0; + } - // We need a CLUT + // We need a CLUT dwFlags |= cmsFLAGS_FORCE_CLUT; _cmsOptimizePipeline(m->ContextID, &DeviceLink, RelativeEncodingIntent, &InFrm, &OutputFormat, &dwFlags); @@ -1404,8 +1365,10 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent _cmsIOPrintf(m, "/RenderTable "); - - WriteCLUT(m, cmsPipelineGetPtrToFirstStage(DeviceLink), "<", ">\n", "", "", lFixWhite, ColorSpace); + first = cmsPipelineGetPtrToFirstStage(DeviceLink); + if (first != NULL) { + WriteCLUT(m, first, "<", ">\n", "", "", lFixWhite, ColorSpace); + } _cmsIOPrintf(m, " %d {} bind ", nChannels); @@ -1414,7 +1377,6 @@ int WriteOutputLUT(cmsIOHANDLER* m, cmsHPROFILE hProfile, cmsUInt32Number Intent _cmsIOPrintf(m, "]\n"); - EmitIntent(m, Intent); _cmsIOPrintf(m, ">>\n"); @@ -1477,7 +1439,10 @@ int WriteNamedColorCRD(cmsIOHANDLER* m, cmsHPROFILE hNamedColor, cmsUInt32Number NamedColorList = cmsGetNamedColorList(xform); - if (NamedColorList == NULL) return 0; + if (NamedColorList == NULL) { + cmsDeleteTransform(xform); + return 0; + } _cmsIOPrintf(m, "<<\n"); _cmsIOPrintf(m, "(colorlistcomment) (%s) \n", "Named profile"); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c index 8a01f7ec685..74f5f4bff29 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmssamp.c @@ -152,7 +152,7 @@ cmsBool BlackPointAsDarkerColorant(cmsHPROFILE hInput, // Convert black to Lab cmsDoTransform(xform, Black, &Lab, 1); - // Force it to be neutral, check for inconsistences + // Force it to be neutral, check for inconsistencies Lab.a = Lab.b = 0; if (Lab.L > 50 || Lab.L < 0) Lab.L = 0; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c index 7b07b6b9cf4..862f393497a 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmstypes.c @@ -122,7 +122,7 @@ cmsBool RegisterTypesPlugin(cmsContext id, cmsPluginBase* Data, _cmsMemoryClient return TRUE; } -// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additons +// Return handler for a given type or NULL if not found. Shared between normal types and MPE. It first tries the additions // made by plug-ins and then the built-in defaults. static cmsTagTypeHandler* GetHandler(cmsTagTypeSignature sig, _cmsTagTypeLinkedList* PluginLinkedList, _cmsTagTypeLinkedList* DefaultLinkedList) @@ -954,6 +954,7 @@ static void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) { char* Text = NULL; + wchar_t* UnicodeString = NULL; cmsMLU* mlu = NULL; cmsUInt32Number AsciiCount; cmsUInt32Number i, UnicodeCode, UnicodeCount; @@ -973,7 +974,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND if (SizeOfTag < AsciiCount) return NULL; // All seems Ok, allocate the container - mlu = cmsMLUalloc(self ->ContextID, 1); + mlu = cmsMLUalloc(self ->ContextID, 2); if (mlu == NULL) return NULL; // As many memory as size of tag @@ -998,15 +999,30 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND if (!_cmsReadUInt32Number(io, &UnicodeCount)) goto Done; SizeOfTag -= 2* sizeof(cmsUInt32Number); - if (SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; + if (UnicodeCount == 0 || SizeOfTag < UnicodeCount*sizeof(cmsUInt16Number)) goto Done; + + UnicodeString = (wchar_t*)_cmsMallocZero(self->ContextID, (UnicodeCount + 1) * sizeof(wchar_t)); + if (UnicodeString == NULL) goto Done; + + if (!_cmsReadWCharArray(io, UnicodeCount, UnicodeString)) { + _cmsFree(self->ContextID, (void*)UnicodeString); + goto Done; + } + + UnicodeString[UnicodeCount] = 0; - for (i=0; i < UnicodeCount; i++) { - if (!io ->Read(io, &Dummy, sizeof(cmsUInt16Number), 1)) goto Done; + if (!cmsMLUsetWide(mlu, cmsV2Unicode, cmsV2Unicode, UnicodeString)) { + _cmsFree(self->ContextID, (void*)UnicodeString); + goto Done; } + + _cmsFree(self->ContextID, (void*)UnicodeString); + UnicodeString = NULL; + SizeOfTag -= UnicodeCount*sizeof(cmsUInt16Number); // Skip ScriptCode code if present. Some buggy profiles does have less - // data that stricttly required. We need to skip it as this type may come + // data that strictly required. We need to skip it as this type may come // embedded in other types. if (SizeOfTag >= sizeof(cmsUInt16Number) + sizeof(cmsUInt8Number) + 67) { @@ -1026,6 +1042,7 @@ void *Type_Text_Description_Read(struct _cms_typehandler_struct* self, cmsIOHAND return mlu; Error: + if (UnicodeString) _cmsFree(self->ContextID, (void*)UnicodeString); if (Text) _cmsFree(self ->ContextID, (void*) Text); if (mlu) cmsMLUfree(mlu); return NULL; @@ -1078,7 +1095,7 @@ cmsBool Type_Text_Description_Write(struct _cms_typehandler_struct* self, cmsIO // Get both representations. cmsMLUgetASCII(mlu, cmsNoLanguage, cmsNoCountry, Text, len * sizeof(char)); - cmsMLUgetWide(mlu, cmsNoLanguage, cmsNoCountry, Wide, len * sizeof(wchar_t)); + cmsMLUgetWide(mlu, cmsV2Unicode, cmsV2Unicode, Wide, len * sizeof(wchar_t)); } // Tell the real text len including the null terminator and padding @@ -1577,8 +1594,6 @@ void *Type_MLU_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsU if (SizeOfTag == 0) { Block = NULL; - NumOfWchar = 0; - } else { @@ -1940,7 +1955,7 @@ void *Type_LUT8_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cms // We only allow a specific MPE structure: Matrix plus prelin, plus clut, plus post-lin. static -cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) { cmsUInt32Number j, nTabSize, i; cmsUInt8Number val; @@ -1953,6 +1968,12 @@ cmsBool Type_LUT8_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // Disassemble the LUT into components. mpe = NewLUT -> Elements; + + if (mpe == NULL) { // Should never be empty. Corrupted? + cmsSignalError(self->ContextID, cmsERROR_UNKNOWN_EXTENSION, "empty LUT8 is not supported"); + return FALSE; + } + if (mpe ->Type == cmsSigMatrixElemType) { if (mpe->InputChannels != 3 || mpe->OutputChannels != 3) return FALSE; @@ -2694,8 +2715,8 @@ cmsBool WriteSetOfCurves(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, // If this is a table-based curve, use curve type even on V4 CurrentType = Type; - if ((Curves[i] ->nSegments == 0)|| - ((Curves[i]->nSegments == 2) && (Curves[i] ->Segments[1].Type == 0)) ) + if ((Curves[i] ->nSegments == 0) || // 16 bits tabulated + ((Curves[i]->nSegments == 3) && (Curves[i] ->Segments[1].Type == 0)) ) // Floating-point tabulated CurrentType = cmsSigCurveType; else if (Curves[i] ->Segments[0].Type < 0) @@ -4459,8 +4480,8 @@ void *Type_MPEclut_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, if (!_cmsReadUInt16Number(io, &InputChans)) return NULL; if (!_cmsReadUInt16Number(io, &OutputChans)) return NULL; - if (InputChans == 0) goto Error; - if (OutputChans == 0) goto Error; + if (InputChans == 0 || InputChans >= cmsMAXCHANNELS) goto Error; + if (OutputChans == 0 || OutputChans >= cmsMAXCHANNELS) goto Error; if (io ->Read(io, Dimensions8, sizeof(cmsUInt8Number), 16) != 16) goto Error; @@ -5250,11 +5271,13 @@ cmsBool WriteOneMLUC(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, _c } Before = io ->Tell(io); - e ->Offsets[i] = Before - BaseOffset; + if (e->Offsets != NULL) + e ->Offsets[i] = Before - BaseOffset; if (!Type_MLU_Write(self, io, (void*) mlu, 1)) return FALSE; - e ->Sizes[i] = io ->Tell(io) - Before; + if (e->Sizes != NULL) + e ->Sizes[i] = io ->Tell(io) - Before; return TRUE; } @@ -5499,6 +5522,216 @@ void Type_VideoSignal_Free(struct _cms_typehandler_struct* self, void* Ptr) _cmsFree(self->ContextID, Ptr); } + +// ******************************************************************************** +// Microsoft's MHC2 Type support +// ******************************************************************************** + +static +void SetIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4]) +{ + XYZ2XYZmatrix[0][0] = 1.0; XYZ2XYZmatrix[0][1] = 0.0; XYZ2XYZmatrix[0][2] = 0.0; XYZ2XYZmatrix[0][3] = 0.0; + XYZ2XYZmatrix[1][0] = 0.0; XYZ2XYZmatrix[1][1] = 1.0; XYZ2XYZmatrix[1][2] = 0.0; XYZ2XYZmatrix[1][3] = 0.0; + XYZ2XYZmatrix[2][0] = 0.0; XYZ2XYZmatrix[2][1] = 0.0; XYZ2XYZmatrix[2][2] = 1.0; XYZ2XYZmatrix[2][3] = 0.0; +} + +static +cmsBool CloseEnough(cmsFloat64Number a, cmsFloat64Number b) +{ + return fabs(b - a) < (1.0 / 65535.0); +} + +cmsBool IsIdentity(cmsFloat64Number XYZ2XYZmatrix[3][4]) +{ + cmsFloat64Number Identity[3][4]; + int i, j; + + SetIdentity(Identity); + + for (i = 0; i < 3; i++) + for (j = 0; j < 4; j++) + if (!CloseEnough(XYZ2XYZmatrix[i][j], Identity[i][j])) return FALSE; + + return TRUE; +} + +static +void Type_MHC2_Free(struct _cms_typehandler_struct* self, void* Ptr) +{ + cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr; + + if (mhc2->RedCurve != NULL) _cmsFree(self->ContextID, mhc2->RedCurve); + if (mhc2->GreenCurve != NULL) _cmsFree(self->ContextID, mhc2->GreenCurve); + if (mhc2->BlueCurve != NULL) _cmsFree(self->ContextID, mhc2->BlueCurve); + + _cmsFree(self->ContextID, Ptr); +} + +void* Type_MHC2_Dup(struct _cms_typehandler_struct* self, const void* Ptr, cmsUInt32Number n) +{ + cmsMHC2Type* mhc2 = _cmsDupMem(self->ContextID, Ptr, sizeof(cmsMHC2Type)); + + mhc2->RedCurve = _cmsDupMem(self->ContextID, mhc2->RedCurve, mhc2->CurveEntries*sizeof(cmsFloat64Number)); + mhc2->GreenCurve = _cmsDupMem(self->ContextID, mhc2->GreenCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number)); + mhc2->BlueCurve = _cmsDupMem(self->ContextID, mhc2->BlueCurve, mhc2->CurveEntries * sizeof(cmsFloat64Number)); + + if (mhc2->RedCurve == NULL || + mhc2->GreenCurve == NULL || + mhc2->BlueCurve == NULL) { + + Type_MHC2_Free(self, mhc2); + return NULL; + } + + return mhc2; + + cmsUNUSED_PARAMETER(n); +} + + +static +cmsBool WriteDoubles(cmsIOHANDLER* io, cmsUInt32Number n, cmsFloat64Number* Values) +{ + cmsUInt32Number i; + + for (i = 0; i < n; i++) { + + if (!_cmsWrite15Fixed16Number(io, *Values++)) return FALSE; + } + + return TRUE; +} + +static +cmsBool Type_MHC2_Write(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, void* Ptr, cmsUInt32Number nItems) +{ + cmsMHC2Type* mhc2 = (cmsMHC2Type*)Ptr; + cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase); + cmsUInt32Number TablesOffsetPos; + cmsUInt32Number MatrixOffset; + cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable; + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; + if (!_cmsWriteUInt32Number(io, mhc2->CurveEntries)) return FALSE; + + if (!_cmsWrite15Fixed16Number(io, mhc2->MinLuminance)) return FALSE; + if (!_cmsWrite15Fixed16Number(io, mhc2->PeakLuminance)) return FALSE; + + TablesOffsetPos = io->Tell(io); + + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Matrix + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Curve R + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Curve G + if (!_cmsWriteUInt32Number(io, 0)) return FALSE; // Curve B + + + if (IsIdentity(mhc2->XYZ2XYZmatrix)) + { + MatrixOffset = 0; + } + else + { + MatrixOffset = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, 3 * 4, &mhc2->XYZ2XYZmatrix[0][0])) return FALSE; + } + + OffsetRedTable = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->RedCurve)) return FALSE; + OffsetGreenTable = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->GreenCurve)) return FALSE; + OffsetBlueTable = io->Tell(io) - BaseOffset; + if (!WriteDoubles(io, mhc2->CurveEntries, mhc2->BlueCurve)) return FALSE; + + if (!io->Seek(io, TablesOffsetPos)) return FALSE; + + if (!_cmsWriteUInt32Number(io, MatrixOffset)) return FALSE; + if (!_cmsWriteUInt32Number(io, OffsetRedTable)) return FALSE; + if (!_cmsWriteUInt32Number(io, OffsetGreenTable)) return FALSE; + if (!_cmsWriteUInt32Number(io, OffsetBlueTable)) return FALSE; + + return TRUE; + + cmsUNUSED_PARAMETER(self); + cmsUNUSED_PARAMETER(nItems); +} + + +static +cmsBool ReadDoublesAt(cmsIOHANDLER* io, cmsUInt32Number At, cmsUInt32Number n, cmsFloat64Number* Values) +{ + cmsUInt32Number CurrentPos = io->Tell(io); + cmsUInt32Number i; + + if (!io->Seek(io, At)) return FALSE; + + for (i = 0; i < n; i++) { + + if (!_cmsRead15Fixed16Number(io, Values++)) return FALSE; + } + + if (!io->Seek(io, CurrentPos)) return FALSE; + + return TRUE; +} + +static +void* Type_MHC2_Read(struct _cms_typehandler_struct* self, cmsIOHANDLER* io, cmsUInt32Number* nItems, cmsUInt32Number SizeOfTag) +{ + cmsMHC2Type* mhc2 = NULL; + + cmsUInt32Number BaseOffset = io->Tell(io) - sizeof(_cmsTagBase); + cmsUInt32Number MatrixOffset; + cmsUInt32Number OffsetRedTable, OffsetGreenTable, OffsetBlueTable; + + if (!_cmsReadUInt32Number(io, NULL)) return NULL; + + mhc2 = (cmsMHC2Type*)_cmsCalloc(self->ContextID, 1, sizeof(cmsMHC2Type)); + if (mhc2 == NULL) return NULL; + + if (!_cmsReadUInt32Number(io, &mhc2->CurveEntries)) goto Error; + + if (mhc2->CurveEntries > 4096) goto Error; + + mhc2->RedCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number)); + mhc2->GreenCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number)); + mhc2->BlueCurve = (cmsFloat64Number*)_cmsCalloc(self->ContextID, mhc2->CurveEntries, sizeof(cmsFloat64Number)); + + if (mhc2->RedCurve == NULL || + mhc2->GreenCurve == NULL || + mhc2->BlueCurve == NULL) goto Error; + + if (!_cmsRead15Fixed16Number(io, &mhc2->MinLuminance)) goto Error; + if (!_cmsRead15Fixed16Number(io, &mhc2->PeakLuminance)) goto Error; + + if (!_cmsReadUInt32Number(io, &MatrixOffset)) goto Error; + if (!_cmsReadUInt32Number(io, &OffsetRedTable)) goto Error; + if (!_cmsReadUInt32Number(io, &OffsetGreenTable)) goto Error; + if (!_cmsReadUInt32Number(io, &OffsetBlueTable)) goto Error; + + if (MatrixOffset == 0) + SetIdentity(mhc2->XYZ2XYZmatrix); + else + { + if (!ReadDoublesAt(io, BaseOffset + MatrixOffset, 3*4, &mhc2->XYZ2XYZmatrix[0][0])) goto Error; + } + + if (!ReadDoublesAt(io, BaseOffset + OffsetRedTable, mhc2->CurveEntries, mhc2->RedCurve)) goto Error; + if (!ReadDoublesAt(io, BaseOffset + OffsetGreenTable, mhc2->CurveEntries, mhc2->GreenCurve)) goto Error; + if (!ReadDoublesAt(io, BaseOffset + OffsetBlueTable, mhc2->CurveEntries, mhc2->BlueCurve)) goto Error; + + // Success + *nItems = 1; + return mhc2; + +Error: + Type_MHC2_Free(self, mhc2); + return NULL; + + cmsUNUSED_PARAMETER(SizeOfTag); +} + + + // ******************************************************************************** // Type support main routines // ******************************************************************************** @@ -5538,7 +5771,8 @@ static const _cmsTagTypeLinkedList SupportedTagTypes[] = { {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 } +{TYPE_HANDLER(cmsSigVcgtType, vcgt), (_cmsTagTypeLinkedList*) &SupportedTagTypes[32] }, +{TYPE_HANDLER(cmsSigMHC2Type, MHC2), NULL } }; @@ -5734,7 +5968,8 @@ static _cmsTagLinkedList SupportedTags[] = { { cmsSigProfileDescriptionMLTag,{ 1, 1, { cmsSigMultiLocalizedUnicodeType}, NULL}, &SupportedTags[63]}, { cmsSigcicpTag, { 1, 1, { cmsSigcicpType}, NULL }, &SupportedTags[64]}, - { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, NULL} + { cmsSigArgyllArtsTag, { 9, 1, { cmsSigS15Fixed16ArrayType}, NULL}, &SupportedTags[65]}, + { cmsSigMHC2Tag, { 1, 1, { cmsSigMHC2Type }, NULL}, NULL} }; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c index 6ce04796174..e8d18d4ca9f 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsvirt.c @@ -435,10 +435,9 @@ cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext ContextID, if (Limit < 0.0 || Limit > 400) { - cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 0..400"); - if (Limit < 0) Limit = 0; + cmsSignalError(ContextID, cmsERROR_RANGE, "InkLimiting: Limit should be between 1..400"); + if (Limit < 1) Limit = 1; if (Limit > 400) Limit = 400; - } hICC = cmsCreateProfilePlaceholder(ContextID); @@ -701,6 +700,127 @@ cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void) return cmsCreate_sRGBProfileTHR(NULL); } +/** +* Oklab colorspace profile (experimental) +* +* This virtual profile cannot be saved as an ICC file +*/ +cmsHPROFILE cmsCreate_OkLabProfile(cmsContext ctx) +{ + cmsStage* XYZPCS = _cmsStageNormalizeFromXyzFloat(ctx); + cmsStage* PCSXYZ = _cmsStageNormalizeToXyzFloat(ctx); + + const double M_D65_D50[] = + { + 1.047886, 0.022919, -0.050216, + 0.029582, 0.990484, -0.017079, + -0.009252, 0.015073, 0.751678 + }; + + const double M_D50_D65[] = + { + 0.955512609517083, -0.023073214184645, 0.063308961782107, + -0.028324949364887, 1.009942432477107, 0.021054814890112, + 0.012328875695483, -0.020535835374141, 1.330713916450354 + }; + + cmsStage* D65toD50 = cmsStageAllocMatrix(ctx, 3, 3, M_D65_D50, NULL); + cmsStage* D50toD65 = cmsStageAllocMatrix(ctx, 3, 3, M_D50_D65, NULL); + + const double M_D65_LMS[] = + { + 0.8189330101, 0.3618667424, -0.1288597137, + 0.0329845436, 0.9293118715, 0.0361456387, + 0.0482003018, 0.2643662691, 0.6338517070 + }; + + const double M_LMS_D65[] = + { + 1.227013851103521, -0.557799980651822, 0.281256148966468, + -0.040580178423281, 1.112256869616830, -0.071676678665601, + -0.076381284505707, -0.421481978418013, 1.586163220440795 + }; + + cmsStage* D65toLMS = cmsStageAllocMatrix(ctx, 3, 3, M_D65_LMS, NULL); + cmsStage* LMStoD65 = cmsStageAllocMatrix(ctx, 3, 3, M_LMS_D65, NULL); + + cmsToneCurve* CubeRoot = cmsBuildGamma(ctx, 1.0 / 3.0); + cmsToneCurve* Cube = cmsBuildGamma(ctx, 3.0); + + cmsToneCurve* Roots[3] = { CubeRoot, CubeRoot, CubeRoot }; + cmsToneCurve* Cubes[3] = { Cube, Cube, Cube }; + + cmsStage* NonLinearityFw = cmsStageAllocToneCurves(ctx, 3, Roots); + cmsStage* NonLinearityRv = cmsStageAllocToneCurves(ctx, 3, Cubes); + + const double M_LMSprime_OkLab[] = + { + 0.2104542553, 0.7936177850, -0.0040720468, + 1.9779984951, -2.4285922050, 0.4505937099, + 0.0259040371, 0.7827717662, -0.8086757660 + }; + + const double M_OkLab_LMSprime[] = + { + 0.999999998450520, 0.396337792173768, 0.215803758060759, + 1.000000008881761, -0.105561342323656, -0.063854174771706, + 1.000000054672411, -0.089484182094966, -1.291485537864092 + }; + + cmsStage* LMSprime_OkLab = cmsStageAllocMatrix(ctx, 3, 3, M_LMSprime_OkLab, NULL); + cmsStage* OkLab_LMSprime = cmsStageAllocMatrix(ctx, 3, 3, M_OkLab_LMSprime, NULL); + + cmsPipeline* AToB = cmsPipelineAlloc(ctx, 3, 3); + cmsPipeline* BToA = cmsPipelineAlloc(ctx, 3, 3); + + cmsHPROFILE hProfile = cmsCreateProfilePlaceholder(ctx); + + cmsSetProfileVersion(hProfile, 4.4); + + cmsSetDeviceClass(hProfile, cmsSigColorSpaceClass); + cmsSetColorSpace(hProfile, cmsSig3colorData); + cmsSetPCS(hProfile, cmsSigXYZData); + + cmsSetHeaderRenderingIntent(hProfile, INTENT_RELATIVE_COLORIMETRIC); + + /** + * Conversion PCS (XYZ/D50) to OkLab + */ + if (!cmsPipelineInsertStage(BToA, cmsAT_END, PCSXYZ)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, D50toD65)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, D65toLMS)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, NonLinearityFw)) goto error; + if (!cmsPipelineInsertStage(BToA, cmsAT_END, LMSprime_OkLab)) goto error; + + if (!cmsWriteTag(hProfile, cmsSigBToA0Tag, BToA)) goto error; + + if (!cmsPipelineInsertStage(AToB, cmsAT_END, OkLab_LMSprime)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, NonLinearityRv)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, LMStoD65)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, D65toD50)) goto error; + if (!cmsPipelineInsertStage(AToB, cmsAT_END, XYZPCS)) goto error; + + if (!cmsWriteTag(hProfile, cmsSigAToB0Tag, AToB)) goto error; + + cmsPipelineFree(BToA); + cmsPipelineFree(AToB); + + cmsFreeToneCurve(CubeRoot); + cmsFreeToneCurve(Cube); + + return hProfile; + +error: + cmsPipelineFree(BToA); + cmsPipelineFree(AToB); + + cmsFreeToneCurve(CubeRoot); + cmsFreeToneCurve(Cube); + cmsCloseProfile(hProfile); + + return NULL; + +} typedef struct { @@ -1060,7 +1180,7 @@ cmsBool CheckOne(const cmsAllowedLUT* Tab, const cmsPipeline* Lut) for (n=0, mpe = Lut ->Elements; mpe != NULL; mpe = mpe ->Next, n++) { - if (n > Tab ->nTypes) return FALSE; + if (n >= Tab ->nTypes) return FALSE; if (cmsStageType(mpe) != Tab ->MpeTypes[n]) return FALSE; } @@ -1091,9 +1211,9 @@ const cmsAllowedLUT* FindCombination(const cmsPipeline* Lut, cmsBool IsV4, cmsTa cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat64Number Version, cmsUInt32Number dwFlags) { cmsHPROFILE hProfile = NULL; - cmsUInt32Number FrmIn, FrmOut; - cmsInt32Number ChansIn, ChansOut; - int ColorSpaceBitsIn, ColorSpaceBitsOut; + cmsUInt32Number FrmIn, FrmOut; + cmsInt32Number ChansIn, ChansOut; + int ColorSpaceBitsIn, ColorSpaceBitsOut; _cmsTRANSFORM* xform = (_cmsTRANSFORM*) hTransform; cmsPipeline* LUT = NULL; cmsStage* mpe; @@ -1104,6 +1224,9 @@ cmsHPROFILE CMSEXPORT cmsTransform2DeviceLink(cmsHTRANSFORM hTransform, cmsFloat _cmsAssert(hTransform != NULL); + // Check if the pipeline holding is valid + if (xform -> Lut == NULL) return NULL; + // Get the first mpe to check for named color mpe = cmsPipelineGetPtrToFirstStage(xform ->Lut); diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c index 3f3ad28c6c4..86afd7202fd 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/cmsxform.c @@ -943,7 +943,7 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, } // Check whatever this is a true floating point transform - if (_cmsFormatterIsFloat(*OutputFormat)) { + if (_cmsFormatterIsFloat(*InputFormat) || _cmsFormatterIsFloat(*OutputFormat)) { // Get formatter function always return a valid union, but the contents of this union may be NULL. p ->FromInputFloat = _cmsGetFormatter(ContextID, *InputFormat, cmsFormatterInput, CMS_PACK_FLAGS_FLOAT).FmtFloat; @@ -1018,6 +1018,19 @@ _cmsTRANSFORM* AllocEmptyTransform(cmsContext ContextID, cmsPipeline* lut, } } + /** + * Check consistency for alpha channel copy + */ + if (*dwFlags & cmsFLAGS_COPY_ALPHA) + { + if (T_EXTRA(*InputFormat) != T_EXTRA(*OutputFormat)) + { + cmsSignalError(ContextID, cmsERROR_NOT_SUITABLE, "Mismatched alpha channels"); + cmsDeleteTransform(p); + return NULL; + } + } + p ->InputFormat = *InputFormat; p ->OutputFormat = *OutputFormat; p ->dwOriginalFlags = *dwFlags; diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h index d5b8c477f23..2d9a8b1248f 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2.h @@ -52,7 +52,7 @@ // //--------------------------------------------------------------------------------- // -// Version 2.15 +// Version 2.16 // #ifndef _lcms2_H @@ -105,12 +105,15 @@ #ifndef CMS_USE_CPP_API # ifdef __cplusplus +# if __cplusplus >= 201703L +# define CMS_NO_REGISTER_KEYWORD 1 +# endif extern "C" { # endif #endif // Version/release -#define LCMS_VERSION 2150 +#define LCMS_VERSION 2160 // I will give the chance of redefining basic types for compilers that are not fully C99 compliant #ifndef CMS_BASIC_TYPES_ALREADY_DEFINED @@ -354,7 +357,8 @@ typedef enum { cmsSigUInt8ArrayType = 0x75693038, // 'ui08' cmsSigVcgtType = 0x76636774, // 'vcgt' cmsSigViewingConditionsType = 0x76696577, // 'view' - cmsSigXYZType = 0x58595A20 // 'XYZ ' + cmsSigXYZType = 0x58595A20, // 'XYZ ' + cmsSigMHC2Type = 0x4D484332 // 'MHC2' } cmsTagTypeSignature; @@ -432,7 +436,8 @@ typedef enum { cmsSigVcgtTag = 0x76636774, // 'vcgt' cmsSigMetaTag = 0x6D657461, // 'meta' cmsSigcicpTag = 0x63696370, // 'cicp' - cmsSigArgyllArtsTag = 0x61727473 // 'arts' + cmsSigArgyllArtsTag = 0x61727473, // 'arts' + cmsSigMHC2Tag = 0x4D484332 // 'MHC2' } cmsTagSignature; @@ -977,6 +982,7 @@ typedef void* cmsHTRANSFORM; #define TYPE_RGB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)) #define TYPE_BGR_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|CHANNELS_SH(3)|BYTES_SH(0)|DOSWAP_SH(1)) #define TYPE_CMYK_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|CHANNELS_SH(4)|BYTES_SH(0)) +#define TYPE_OKLAB_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_MCH3)|CHANNELS_SH(3)|BYTES_SH(0)) // IEEE 754-2008 "half" #define TYPE_GRAY_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|CHANNELS_SH(1)|BYTES_SH(2)) @@ -1077,6 +1083,19 @@ typedef struct { } cmsVideoSignalType; +typedef struct { + cmsUInt32Number CurveEntries; + cmsFloat64Number* RedCurve; + cmsFloat64Number* GreenCurve; + cmsFloat64Number* BlueCurve; + + cmsFloat64Number MinLuminance; // ST.2086 min luminance in nits + cmsFloat64Number PeakLuminance; // ST.2086 peak luminance in nits + + cmsFloat64Number XYZ2XYZmatrix[3][4]; + +} cmsMHC2Type; + // Get LittleCMS version (for shared objects) ----------------------------------------------------------------------------- @@ -1249,7 +1268,8 @@ CMSAPI cmsBool CMSEXPORT cmsIsToneCurveMonotonic(const cmsToneCurve* t CMSAPI cmsBool CMSEXPORT cmsIsToneCurveDescending(const cmsToneCurve* t); CMSAPI cmsInt32Number CMSEXPORT cmsGetToneCurveParametricType(const cmsToneCurve* t); CMSAPI cmsFloat64Number CMSEXPORT cmsEstimateGamma(const cmsToneCurve* t, cmsFloat64Number Precision); -CMSAPI cmsFloat64Number* CMSEXPORT cmsGetToneCurveParams(const cmsToneCurve* t); + +CMSAPI const cmsCurveSegment* CMSEXPORT cmsGetToneCurveSegment(cmsInt32Number n, const cmsToneCurve* t); // Tone curve tabular estimation CMSAPI cmsUInt32Number CMSEXPORT cmsGetToneCurveEstimatedTableEntries(const cmsToneCurve* t); @@ -1343,8 +1363,11 @@ CMSAPI cmsBool CMSEXPORT cmsSliceSpaceFloat(cmsUInt32Number nInputs, c typedef struct _cms_MLU_struct cmsMLU; -#define cmsNoLanguage "\0\0" -#define cmsNoCountry "\0\0" +#define cmsNoLanguage "\0\0" +#define cmsNoCountry "\0\0" + +// Special language/country to retrieve unicode field for description in V2 profiles. Use with care. +#define cmsV2Unicode "\xff\xff" CMSAPI cmsMLU* CMSEXPORT cmsMLUalloc(cmsContext ContextID, cmsUInt32Number nItems); CMSAPI void CMSEXPORT cmsMLUfree(cmsMLU* mlu); @@ -1356,6 +1379,9 @@ CMSAPI cmsBool CMSEXPORT cmsMLUsetASCII(cmsMLU* mlu, CMSAPI cmsBool CMSEXPORT cmsMLUsetWide(cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], const wchar_t* WideString); +CMSAPI cmsBool CMSEXPORT cmsMLUsetUTF8(cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + const char* UTF8String); CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], @@ -1364,6 +1390,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetASCII(const cmsMLU* mlu, CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetWide(const cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], wchar_t* Buffer, cmsUInt32Number BufferSize); +CMSAPI cmsUInt32Number CMSEXPORT cmsMLUgetUTF8(const cmsMLU* mlu, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize); + CMSAPI cmsBool CMSEXPORT cmsMLUgetTranslation(const cmsMLU* mlu, const char LanguageCode[3], const char CountryCode[3], @@ -1588,6 +1618,10 @@ CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoASCII(cmsHPROFILE hProfile, const char LanguageCode[3], const char CountryCode[3], char* Buffer, cmsUInt32Number BufferSize); +CMSAPI cmsUInt32Number CMSEXPORT cmsGetProfileInfoUTF8(cmsHPROFILE hProfile, cmsInfoType Info, + const char LanguageCode[3], const char CountryCode[3], + char* Buffer, cmsUInt32Number BufferSize); + // IO handlers ---------------------------------------------------------------------------------------------------------- typedef struct _cms_io_handler cmsIOHANDLER; @@ -1650,6 +1684,9 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLinkTHR(cmsContext C CMSAPI cmsHPROFILE CMSEXPORT cmsCreateInkLimitingDeviceLink(cmsColorSpaceSignature ColorSpace, cmsFloat64Number Limit); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFile(const char* cFileName); + +CMSAPI cmsHPROFILE CMSEXPORT cmsCreateDeviceLinkFromCubeFileTHR(cmsContext ContextID, const char* cFileName); CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2ProfileTHR(cmsContext ContextID, const cmsCIExyY* WhitePoint); CMSAPI cmsHPROFILE CMSEXPORT cmsCreateLab2Profile(const cmsCIExyY* WhitePoint); @@ -1662,6 +1699,8 @@ CMSAPI cmsHPROFILE CMSEXPORT cmsCreateXYZProfile(void); CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfileTHR(cmsContext ContextID); CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_sRGBProfile(void); +CMSAPI cmsHPROFILE CMSEXPORT cmsCreate_OkLabProfile(cmsContext ctx); + CMSAPI cmsHPROFILE CMSEXPORT cmsCreateBCHSWabstractProfileTHR(cmsContext ContextID, cmsUInt32Number nLUTPoints, cmsFloat64Number Bright, diff --git a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h index 4c29a6c0218..75973edad0d 100644 --- a/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h +++ b/jdk/src/share/native/sun/java2d/cmm/lcms/lcms2_internal.h @@ -288,6 +288,7 @@ typedef CRITICAL_SECTION _cmsMutex; #ifdef _MSC_VER # if (_MSC_VER >= 1800) # pragma warning(disable : 26135) +# pragma warning(disable : 4127) # endif #endif @@ -545,7 +546,7 @@ struct _cmsContext_struct { struct _cmsContext_struct* Next; // Points to next context in the new style _cmsSubAllocator* MemPool; // The memory pool that stores context data - void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is hold in the suballocator. + void* chunks[MemoryClientMax]; // array of pointers to client chunks. Memory itself is held in the suballocator. // If NULL, then it reverts to global Context0 _cmsMemPluginChunkType DefaultMemoryManager; // The allocators used for creating the context itself. Cannot be overridden @@ -839,6 +840,9 @@ typedef struct _cms_iccprofile_struct { // Creation time struct tm Created; + // Color management module identification + cmsUInt32Number CMM; + // Only most important items found in ICC profiles cmsUInt32Number Version; cmsProfileClassSignature DeviceClass; @@ -846,6 +850,7 @@ typedef struct _cms_iccprofile_struct { cmsColorSpaceSignature PCS; cmsUInt32Number RenderingIntent; + cmsPlatformSignature platform; cmsUInt32Number flags; cmsUInt32Number manufacturer, model; cmsUInt64Number attributes;