Index: third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp |
diff --git a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp |
index ab5969d2bf801d5a5a4e44fefbf99adbc0704298..9f3aeab110589bd7936797be2924085778974665 100644 |
--- a/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp |
+++ b/third_party/WebKit/Source/platform/image-decoders/ImageDecoder.cpp |
@@ -34,6 +34,17 @@ |
#include <memory> |
namespace blink { |
+ |
+#if USE(QCMSLIB) |
+struct QCMSProfileDeleter { |
+ void operator()(qcms_profile* profile) { |
+ if (profile) |
+ qcms_profile_release(profile); |
+ } |
+}; |
+ |
+using QCMSProfileUniquePtr = std::unique_ptr<qcms_profile, QCMSProfileDeleter>; |
+#endif // USE(QCMSLIB) |
inline bool matchesJPEGSignature(const char* contents) { |
return !memcmp(contents, "\xFF\xD8\xFF", 3); |
@@ -332,41 +343,71 @@ |
namespace { |
-#if USE(SKCOLORXFORM) |
- |
-// The output device color space is global and shared across multiple threads. |
-SpinLock gTargetColorSpaceLock; |
-SkColorSpace* gTargetColorSpace = nullptr; |
- |
-#endif // USE(SKCOLORXFORM) |
+#if USE(QCMSLIB) |
+ |
+const unsigned kIccColorProfileHeaderLength = 128; |
+ |
+bool rgbColorProfile(const char* profileData, unsigned profileLength) { |
+ DCHECK_GE(profileLength, kIccColorProfileHeaderLength); |
+ |
+ return !memcmp(&profileData[16], "RGB ", 4); |
+} |
+ |
+bool inputDeviceColorProfile(const char* profileData, unsigned profileLength) { |
+ DCHECK_GE(profileLength, kIccColorProfileHeaderLength); |
+ |
+ return !memcmp(&profileData[12], "mntr", 4) || |
+ !memcmp(&profileData[12], "scnr", 4); |
+} |
+ |
+// The output device color profile is global and shared across multiple threads. |
+SpinLock gTargetColorProfileLock; |
+qcms_profile* gTargetColorProfile = nullptr; |
+ |
+#endif // USE(QCMSLIB) |
} // namespace |
// static |
void ImageDecoder::setTargetColorProfile(const WebVector<char>& profile) { |
-#if USE(SKCOLORXFORM) |
+#if USE(QCMSLIB) |
if (profile.isEmpty()) |
return; |
// Take a lock around initializing and accessing the global device color |
// profile. |
- SpinLock::Guard guard(gTargetColorSpaceLock); |
+ SpinLock::Guard guard(gTargetColorProfileLock); |
// Layout tests expect that only the first call will take effect. |
- if (gTargetColorSpace) |
- return; |
- |
- gTargetColorSpace = |
- SkColorSpace::NewICC(profile.data(), profile.size()).release(); |
- |
- // UMA statistics. |
- BitmapImageMetrics::countGamma(gTargetColorSpace); |
-#endif // USE(SKCOLORXFORM) |
-} |
- |
-void ImageDecoder::setColorSpaceAndComputeTransform(const char* iccData, |
- unsigned iccLength, |
- bool useSRGB) { |
+ if (gTargetColorProfile) |
+ return; |
+ |
+ { |
+ sk_sp<SkColorSpace> colorSpace = |
+ SkColorSpace::NewICC(profile.data(), profile.size()); |
+ BitmapImageMetrics::countGamma(colorSpace.get()); |
+ } |
+ |
+ // FIXME: Add optional ICCv4 support and support for multiple monitors. |
+ gTargetColorProfile = |
+ qcms_profile_from_memory(profile.data(), profile.size()); |
+ if (!gTargetColorProfile) |
+ return; |
+ |
+ if (qcms_profile_is_bogus(gTargetColorProfile)) { |
+ qcms_profile_release(gTargetColorProfile); |
+ gTargetColorProfile = nullptr; |
+ return; |
+ } |
+ |
+ qcms_profile_precache_output_transform(gTargetColorProfile); |
+#endif // USE(QCMSLIB) |
+} |
+ |
+void ImageDecoder::setColorProfileAndComputeTransform(const char* iccData, |
+ unsigned iccLength, |
+ bool hasAlpha, |
+ bool useSRGB) { |
// Sub-classes should not call this if they were instructed to ignore embedded |
// color profiles. |
DCHECK(!m_ignoreGammaAndColorProfile); |
@@ -374,44 +415,56 @@ |
m_colorProfile.assign(iccData, iccLength); |
m_hasColorProfile = true; |
- // With color correct rendering, we do not transform to the output color space |
- // at decode time. Instead, we tag the raw image pixels and pass the tagged |
- // SkImage to Skia. |
+ // With color correct rendering, we use Skia instead of QCMS to color correct |
+ // images. |
if (RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) |
return; |
-#if USE(SKCOLORXFORM) |
- m_sourceToOutputDeviceColorTransform = nullptr; |
- |
- // Create the input profile. |
- sk_sp<SkColorSpace> srcSpace = nullptr; |
+#if USE(QCMSLIB) |
+ m_sourceToOutputDeviceColorTransform.reset(); |
+ |
+ // Create the input profile |
+ QCMSProfileUniquePtr inputProfile; |
if (useSRGB) { |
- srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); |
+ inputProfile.reset(qcms_profile_sRGB()); |
} else { |
- srcSpace = SkColorSpace::NewICC(iccData, iccLength); |
- } |
- |
- if (!srcSpace) |
- return; |
+ // Only accept RGB color profiles from input class devices. |
+ if (iccLength < kIccColorProfileHeaderLength) |
+ return; |
+ if (!rgbColorProfile(iccData, iccLength)) |
+ return; |
+ if (!inputDeviceColorProfile(iccData, iccLength)) |
+ return; |
+ inputProfile.reset(qcms_profile_from_memory(iccData, iccLength)); |
+ } |
+ if (!inputProfile) |
+ return; |
+ |
+ // We currently only support color profiles for RGB profiled images. |
+ ASSERT(rgbData == qcms_profile_get_color_space(inputProfile.get())); |
// Take a lock around initializing and accessing the global device color |
// profile. |
- SpinLock::Guard guard(gTargetColorSpaceLock); |
+ SpinLock::Guard guard(gTargetColorProfileLock); |
// Initialize the output device profile to sRGB if it has not yet been |
// initialized. |
- if (!gTargetColorSpace) { |
- gTargetColorSpace = |
- SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).release(); |
- } |
- |
- if (SkColorSpace::Equals(srcSpace.get(), gTargetColorSpace)) { |
- return; |
- } |
- |
- m_sourceToOutputDeviceColorTransform = |
- SkColorSpaceXform::New(srcSpace.get(), gTargetColorSpace); |
-#endif // USE(SKCOLORXFORM) |
+ if (!gTargetColorProfile) { |
+ gTargetColorProfile = qcms_profile_sRGB(); |
+ qcms_profile_precache_output_transform(gTargetColorProfile); |
+ } |
+ |
+ if (qcms_profile_match(inputProfile.get(), gTargetColorProfile)) |
+ return; |
+ |
+ qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_8; |
+ |
+ // FIXME: Don't force perceptual intent if the image profile contains an |
+ // intent. |
+ m_sourceToOutputDeviceColorTransform.reset( |
+ qcms_transform_create(inputProfile.get(), dataFormat, gTargetColorProfile, |
+ QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL)); |
+#endif // USE(QCMSLIB) |
} |
} // namespace blink |