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 |
38 inline bool matchesJPEGSignature(const char* contents) { | 49 inline bool matchesJPEGSignature(const char* contents) { |
39 return !memcmp(contents, "\xFF\xD8\xFF", 3); | 50 return !memcmp(contents, "\xFF\xD8\xFF", 3); |
40 } | 51 } |
41 | 52 |
42 inline bool matchesPNGSignature(const char* contents) { | 53 inline bool matchesPNGSignature(const char* contents) { |
43 return !memcmp(contents, "\x89PNG\r\n\x1A\n", 8); | 54 return !memcmp(contents, "\x89PNG\r\n\x1A\n", 8); |
44 } | 55 } |
45 | 56 |
46 inline bool matchesGIFSignature(const char* contents) { | 57 inline bool matchesGIFSignature(const char* contents) { |
47 return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6); | 58 return !memcmp(contents, "GIF87a", 6) || !memcmp(contents, "GIF89a", 6); |
(...skipping 277 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
325 return m_planes[i]; | 336 return m_planes[i]; |
326 } | 337 } |
327 | 338 |
328 size_t ImagePlanes::rowBytes(int i) const { | 339 size_t ImagePlanes::rowBytes(int i) const { |
329 ASSERT((i >= 0) && i < 3); | 340 ASSERT((i >= 0) && i < 3); |
330 return m_rowBytes[i]; | 341 return m_rowBytes[i]; |
331 } | 342 } |
332 | 343 |
333 namespace { | 344 namespace { |
334 | 345 |
335 #if USE(SKCOLORXFORM) | 346 #if USE(QCMSLIB) |
336 | 347 |
337 // The output device color space is global and shared across multiple threads. | 348 const unsigned kIccColorProfileHeaderLength = 128; |
338 SpinLock gTargetColorSpaceLock; | |
339 SkColorSpace* gTargetColorSpace = nullptr; | |
340 | 349 |
341 #endif // USE(SKCOLORXFORM) | 350 bool rgbColorProfile(const char* profileData, unsigned profileLength) { |
| 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) |
342 | 368 |
343 } // namespace | 369 } // namespace |
344 | 370 |
345 // static | 371 // static |
346 void ImageDecoder::setTargetColorProfile(const WebVector<char>& profile) { | 372 void ImageDecoder::setTargetColorProfile(const WebVector<char>& profile) { |
347 #if USE(SKCOLORXFORM) | 373 #if USE(QCMSLIB) |
348 if (profile.isEmpty()) | 374 if (profile.isEmpty()) |
349 return; | 375 return; |
350 | 376 |
351 // Take a lock around initializing and accessing the global device color | 377 // Take a lock around initializing and accessing the global device color |
352 // profile. | 378 // profile. |
353 SpinLock::Guard guard(gTargetColorSpaceLock); | 379 SpinLock::Guard guard(gTargetColorProfileLock); |
354 | 380 |
355 // Layout tests expect that only the first call will take effect. | 381 // Layout tests expect that only the first call will take effect. |
356 if (gTargetColorSpace) | 382 if (gTargetColorProfile) |
357 return; | 383 return; |
358 | 384 |
359 gTargetColorSpace = | 385 { |
360 SkColorSpace::NewICC(profile.data(), profile.size()).release(); | 386 sk_sp<SkColorSpace> colorSpace = |
| 387 SkColorSpace::NewICC(profile.data(), profile.size()); |
| 388 BitmapImageMetrics::countGamma(colorSpace.get()); |
| 389 } |
361 | 390 |
362 // UMA statistics. | 391 // FIXME: Add optional ICCv4 support and support for multiple monitors. |
363 BitmapImageMetrics::countGamma(gTargetColorSpace); | 392 gTargetColorProfile = |
364 #endif // USE(SKCOLORXFORM) | 393 qcms_profile_from_memory(profile.data(), profile.size()); |
| 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) |
365 } | 405 } |
366 | 406 |
367 void ImageDecoder::setColorSpaceAndComputeTransform(const char* iccData, | 407 void ImageDecoder::setColorProfileAndComputeTransform(const char* iccData, |
368 unsigned iccLength, | 408 unsigned iccLength, |
369 bool useSRGB) { | 409 bool hasAlpha, |
| 410 bool useSRGB) { |
370 // Sub-classes should not call this if they were instructed to ignore embedded | 411 // Sub-classes should not call this if they were instructed to ignore embedded |
371 // color profiles. | 412 // color profiles. |
372 DCHECK(!m_ignoreGammaAndColorProfile); | 413 DCHECK(!m_ignoreGammaAndColorProfile); |
373 | 414 |
374 m_colorProfile.assign(iccData, iccLength); | 415 m_colorProfile.assign(iccData, iccLength); |
375 m_hasColorProfile = true; | 416 m_hasColorProfile = true; |
376 | 417 |
377 // With color correct rendering, we do not transform to the output color space | 418 // With color correct rendering, we use Skia instead of QCMS to color correct |
378 // at decode time. Instead, we tag the raw image pixels and pass the tagged | 419 // images. |
379 // SkImage to Skia. | |
380 if (RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) | 420 if (RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) |
381 return; | 421 return; |
382 | 422 |
383 #if USE(SKCOLORXFORM) | 423 #if USE(QCMSLIB) |
384 m_sourceToOutputDeviceColorTransform = nullptr; | 424 m_sourceToOutputDeviceColorTransform.reset(); |
385 | 425 |
386 // Create the input profile. | 426 // Create the input profile |
387 sk_sp<SkColorSpace> srcSpace = nullptr; | 427 QCMSProfileUniquePtr inputProfile; |
388 if (useSRGB) { | 428 if (useSRGB) { |
389 srcSpace = SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named); | 429 inputProfile.reset(qcms_profile_sRGB()); |
390 } else { | 430 } else { |
391 srcSpace = SkColorSpace::NewICC(iccData, iccLength); | 431 // Only accept RGB color profiles from input class devices. |
| 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)); |
392 } | 439 } |
| 440 if (!inputProfile) |
| 441 return; |
393 | 442 |
394 if (!srcSpace) | 443 // We currently only support color profiles for RGB profiled images. |
395 return; | 444 ASSERT(rgbData == qcms_profile_get_color_space(inputProfile.get())); |
396 | 445 |
397 // Take a lock around initializing and accessing the global device color | 446 // Take a lock around initializing and accessing the global device color |
398 // profile. | 447 // profile. |
399 SpinLock::Guard guard(gTargetColorSpaceLock); | 448 SpinLock::Guard guard(gTargetColorProfileLock); |
400 | 449 |
401 // Initialize the output device profile to sRGB if it has not yet been | 450 // Initialize the output device profile to sRGB if it has not yet been |
402 // initialized. | 451 // initialized. |
403 if (!gTargetColorSpace) { | 452 if (!gTargetColorProfile) { |
404 gTargetColorSpace = | 453 gTargetColorProfile = qcms_profile_sRGB(); |
405 SkColorSpace::NewNamed(SkColorSpace::kSRGB_Named).release(); | 454 qcms_profile_precache_output_transform(gTargetColorProfile); |
406 } | 455 } |
407 | 456 |
408 if (SkColorSpace::Equals(srcSpace.get(), gTargetColorSpace)) { | 457 if (qcms_profile_match(inputProfile.get(), gTargetColorProfile)) |
409 return; | 458 return; |
410 } | |
411 | 459 |
412 m_sourceToOutputDeviceColorTransform = | 460 qcms_data_type dataFormat = hasAlpha ? QCMS_DATA_RGBA_8 : QCMS_DATA_RGB_8; |
413 SkColorSpaceXform::New(srcSpace.get(), gTargetColorSpace); | 461 |
414 #endif // USE(SKCOLORXFORM) | 462 // FIXME: Don't force perceptual intent if the image profile contains an |
| 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) |
415 } | 468 } |
416 | 469 |
417 } // namespace blink | 470 } // namespace blink |
OLD | NEW |