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 |