| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. | 2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. |
| 3 * | 3 * |
| 4 * This library is free software; you can redistribute it and/or | 4 * This library is free software; you can redistribute it and/or |
| 5 * modify it under the terms of the GNU Library General Public | 5 * modify it under the terms of the GNU Library General Public |
| 6 * License as published by the Free Software Foundation; either | 6 * License as published by the Free Software Foundation; either |
| 7 * version 2 of the License, or (at your option) any later version. | 7 * version 2 of the License, or (at your option) any later version. |
| 8 * | 8 * |
| 9 * This library is distributed in the hope that it will be useful, | 9 * This library is distributed in the hope that it will be useful, |
| 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| (...skipping 17 matching lines...) Expand all Loading... |
| 28 #include "platform/image-decoders/gif/GIFImageDecoder.h" | 28 #include "platform/image-decoders/gif/GIFImageDecoder.h" |
| 29 #include "platform/image-decoders/ico/ICOImageDecoder.h" | 29 #include "platform/image-decoders/ico/ICOImageDecoder.h" |
| 30 #include "platform/image-decoders/jpeg/JPEGImageDecoder.h" | 30 #include "platform/image-decoders/jpeg/JPEGImageDecoder.h" |
| 31 #include "platform/image-decoders/png/PNGImageDecoder.h" | 31 #include "platform/image-decoders/png/PNGImageDecoder.h" |
| 32 #include "platform/image-decoders/webp/WEBPImageDecoder.h" | 32 #include "platform/image-decoders/webp/WEBPImageDecoder.h" |
| 33 #include "wtf/PtrUtil.h" | 33 #include "wtf/PtrUtil.h" |
| 34 #include <memory> | 34 #include <memory> |
| 35 | 35 |
| 36 namespace blink { | 36 namespace blink { |
| 37 | 37 |
| 38 #if USE(QCMSLIB) | |
| 39 struct QCMSProfileDeleter { | |
| 40 void operator()(qcms_profile* profile) { | |
| 41 if (profile) | |
| 42 qcms_profile_release(profile); | |
| 43 } | |
| 44 }; | |
| 45 | |
| 46 using QCMSProfileUniquePtr = std::unique_ptr<qcms_profile, QCMSProfileDeleter>; | |
| 47 #endif // USE(QCMSLIB) | |
| 48 | |
| 49 inline bool matchesJPEGSignature(const char* contents) { | 38 inline bool matchesJPEGSignature(const char* contents) { |
| 50 return !memcmp(contents, "\xFF\xD8\xFF", 3); | 39 return !memcmp(contents, "\xFF\xD8\xFF", 3); |
| 51 } | 40 } |
| 52 | 41 |
| 53 inline bool matchesPNGSignature(const char* contents) { | 42 inline bool matchesPNGSignature(const char* contents) { |
| 54 return !memcmp(contents, "\x89PNG\r\n\x1A\n", 8); | 43 return !memcmp(contents, "\x89PNG\r\n\x1A\n", 8); |
| 55 } | 44 } |
| 56 | 45 |
| 57 inline bool matchesGIFSignature(const char* contents) { | 46 inline bool matchesGIFSignature(const char* contents) { |
| 58 return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6); | 47 return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6); |
| (...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 336 return m_planes[i]; | 325 return m_planes[i]; |
| 337 } | 326 } |
| 338 | 327 |
| 339 size_t ImagePlanes::rowBytes(int i) const { | 328 size_t ImagePlanes::rowBytes(int i) const { |
| 340 ASSERT((i >= 0) && i < 3); | 329 ASSERT((i >= 0) && i < 3); |
| 341 return m_rowBytes[i]; | 330 return m_rowBytes[i]; |
| 342 } | 331 } |
| 343 | 332 |
| 344 namespace { | 333 namespace { |
| 345 | 334 |
| 346 #if USE(QCMSLIB) | 335 #if USE(SKCOLORXFORM) |
| 347 | 336 |
| 348 const unsigned kIccColorProfileHeaderLength = 128; | 337 // The output device color space is global and shared across multiple threads. |
| 338 SpinLock gTargetColorSpaceLock; |
| 339 SkColorSpace* gTargetColorSpace = nullptr; |
| 349 | 340 |
| 350 bool rgbColorProfile(const char* profileData, unsigned profileLength) { | 341 #endif // USE(SKCOLORXFORM) |
| 351 DCHECK_GE(profileLength, kIccColorProfileHeaderLength); | |
| 352 | |
| 353 return !memcmp(&profileData[16], "RGB ", 4); | |
| 354 } | |
| 355 | |
| 356 bool inputDeviceColorProfile(const char* profileData, unsigned profileLength) { | |
| 357 DCHECK_GE(profileLength, kIccColorProfileHeaderLength); | |
| 358 | |
| 359 return !memcmp(&profileData[12], "mntr", 4) || | |
| 360 !memcmp(&profileData[12], "scnr", 4); | |
| 361 } | |
| 362 | |
| 363 // The output device color profile is global and shared across multiple threads. | |
| 364 SpinLock gTargetColorProfileLock; | |
| 365 qcms_profile* gTargetColorProfile = nullptr; | |
| 366 | |
| 367 #endif // USE(QCMSLIB) | |
| 368 | 342 |
| 369 } // namespace | 343 } // namespace |
| 370 | 344 |
| 371 // static | 345 // static |
| 372 void ImageDecoder::setTargetColorProfile(const WebVector<char>& profile) { | 346 void ImageDecoder::setTargetColorProfile(const WebVector<char>& profile) { |
| 373 #if USE(QCMSLIB) | 347 #if USE(SKCOLORXFORM) |
| 374 if (profile.isEmpty()) | 348 if (profile.isEmpty()) |
| 375 return; | 349 return; |
| 376 | 350 |
| 377 // Take a lock around initializing and accessing the global device color | 351 // Take a lock around initializing and accessing the global device color |
| 378 // profile. | 352 // profile. |
| 379 SpinLock::Guard guard(gTargetColorProfileLock); | 353 SpinLock::Guard guard(gTargetColorSpaceLock); |
| 380 | 354 |
| 381 // Layout tests expect that only the first call will take effect. | 355 // Layout tests expect that only the first call will take effect. |
| 382 if (gTargetColorProfile) | 356 if (gTargetColorSpace) |
| 383 return; | 357 return; |
| 384 | 358 |
| 385 { | 359 gTargetColorSpace = |
| 386 sk_sp<SkColorSpace> colorSpace = | 360 SkColorSpace::NewICC(profile.data(), profile.size()).release(); |
| 387 SkColorSpace::NewICC(profile.data(), profile.size()); | |
| 388 BitmapImageMetrics::countGamma(colorSpace.get()); | |
| 389 } | |
| 390 | 361 |
| 391 // FIXME: Add optional ICCv4 support and support for multiple monitors. | 362 // UMA statistics. |
| 392 gTargetColorProfile = | 363 BitmapImageMetrics::countGamma(gTargetColorSpace); |
| 393 qcms_profile_from_memory(profile.data(), profile.size()); | 364 #endif // USE(SKCOLORXFORM) |
| 394 if (!gTargetColorProfile) | |
| 395 return; | |
| 396 | |
| 397 if (qcms_profile_is_bogus(gTargetColorProfile)) { | |
| 398 qcms_profile_release(gTargetColorProfile); | |
| 399 gTargetColorProfile = nullptr; | |
| 400 return; | |
| 401 } | |
| 402 | |
| 403 qcms_profile_precache_output_transform(gTargetColorProfile); | |
| 404 #endif // USE(QCMSLIB) | |
| 405 } | 365 } |
| 406 | 366 |
| 407 void ImageDecoder::setColorProfileAndComputeTransform(const char* iccData, | 367 void ImageDecoder::setColorSpaceAndComputeTransform(const char* iccData, |
| 408 unsigned iccLength, | 368 unsigned iccLength, |
| 409 bool hasAlpha, | 369 bool useSRGB) { |
| 410 bool useSRGB) { | |
| 411 // Sub-classes should not call this if they were instructed to ignore embedded | 370 // Sub-classes should not call this if they were instructed to ignore embedded |
| 412 // color profiles. | 371 // color profiles. |
| 413 DCHECK(!m_ignoreGammaAndColorProfile); | 372 DCHECK(!m_ignoreGammaAndColorProfile); |
| 414 | 373 |
| 415 m_colorProfile.assign(iccData, iccLength); | 374 m_colorProfile.assign(iccData, iccLength); |
| 416 m_hasColorProfile = true; | 375 m_hasColorProfile = true; |
| 417 | 376 |
| 418 // With color correct rendering, we use Skia instead of QCMS to color correct | 377 // With color correct rendering, we do not transform to the output color space |
| 419 // images. | 378 // at decode time. Instead, we tag the raw image pixels and pass the tagged |
| 379 // SkImage to Skia. |
| 420 if (RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) | 380 if (RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) |
| 421 return; | 381 return; |
| 422 | 382 |
| 423 #if USE(QCMSLIB) | 383 #if USE(SKCOLORXFORM) |
| 424 m_sourceToOutputDeviceColorTransform.reset(); | 384 m_sourceToOutputDeviceColorTransform = nullptr; |
| 425 | 385 |
| 426 // Create the input profile | 386 // Create the input profile. |
| 427 QCMSProfileUniquePtr inputProfile; | 387 sk_sp<SkColorSpace> srcSpace = nullptr; |
| 428 if (useSRGB) { | 388 if (useSRGB) { |
| 429 inputProfile.reset(qcms_profile_sRGB()); | 389 srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); |
| 430 } else { | 390 } else { |
| 431 // Only accept RGB color profiles from input class devices. | 391 srcSpace = SkColorSpace::NewICC(iccData, iccLength); |
| 432 if (iccLength < kIccColorProfileHeaderLength) | |
| 433 return; | |
| 434 if (!rgbColorProfile(iccData, iccLength)) | |
| 435 return; | |
| 436 if (!inputDeviceColorProfile(iccData, iccLength)) | |
| 437 return; | |
| 438 inputProfile.reset(qcms_profile_from_memory(iccData, iccLength)); | |
| 439 } | 392 } |
| 440 if (!inputProfile) | 393 |
| 394 if (!srcSpace) |
| 441 return; | 395 return; |
| 442 | 396 |
| 443 // We currently only support color profiles for RGB profiled images. | |
| 444 ASSERT(rgbData == qcms_profile_get_color_space(inputProfile.get())); | |
| 445 | |
| 446 // Take a lock around initializing and accessing the global device color | 397 // Take a lock around initializing and accessing the global device color |
| 447 // profile. | 398 // profile. |
| 448 SpinLock::Guard guard(gTargetColorProfileLock); | 399 SpinLock::Guard guard(gTargetColorSpaceLock); |
| 449 | 400 |
| 450 // Initialize the output device profile to sRGB if it has not yet been | 401 // Initialize the output device profile to sRGB if it has not yet been |
| 451 // initialized. | 402 // initialized. |
| 452 if (!gTargetColorProfile) { | 403 if (!gTargetColorSpace) { |
| 453 gTargetColorProfile = qcms_profile_sRGB(); | 404 gTargetColorSpace = |
| 454 qcms_profile_precache_output_transform(gTargetColorProfile); | 405 SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).release(); |
| 455 } | 406 } |
| 456 | 407 |
| 457 if (qcms_profile_match(inputProfile.get(), gTargetColorProfile)) | 408 if (SkColorSpace::Equals(srcSpace.get(), gTargetColorSpace)) { |
| 458 return; | 409 return; |
| 410 } |
| 459 | 411 |
| 460 qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_8; | 412 m_sourceToOutputDeviceColorTransform = |
| 461 | 413 SkColorSpaceXform::New(srcSpace.get(), gTargetColorSpace); |
| 462 // FIXME: Don't force perceptual intent if the image profile contains an | 414 #endif // USE(SKCOLORXFORM) |
| 463 // intent. | |
| 464 m_sourceToOutputDeviceColorTransform.reset( | |
| 465 qcms_transform_create(inputProfile.get(), dataFormat, gTargetColorProfile, | |
| 466 QCMS_DATA_RGBA_8, QCMS_INTENT_PERCEPTUAL)); | |
| 467 #endif // USE(QCMSLIB) | |
| 468 } | 415 } |
| 469 | 416 |
| 470 } // namespace blink | 417 } // namespace blink |
| OLD | NEW |