aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authorGravatar msarett <msarett@google.com>2016-08-22 12:29:31 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-22 12:29:32 -0700
commitd9015a43cf6c6e7c372c804ee3e1021b153d505f (patch)
treee52b1e47fd340695a2fef97bb63a5af88522c907 /src
parenta90dcf791b70ee5147faebd1d102f51c455b2889 (diff)
Fix Equals and serialization for rare pngs
PNGs may contain a gAMA chunk that specifies gamma values as floats. If so, we will use these floats to create an SkColorSpace. This CL fixes Equals(), serialize(), and Deserialize() to correctly handle SkColorSpaces with strange gammas, where we are unable to fall back on the profile data. BUG=skia: GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2221983002 Review-Url: https://codereview.chromium.org/2221983002
Diffstat (limited to 'src')
-rw-r--r--src/core/SkColorSpace.cpp97
-rw-r--r--src/core/SkColorSpace_Base.h2
2 files changed, 75 insertions, 24 deletions
diff --git a/src/core/SkColorSpace.cpp b/src/core/SkColorSpace.cpp
index cb5c8695ee..3a5d9c196a 100644
--- a/src/core/SkColorSpace.cpp
+++ b/src/core/SkColorSpace.cpp
@@ -68,7 +68,7 @@ static bool xyz_almost_equal(const SkMatrix44& toXYZD50, const float* standard)
color_space_almost_equal(toXYZD50.getFloat(3, 3), 1.0f);
}
-sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(float values[3], const SkMatrix44& toXYZD50) {
+sk_sp<SkColorSpace> SkColorSpace_Base::NewRGB(const float values[3], const SkMatrix44& toXYZD50) {
if (0.0f > values[0] || 0.0f > values[1] || 0.0f > values[2]) {
return nullptr;
}
@@ -164,17 +164,25 @@ enum Version {
struct ColorSpaceHeader {
/**
* If kMatrix_Flag is set, we will write 12 floats after the header.
- * Should not be set at the same time as the kICC_Flag.
+ * Should not be set at the same time as the kICC_Flag or kFloatGamma_Flag.
*/
- static constexpr uint8_t kMatrix_Flag = 1 << 0;
+ static constexpr uint8_t kMatrix_Flag = 1 << 0;
/**
* If kICC_Flag is set, we will write an ICC profile after the header.
* The ICC profile will be written as a uint32 size, followed immediately
* by the data (padded to 4 bytes).
- * Should not be set at the same time as the kMatrix_Flag.
+ * Should not be set at the same time as the kMatrix_Flag or kFloatGamma_Flag.
*/
- static constexpr uint8_t kICC_Flag = 1 << 1;
+ static constexpr uint8_t kICC_Flag = 1 << 1;
+
+ /**
+ * If kFloatGamma_Flag is set, we will write 15 floats after the header.
+ * The first three are the gamma values, and the next twelve are the
+ * matrix.
+ * Should not be set at the same time as the kICC_Flag or kMatrix_Flag.
+ */
+ static constexpr uint8_t kFloatGamma_Flag = 1 << 2;
static ColorSpaceHeader Pack(Version version, SkColorSpace::Named named,
SkColorSpace::GammaNamed gammaNamed, uint8_t flags) {
@@ -189,7 +197,7 @@ struct ColorSpaceHeader {
SkASSERT(gammaNamed <= SkColorSpace::kNonStandard_GammaNamed);
header.fGammaNamed = (uint8_t) gammaNamed;
- SkASSERT(flags <= kICC_Flag);
+ SkASSERT(flags <= kFloatGamma_Flag);
header.fFlags = flags;
return header;
}
@@ -233,8 +241,26 @@ size_t SkColorSpace::writeToMemory(void* memory) const {
return sizeof(ColorSpaceHeader) + 12 * sizeof(float);
}
default:
- SkASSERT(false);
- return 0;
+ // Otherwise, write the gamma values and the matrix.
+ if (memory) {
+ *((ColorSpaceHeader*) memory) =
+ ColorSpaceHeader::Pack(k0_Version, fNamed, fGammaNamed,
+ ColorSpaceHeader::kFloatGamma_Flag);
+ memory = SkTAddOffset<void>(memory, sizeof(ColorSpaceHeader));
+
+ const SkGammas* gammas = as_CSB(this)->gammas();
+ SkASSERT(gammas);
+ SkASSERT(SkGammas::Type::kValue_Type == gammas->fRedType &&
+ SkGammas::Type::kValue_Type == gammas->fGreenType &&
+ SkGammas::Type::kValue_Type == gammas->fBlueType);
+ *(((float*) memory) + 0) = gammas->fRedData.fValue;
+ *(((float*) memory) + 1) = gammas->fGreenData.fValue;
+ *(((float*) memory) + 2) = gammas->fBlueData.fValue;
+ memory = SkTAddOffset<void>(memory, 3 * sizeof(float));
+
+ fToXYZD50.as4x3ColMajorf((float*) memory);
+ }
+ return sizeof(ColorSpaceHeader) + 15 * sizeof(float);
}
}
@@ -302,18 +328,39 @@ sk_sp<SkColorSpace> SkColorSpace::Deserialize(const void* data, size_t length) {
break;
}
- if (ColorSpaceHeader::kICC_Flag != header.fFlags || length < sizeof(uint32_t)) {
- return nullptr;
- }
+ switch (header.fFlags) {
+ case ColorSpaceHeader::kICC_Flag: {
+ if (length < sizeof(uint32_t)) {
+ return nullptr;
+ }
- uint32_t profileSize = *((uint32_t*) data);
- data = SkTAddOffset<const void>(data, sizeof(uint32_t));
- length -= sizeof(uint32_t);
- if (length < profileSize) {
- return nullptr;
- }
+ uint32_t profileSize = *((uint32_t*) data);
+ data = SkTAddOffset<const void>(data, sizeof(uint32_t));
+ length -= sizeof(uint32_t);
+ if (length < profileSize) {
+ return nullptr;
+ }
+
+ return NewICC(data, profileSize);
+ }
+ case ColorSpaceHeader::kFloatGamma_Flag: {
+ if (length < 15 * sizeof(float)) {
+ return nullptr;
+ }
- return NewICC(data, profileSize);
+ float gammas[3];
+ gammas[0] = *(((const float*) data) + 0);
+ gammas[1] = *(((const float*) data) + 1);
+ gammas[2] = *(((const float*) data) + 2);
+ data = SkTAddOffset<const void>(data, 3 * sizeof(float));
+
+ SkMatrix44 toXYZ(SkMatrix44::kUninitialized_Constructor);
+ toXYZ.set4x3ColMajorf((const float*) data);
+ return SkColorSpace_Base::NewRGB(gammas, toXYZ);
+ }
+ default:
+ return nullptr;
+ }
}
bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) {
@@ -355,11 +402,15 @@ bool SkColorSpace::Equals(const SkColorSpace* src, const SkColorSpace* dst) {
case kLinear_GammaNamed:
return (src->fGammaNamed == dst->fGammaNamed) && (src->fToXYZD50 == dst->fToXYZD50);
default:
- // If |src| does not have a named gamma, fProfileData should be non-null.
- // FIXME (msarett): We may hit this case on pngs that specify float gammas.
- // Gamma can be non-standard, but we don't have a profile
- // to fall back on. What do we do?
- return false;
+ if (src->fGammaNamed != dst->fGammaNamed) {
+ return false;
+ }
+
+ // It is unlikely that we will reach this case.
+ sk_sp<SkData> srcData = src->serialize();
+ sk_sp<SkData> dstData = dst->serialize();
+ return srcData->size() == dstData->size() &&
+ 0 == memcmp(srcData->data(), dstData->data(), srcData->size());
}
}
diff --git a/src/core/SkColorSpace_Base.h b/src/core/SkColorSpace_Base.h
index 3a2518db9c..38e0ba0026 100644
--- a/src/core/SkColorSpace_Base.h
+++ b/src/core/SkColorSpace_Base.h
@@ -174,7 +174,7 @@ struct SkColorLookUpTable : public SkRefCnt {
class SkColorSpace_Base : public SkColorSpace {
public:
- static sk_sp<SkColorSpace> NewRGB(float gammas[3], const SkMatrix44& toXYZD50);
+ static sk_sp<SkColorSpace> NewRGB(const float gammas[3], const SkMatrix44& toXYZD50);
const SkGammas* gammas() const { return fGammas.get(); }