Index: src/core/SkColorSpaceXform.cpp |
diff --git a/src/core/SkColorSpaceXform.cpp b/src/core/SkColorSpaceXform.cpp |
index 5e362464b41d5d9470a9795a2eea9e5e23601bf5..cacb38878cd1cf86c0489b3775b5abea945df16c 100644 |
--- a/src/core/SkColorSpaceXform.cpp |
+++ b/src/core/SkColorSpaceXform.cpp |
@@ -6,7 +6,9 @@ |
*/ |
#include "SkColorPriv.h" |
+#include "SkColorSpace_A2B.h" |
#include "SkColorSpace_Base.h" |
+#include "SkColorSpace_XYZ.h" |
#include "SkColorSpacePriv.h" |
#include "SkColorSpaceXform_Base.h" |
#include "SkHalf.h" |
@@ -254,10 +256,10 @@ static const GammaFns<uint8_t> kFromLinear { |
// Build tables to transform src gamma to linear. |
template <typename T> |
static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, int gammaTableSize, |
- const SkColorSpace* space, const GammaFns<T>& fns, |
+ const SkColorSpace_XYZ* space, const GammaFns<T>& fns, |
bool gammasAreMatching) |
{ |
- switch (as_CSB(space)->gammaNamed()) { |
+ switch (space->gammaNamed()) { |
case kSRGB_SkGammaNamed: |
outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = fns.fSRGBTable; |
break; |
@@ -268,7 +270,7 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, |
outGammaTables[0] = outGammaTables[1] = outGammaTables[2] = nullptr; |
break; |
default: { |
- const SkGammas* gammas = as_CSB(space)->gammas(); |
+ const SkGammas* gammas = space->gammas(); |
SkASSERT(gammas); |
auto build_table = [=](int i) { |
@@ -326,7 +328,8 @@ static void build_gamma_tables(const T* outGammaTables[3], T* gammaTableStorage, |
} |
void SkColorSpaceXform_Base::BuildDstGammaTables(const uint8_t* dstGammaTables[3], |
- uint8_t* dstStorage, const SkColorSpace* space, |
+ uint8_t* dstStorage, |
+ const SkColorSpace_XYZ* space, |
bool gammasAreMatching) { |
build_gamma_tables(dstGammaTables, dstStorage, kDstGammaTableSize, space, kFromLinear, |
gammasAreMatching); |
@@ -355,13 +358,30 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace |
return nullptr; |
} |
+ if (SkColorSpace_Base::Type::kA2B == as_CSB(dstSpace)->type()) { |
+ SkColorSpacePrintf("A2B destinations not supported\n"); |
+ return nullptr; |
+ } |
+ |
+ if (SkColorSpace_Base::Type::kA2B == as_CSB(srcSpace)->type()) { |
+ // TODO (raftias): return an A2B-supporting SkColorSpaceXform here once the xform. |
+ // is implemented. SkColorSpaceXform_Base only supports XYZ+TRC based SkColorSpaces |
+ //SkColorSpace_A2B* src = static_cast<SkColorSpace_A2B*>(srcSpace); |
+ //SkColorSpace_XYZ* dst = static_cast<SkColorSpace_XYZ*>(dstSpace); |
+ //return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_A2B(src, dst)); |
+ SkColorSpacePrintf("A2B sources not supported (yet)\n"); |
+ return nullptr; |
+ } |
+ SkColorSpace_XYZ* srcSpaceXYZ = static_cast<SkColorSpace_XYZ*>(srcSpace); |
+ SkColorSpace_XYZ* dstSpaceXYZ = static_cast<SkColorSpace_XYZ*>(dstSpace); |
+ |
ColorSpaceMatch csm = kNone_ColorSpaceMatch; |
SkMatrix44 srcToDst(SkMatrix44::kUninitialized_Constructor); |
if (SkColorSpace::Equals(srcSpace, dstSpace)) { |
srcToDst.setIdentity(); |
csm = kFull_ColorSpaceMatch; |
} else { |
- srcToDst.setConcat(as_CSB(dstSpace)->fromXYZD50(), as_CSB(srcSpace)->toXYZD50()); |
+ srcToDst.setConcat(*dstSpaceXYZ->fromXYZD50(), *srcSpaceXYZ->toXYZD50()); |
if (is_almost_identity(srcToDst)) { |
srcToDst.setIdentity(); |
@@ -371,109 +391,109 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace |
switch (csm) { |
case kNone_ColorSpaceMatch: |
- switch (as_CSB(dstSpace)->gammaNamed()) { |
+ switch (dstSpaceXYZ->gammaNamed()) { |
case kSRGB_SkGammaNamed: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kSRGB_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
case k2Dot2Curve_SkGammaNamed: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, k2Dot2_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
case kLinear_SkGammaNamed: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kLinear_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
default: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
} |
case kGamut_ColorSpaceMatch: |
- switch (as_CSB(dstSpace)->gammaNamed()) { |
+ switch (dstSpaceXYZ->gammaNamed()) { |
case kSRGB_SkGammaNamed: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kSRGB_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
case k2Dot2Curve_SkGammaNamed: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, k2Dot2_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
case kLinear_SkGammaNamed: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kLinear_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
default: |
- if (srcSpace->gammaIsLinear()) { |
+ if (srcSpaceXYZ->gammaIsLinear()) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} else { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kTable_DstGamma, kGamut_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
} |
case kFull_ColorSpaceMatch: |
- switch (as_CSB(dstSpace)->gammaNamed()) { |
+ switch (dstSpaceXYZ->gammaNamed()) { |
case kSRGB_SkGammaNamed: |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kSRGB_DstGamma, kFull_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
case k2Dot2Curve_SkGammaNamed: |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, k2Dot2_DstGamma, kFull_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
case kLinear_SkGammaNamed: |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kLinear_SrcGamma, kLinear_DstGamma, kFull_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
default: |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kTable_DstGamma, kFull_ColorSpaceMatch> |
- (srcSpace, srcToDst, dstSpace)); |
+ (srcSpaceXYZ, srcToDst, dstSpaceXYZ)); |
} |
default: |
SkASSERT(false); |
@@ -483,138 +503,6 @@ std::unique_ptr<SkColorSpaceXform> SkColorSpaceXform::New(SkColorSpace* srcSpace |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
-static float byte_to_float(uint8_t byte) { |
- return ((float) byte) * (1.0f / 255.0f); |
-} |
- |
-// Clamp to the 0-1 range. |
-static float clamp_normalized_float(float v) { |
- if (v > 1.0f) { |
- return 1.0f; |
- } else if ((v < 0.0f) || (v != v)) { |
- return 0.0f; |
- } else { |
- return v; |
- } |
-} |
- |
-static void interp_3d_clut(float dst[3], float src[3], const SkColorLookUpTable* colorLUT) { |
- // Call the src components x, y, and z. |
- uint8_t maxX = colorLUT->fGridPoints[0] - 1; |
- uint8_t maxY = colorLUT->fGridPoints[1] - 1; |
- uint8_t maxZ = colorLUT->fGridPoints[2] - 1; |
- |
- // An approximate index into each of the three dimensions of the table. |
- float x = src[0] * maxX; |
- float y = src[1] * maxY; |
- float z = src[2] * maxZ; |
- |
- // This gives us the low index for our interpolation. |
- int ix = sk_float_floor2int(x); |
- int iy = sk_float_floor2int(y); |
- int iz = sk_float_floor2int(z); |
- |
- // Make sure the low index is not also the max index. |
- ix = (maxX == ix) ? ix - 1 : ix; |
- iy = (maxY == iy) ? iy - 1 : iy; |
- iz = (maxZ == iz) ? iz - 1 : iz; |
- |
- // Weighting factors for the interpolation. |
- float diffX = x - ix; |
- float diffY = y - iy; |
- float diffZ = z - iz; |
- |
- // Constants to help us navigate the 3D table. |
- // Ex: Assume x = a, y = b, z = c. |
- // table[a * n001 + b * n010 + c * n100] logically equals table[a][b][c]. |
- const int n000 = 0; |
- const int n001 = 3 * colorLUT->fGridPoints[1] * colorLUT->fGridPoints[2]; |
- const int n010 = 3 * colorLUT->fGridPoints[2]; |
- const int n011 = n001 + n010; |
- const int n100 = 3; |
- const int n101 = n100 + n001; |
- const int n110 = n100 + n010; |
- const int n111 = n110 + n001; |
- |
- // Base ptr into the table. |
- const float* ptr = &(colorLUT->table()[ix*n001 + iy*n010 + iz*n100]); |
- |
- // The code below performs a tetrahedral interpolation for each of the three |
- // dst components. Once the tetrahedron containing the interpolation point is |
- // identified, the interpolation is a weighted sum of grid values at the |
- // vertices of the tetrahedron. The claim is that tetrahedral interpolation |
- // provides a more accurate color conversion. |
- // blogs.mathworks.com/steve/2006/11/24/tetrahedral-interpolation-for-colorspace-conversion/ |
- // |
- // I have one test image, and visually I can't tell the difference between |
- // tetrahedral and trilinear interpolation. In terms of computation, the |
- // tetrahedral code requires more branches but less computation. The |
- // SampleICC library provides an option for the client to choose either |
- // tetrahedral or trilinear. |
- for (int i = 0; i < 3; i++) { |
- if (diffZ < diffY) { |
- if (diffZ < diffX) { |
- dst[i] = (ptr[n000] + diffZ * (ptr[n110] - ptr[n010]) + |
- diffY * (ptr[n010] - ptr[n000]) + |
- diffX * (ptr[n111] - ptr[n110])); |
- } else if (diffY < diffX) { |
- dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + |
- diffY * (ptr[n011] - ptr[n001]) + |
- diffX * (ptr[n001] - ptr[n000])); |
- } else { |
- dst[i] = (ptr[n000] + diffZ * (ptr[n111] - ptr[n011]) + |
- diffY * (ptr[n010] - ptr[n000]) + |
- diffX * (ptr[n011] - ptr[n010])); |
- } |
- } else { |
- if (diffZ < diffX) { |
- dst[i] = (ptr[n000] + diffZ * (ptr[n101] - ptr[n001]) + |
- diffY * (ptr[n111] - ptr[n101]) + |
- diffX * (ptr[n001] - ptr[n000])); |
- } else if (diffY < diffX) { |
- dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + |
- diffY * (ptr[n111] - ptr[n101]) + |
- diffX * (ptr[n101] - ptr[n100])); |
- } else { |
- dst[i] = (ptr[n000] + diffZ * (ptr[n100] - ptr[n000]) + |
- diffY * (ptr[n110] - ptr[n100]) + |
- diffX * (ptr[n111] - ptr[n110])); |
- } |
- } |
- |
- // Increment the table ptr in order to handle the next component. |
- // Note that this is the how table is designed: all of nXXX |
- // variables are multiples of 3 because there are 3 output |
- // components. |
- ptr++; |
- } |
-} |
- |
-static void handle_color_lut(uint32_t* dst, const void* vsrc, int len, |
- SkColorLookUpTable* colorLUT) { |
- const uint32_t* src = (const uint32_t*) vsrc; |
- while (len-- > 0) { |
- uint8_t r = (*src >> 0) & 0xFF, |
- g = (*src >> 8) & 0xFF, |
- b = (*src >> 16) & 0xFF; |
- |
- float in[3]; |
- float out[3]; |
- in[0] = byte_to_float(r); |
- in[1] = byte_to_float(g); |
- in[2] = byte_to_float(b); |
- interp_3d_clut(out, in, colorLUT); |
- |
- r = sk_float_round2int(255.0f * clamp_normalized_float(out[0])); |
- g = sk_float_round2int(255.0f * clamp_normalized_float(out[1])); |
- b = sk_float_round2int(255.0f * clamp_normalized_float(out[2])); |
- *dst = SkPackARGB_as_RGBA(0xFF, r, g, b); |
- |
- src++; |
- dst++; |
- } |
-} |
- |
static inline void load_matrix(const float matrix[16], |
Sk4f& rXgXbX, Sk4f& rYgYbY, Sk4f& rZgZbZ, Sk4f& rTgTbT) { |
rXgXbX = Sk4f::Load(matrix + 0); |
@@ -1226,14 +1114,14 @@ static void color_xform_RGBA(void* dst, const void* vsrc, int len, |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
-static inline int num_tables(SkColorSpace* space) { |
- switch (as_CSB(space)->gammaNamed()) { |
+static inline int num_tables(SkColorSpace_XYZ* space) { |
+ switch (space->gammaNamed()) { |
case kSRGB_SkGammaNamed: |
case k2Dot2Curve_SkGammaNamed: |
case kLinear_SkGammaNamed: |
return 0; |
default: { |
- const SkGammas* gammas = as_CSB(space)->gammas(); |
+ const SkGammas* gammas = space->gammas(); |
SkASSERT(gammas); |
bool gammasAreMatching = (gammas->type(0) == gammas->type(1)) && |
@@ -1250,8 +1138,8 @@ static inline int num_tables(SkColorSpace* space) { |
template <SrcGamma kSrc, DstGamma kDst, ColorSpaceMatch kCSM> |
SkColorSpaceXform_XYZ<kSrc, kDst, kCSM> |
-::SkColorSpaceXform_XYZ(SkColorSpace* srcSpace, const SkMatrix44& srcToDst, SkColorSpace* dstSpace) |
- : fColorLUT(sk_ref_sp((SkColorLookUpTable*) as_CSB(srcSpace)->colorLUT())) |
+::SkColorSpaceXform_XYZ(SkColorSpace_XYZ* srcSpace, const SkMatrix44& srcToDst, |
+ SkColorSpace_XYZ* dstSpace) |
{ |
srcToDst.asColMajorf(fSrcToDst); |
@@ -1263,7 +1151,7 @@ SkColorSpaceXform_XYZ<kSrc, kDst, kCSM> |
srcGammasAreMatching); |
const int numDstTables = num_tables(dstSpace); |
- as_CSB(dstSpace)->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables); |
+ dstSpace->toDstGammaTables(fDstGammaTables, &fDstStorage, numDstTables); |
} |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
@@ -1348,19 +1236,6 @@ bool SkColorSpaceXform_XYZ<kSrc, kDst, kCSM> |
} |
} |
-#if defined(GOOGLE3) |
- // Stack frame size is limited in GOOGLE3. |
- SkAutoSMalloc<256 * sizeof(uint32_t)> storage; |
-#else |
- SkAutoSMalloc<1024 * sizeof(uint32_t)> storage; |
-#endif |
- if (fColorLUT) { |
- size_t storageBytes = len * sizeof(uint32_t); |
- storage.reset(storageBytes); |
- handle_color_lut((uint32_t*) storage.get(), src, len, fColorLUT.get()); |
- src = (const uint32_t*) storage.get(); |
- } |
- |
switch (dstColorFormat) { |
case kRGBA_8888_ColorFormat: |
switch (kDst) { |
@@ -1431,7 +1306,7 @@ bool SkColorSpaceXform::apply(ColorFormat dstColorFormat, void* dst, ColorFormat |
/////////////////////////////////////////////////////////////////////////////////////////////////// |
-std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace* space) { |
+std::unique_ptr<SkColorSpaceXform> SlowIdentityXform(SkColorSpace_XYZ* space) { |
return std::unique_ptr<SkColorSpaceXform>(new SkColorSpaceXform_XYZ |
<kTable_SrcGamma, kTable_DstGamma, kNone_ColorSpaceMatch> |
(space, SkMatrix::I(), space)); |