Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(249)

Side by Side Diff: third_party/WebKit/Source/modules/canvas2d/CanvasRenderingContext2DTest.cpp

Issue 2797213002: Fix BaseRenderingContext2D create/put/get-ImageData() for color managed canvas (Closed)
Patch Set: Corrections Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "modules/canvas2d/CanvasRenderingContext2D.h" 5 #include "modules/canvas2d/CanvasRenderingContext2D.h"
6 6
7 #include <memory> 7 #include <memory>
8 #include "bindings/core/v8/V8Binding.h" 8 #include "bindings/core/v8/V8Binding.h"
9 #include "bindings/core/v8/V8BindingForTesting.h" 9 #include "bindings/core/v8/V8BindingForTesting.h"
10 #include "core/dom/Document.h" 10 #include "core/dom/Document.h"
(...skipping 14 matching lines...) Expand all
25 #include "platform/graphics/UnacceleratedImageBufferSurface.h" 25 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
26 #include "platform/graphics/test/FakeGLES2Interface.h" 26 #include "platform/graphics/test/FakeGLES2Interface.h"
27 #include "platform/graphics/test/FakeWebGraphicsContext3DProvider.h" 27 #include "platform/graphics/test/FakeWebGraphicsContext3DProvider.h"
28 #include "platform/loader/fetch/MemoryCache.h" 28 #include "platform/loader/fetch/MemoryCache.h"
29 #include "platform/wtf/PtrUtil.h" 29 #include "platform/wtf/PtrUtil.h"
30 #include "testing/gmock/include/gmock/gmock.h" 30 #include "testing/gmock/include/gmock/gmock.h"
31 #include "testing/gtest/include/gtest/gtest.h" 31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "third_party/skia/include/core/SkColorSpaceXform.h" 32 #include "third_party/skia/include/core/SkColorSpaceXform.h"
33 #include "third_party/skia/include/core/SkImage.h" 33 #include "third_party/skia/include/core/SkImage.h"
34 #include "third_party/skia/include/core/SkSurface.h" 34 #include "third_party/skia/include/core/SkSurface.h"
35 #include "third_party/skia/include/core/SkSwizzle.h"
35 36
36 using ::testing::Mock; 37 using ::testing::Mock;
37 38
38 namespace blink { 39 namespace blink {
39 40
40 namespace { 41 namespace {
41 42
42 gfx::ColorSpace AdobeRGBColorSpace() { 43 gfx::ColorSpace AdobeRGBColorSpace() {
43 return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::ADOBE_RGB, 44 return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::ADOBE_RGB,
44 gfx::ColorSpace::TransferID::GAMMA22); 45 gfx::ColorSpace::TransferID::GAMMA22);
(...skipping 1333 matching lines...) Expand 10 before | Expand all | Expand 10 after
1378 } 1379 }
1379 1380
1380 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( 1381 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(
1381 experimental_canvas_features_runtime_flag); 1382 experimental_canvas_features_runtime_flag);
1382 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( 1383 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(
1383 color_correct_rendering_runtime_flag); 1384 color_correct_rendering_runtime_flag);
1384 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled( 1385 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled(
1385 color_correct_rendering_default_mode_runtime_flag); 1386 color_correct_rendering_default_mode_runtime_flag);
1386 } 1387 }
1387 1388
1389 bool ConvertPixelsToColorSpaceAndPixelFormatForTest(
1390 DOMArrayBufferView* data_array,
1391 CanvasColorSpace src_color_space,
1392 CanvasColorSpace dst_color_space,
1393 CanvasPixelFormat dst_pixel_format,
1394 std::unique_ptr<uint8_t[]>& converted_pixels) {
1395 // Setting SkColorSpaceXform::apply parameters
1396 SkColorSpaceXform::ColorFormat src_color_format =
1397 SkColorSpaceXform::kRGBA_8888_ColorFormat;
1398
1399 unsigned data_length = data_array->byteLength() / data_array->TypeSize();
1400 unsigned num_pixels = data_length / 4;
1401 DOMUint8ClampedArray* u8_array = nullptr;
1402 DOMUint16Array* u16_array = nullptr;
1403 DOMFloat32Array* f32_array = nullptr;
1404 void* src_data = nullptr;
1405
1406 switch (data_array->GetType()) {
1407 case ArrayBufferView::ViewType::kTypeUint8Clamped:
1408 u8_array = const_cast<DOMUint8ClampedArray*>(
1409 static_cast<const DOMUint8ClampedArray*>(data_array));
1410 src_data = static_cast<void*>(u8_array->Data());
1411 break;
1412
1413 case ArrayBufferView::ViewType::kTypeUint16:
1414 u16_array = const_cast<DOMUint16Array*>(
1415 static_cast<const DOMUint16Array*>(data_array));
1416 src_color_format =
1417 SkColorSpaceXform::ColorFormat::kRGBA_U16_BE_ColorFormat;
1418 src_data = static_cast<void*>(u16_array->Data());
1419 break;
1420
1421 case ArrayBufferView::ViewType::kTypeFloat32:
1422 f32_array = const_cast<DOMFloat32Array*>(
1423 static_cast<const DOMFloat32Array*>(data_array));
1424 src_color_format = SkColorSpaceXform::kRGBA_F32_ColorFormat;
1425 src_data = static_cast<void*>(f32_array->Data());
1426 break;
1427 default:
1428 NOTREACHED();
1429 return false;
1430 }
1431
1432 SkColorSpaceXform::ColorFormat dst_color_format =
1433 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
1434 if (dst_pixel_format == kF16CanvasPixelFormat)
1435 dst_color_format = SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat;
1436
1437 sk_sp<SkColorSpace> src_sk_color_space = nullptr;
1438 if (u8_array) {
1439 src_sk_color_space = ImageData::GetSkColorSpaceForTest(
1440 src_color_space, kRGBA8CanvasPixelFormat);
1441 } else {
1442 src_sk_color_space = ImageData::GetSkColorSpaceForTest(
1443 src_color_space, kF16CanvasPixelFormat);
1444 }
1445
1446 sk_sp<SkColorSpace> dst_sk_color_space =
1447 ImageData::GetSkColorSpaceForTest(dst_color_space, dst_pixel_format);
1448
1449 // When the input dataArray is in Uint16, we normally should convert the
1450 // values from Little Endian to Big Endian before passing the buffer to
1451 // SkColorSpaceXform::apply. However, in this test scenario we are creating
1452 // the Uin16 dataArray by multiplying a Uint8Clamped array members by 257,
1453 // hence the Big Endian and Little Endian representations are the same.
1454
1455 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(
1456 src_sk_color_space.get(), dst_sk_color_space.get());
1457
1458 if (!xform->apply(dst_color_format, converted_pixels.get(), src_color_format,
1459 src_data, num_pixels, kUnpremul_SkAlphaType))
1460 return false;
1461 return true;
1462 }
1463
1464 // The color settings of the surface of the canvas always remaines loyal to the
1465 // first created context 2D. Therefore, we have to test different canvas color
1466 // space settings for CanvasRenderingContext2D::putImageData() in different
1467 // tests.
1468 enum class CanvasColorSpaceSettings : uint8_t {
1469 CANVAS_SRGB = 0,
1470 CANVAS_LINEARSRGB = 1,
1471 CANVAS_REC2020 = 2,
1472 CANVAS_P3 = 3,
1473
1474 LAST = CANVAS_P3
1475 };
1476
1477 // This test verifies the correct behavior of putImageData member function in
1478 // color managed mode.
1479 void TestPutImageDataOnCanvasWithColorSpaceSettings(
1480 HTMLCanvasElement& canvas_element,
1481 CanvasColorSpaceSettings canvas_colorspace_setting,
1482 float color_tolerance) {
1483 bool experimental_canvas_features_runtime_flag =
1484 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
1485 bool color_correct_rendering_runtime_flag =
1486 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
1487 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(true);
1488 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(true);
1489
1490 bool test_passed = true;
1491 unsigned num_image_data_color_spaces = 3;
1492 CanvasColorSpace image_data_color_spaces[] = {
1493 kSRGBCanvasColorSpace, kRec2020CanvasColorSpace, kP3CanvasColorSpace,
1494 };
1495
1496 unsigned num_image_data_storage_formats = 3;
1497 ImageDataStorageFormat image_data_storage_formats[] = {
1498 kUint8ClampedArrayStorageFormat, kUint16ArrayStorageFormat,
1499 kFloat32ArrayStorageFormat,
1500 };
1501
1502 CanvasColorSpace canvas_color_spaces[] = {
1503 kSRGBCanvasColorSpace, kSRGBCanvasColorSpace, kRec2020CanvasColorSpace,
1504 kP3CanvasColorSpace,
1505 };
1506
1507 String canvas_color_space_names[] = {
1508 kSRGBCanvasColorSpaceName, kSRGBCanvasColorSpaceName,
1509 kRec2020CanvasColorSpaceName, kP3CanvasColorSpaceName};
1510
1511 CanvasPixelFormat canvas_pixel_formats[] = {
1512 kRGBA8CanvasPixelFormat, kF16CanvasPixelFormat, kF16CanvasPixelFormat,
1513 kF16CanvasPixelFormat,
1514 };
1515
1516 String canvas_pixel_format_names[] = {
1517 kRGBA8CanvasPixelFormatName, kF16CanvasPixelFormatName,
1518 kF16CanvasPixelFormatName, kF16CanvasPixelFormatName};
1519
1520 // Source pixels in RGBA32
1521 uint8_t u8_pixels[] = {255, 0, 0, 255, // Red
1522 0, 0, 0, 0, // Transparent
1523 255, 192, 128, 64, // Decreasing values
1524 93, 117, 205, 11}; // Random values
1525 unsigned data_length = 16;
1526
1527 uint16_t* u16_pixels = new uint16_t[data_length];
1528 for (unsigned i = 0; i < data_length; i++)
1529 u16_pixels[i] = u8_pixels[i] * 257;
1530
1531 float* f32_pixels = new float[data_length];
1532 for (unsigned i = 0; i < data_length; i++)
1533 f32_pixels[i] = u8_pixels[i] / 255.0;
1534
1535 DOMArrayBufferView* data_array = nullptr;
1536
1537 DOMUint8ClampedArray* data_u8 =
1538 DOMUint8ClampedArray::Create(u8_pixels, data_length);
1539 DCHECK(data_u8);
1540 EXPECT_EQ(data_length, data_u8->length());
1541 DOMUint16Array* data_u16 = DOMUint16Array::Create(u16_pixels, data_length);
1542 DCHECK(data_u16);
1543 EXPECT_EQ(data_length, data_u16->length());
1544 DOMFloat32Array* data_f32 = DOMFloat32Array::Create(f32_pixels, data_length);
1545 DCHECK(data_f32);
1546 EXPECT_EQ(data_length, data_f32->length());
1547
1548 ImageData* image_data = nullptr;
1549 ImageDataColorSettings color_settings;
1550
1551 // At most four bytes are needed for Float32 output per color component.
1552 std::unique_ptr<uint8_t[]> pixels_converted_manually(
1553 new uint8_t[data_length * 4]());
1554
1555 // Loop through different possible combinations of image data color space and
1556 // storage formats and create the respective test image data objects.
1557 for (unsigned i = 0; i < num_image_data_color_spaces; i++) {
1558 color_settings.setColorSpace(
1559 ImageData::CanvasColorSpaceName(image_data_color_spaces[i]));
1560
1561 for (unsigned j = 0; j < num_image_data_storage_formats; j++) {
1562 switch (image_data_storage_formats[j]) {
1563 case kUint8ClampedArrayStorageFormat:
1564 data_array = static_cast<DOMArrayBufferView*>(data_u8);
1565 color_settings.setStorageFormat(kUint8ClampedArrayStorageFormatName);
1566 break;
1567 case kUint16ArrayStorageFormat:
1568 data_array = static_cast<DOMArrayBufferView*>(data_u16);
1569 color_settings.setStorageFormat(kUint16ArrayStorageFormatName);
1570 break;
1571 case kFloat32ArrayStorageFormat:
1572 data_array = static_cast<DOMArrayBufferView*>(data_f32);
1573 color_settings.setStorageFormat(kFloat32ArrayStorageFormatName);
1574 break;
1575 default:
1576 NOTREACHED();
1577 }
1578
1579 image_data =
1580 ImageData::CreateForTest(IntSize(2, 2), data_array, &color_settings);
1581
1582 unsigned k = (unsigned)(canvas_colorspace_setting);
1583 // Convert the original data used to create ImageData to the
1584 // canvas color space and canvas pixel format.
1585 EXPECT_TRUE(ConvertPixelsToColorSpaceAndPixelFormatForTest(
1586 data_array, image_data_color_spaces[i], canvas_color_spaces[k],
1587 canvas_pixel_formats[k], pixels_converted_manually));
1588
1589 // Create a canvas and call putImageData and getImageData to make sure
1590 // the conversion is done correctly.
1591 CanvasContextCreationAttributes attributes;
1592 attributes.setAlpha(true);
1593 attributes.setColorSpace(canvas_color_space_names[k]);
1594 attributes.setPixelFormat(canvas_pixel_format_names[k]);
1595 CanvasRenderingContext2D* context =
1596 static_cast<CanvasRenderingContext2D*>(
1597 canvas_element.GetCanvasRenderingContext("2d", attributes));
1598 NonThrowableExceptionState exception_state;
1599 context->putImageData(image_data, 0, 0, exception_state);
1600
1601 void* pixels_from_get_image_data = nullptr;
1602 if (canvas_pixel_formats[k] == kRGBA8CanvasPixelFormat) {
1603 pixels_from_get_image_data =
1604 context->getImageData(0, 0, 2, 2, exception_state)->data()->Data();
1605 // Swizzle if needed
1606 if (kN32_SkColorType == kBGRA_8888_SkColorType) {
1607 SkSwapRB(static_cast<uint32_t*>(pixels_from_get_image_data),
1608 static_cast<uint32_t*>(pixels_from_get_image_data),
1609 data_length / 4);
1610 }
1611
1612 unsigned char* cpixels1 =
1613 static_cast<unsigned char*>(pixels_converted_manually.get());
1614 unsigned char* cpixels2 =
1615 static_cast<unsigned char*>(pixels_from_get_image_data);
1616 for (unsigned m = 0; m < data_length; m++) {
1617 if (abs(cpixels1[m] - cpixels2[m]) > color_tolerance)
1618 test_passed = false;
1619 }
1620 } else {
1621 pixels_from_get_image_data =
1622 context->getImageData(0, 0, 2, 2, exception_state)
1623 ->dataUnion()
1624 .getAsFloat32Array()
1625 .View()
1626 ->Data();
1627 float* fpixels1 = nullptr;
1628 float* fpixels2 = nullptr;
1629 void* vpointer = pixels_converted_manually.get();
1630 fpixels1 = static_cast<float*>(vpointer);
1631 fpixels2 = static_cast<float*>(pixels_from_get_image_data);
1632 for (unsigned m = 0; m < data_length; m++) {
1633 if (fpixels1[m] < 0)
1634 fpixels1[m] = 0;
1635 if (fabs(fpixels1[m] - fpixels2[m]) > color_tolerance) {
1636 test_passed = false;
1637 }
1638 }
1639
1640 ASSERT_TRUE(test_passed);
1641 }
1642 }
1643 }
1644 delete[] u16_pixels;
1645 delete[] f32_pixels;
1646
1647 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(
1648 experimental_canvas_features_runtime_flag);
1649 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(
1650 color_correct_rendering_runtime_flag);
1651 }
1652
1653 TEST_F(CanvasRenderingContext2DTest, ColorManagedPutImageDataOnSRGBCanvas) {
1654 TestPutImageDataOnCanvasWithColorSpaceSettings(
1655 CanvasElement(), CanvasColorSpaceSettings::CANVAS_SRGB, 0);
1656 }
1657
1658 TEST_F(CanvasRenderingContext2DTest,
1659 ColorManagedPutImageDataOnLinearSRGBCanvas) {
1660 TestPutImageDataOnCanvasWithColorSpaceSettings(
1661 CanvasElement(), CanvasColorSpaceSettings::CANVAS_LINEARSRGB, 0.15);
1662 }
1663
1664 TEST_F(CanvasRenderingContext2DTest, ColorManagedPutImageDataOnRec2020Canvas) {
1665 TestPutImageDataOnCanvasWithColorSpaceSettings(
1666 CanvasElement(), CanvasColorSpaceSettings::CANVAS_REC2020, 0.1);
1667 }
1668
1669 TEST_F(CanvasRenderingContext2DTest, ColorManagedPutImageDataOnP3Canvas) {
1670 TestPutImageDataOnCanvasWithColorSpaceSettings(
1671 CanvasElement(), CanvasColorSpaceSettings::CANVAS_P3, 0.1);
1672 }
1673
1388 } // namespace blink 1674 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698