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

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: Rebaseline Created 3 years, 7 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/V8BindingForCore.h" 8 #include "bindings/core/v8/V8BindingForCore.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 19 matching lines...) Expand all
30 #include "platform/graphics/test/FakeWebGraphicsContext3DProvider.h" 30 #include "platform/graphics/test/FakeWebGraphicsContext3DProvider.h"
31 #include "platform/loader/fetch/MemoryCache.h" 31 #include "platform/loader/fetch/MemoryCache.h"
32 #include "platform/testing/TestingPlatformSupport.h" 32 #include "platform/testing/TestingPlatformSupport.h"
33 #include "platform/wtf/PtrUtil.h" 33 #include "platform/wtf/PtrUtil.h"
34 #include "public/platform/scheduler/test/renderer_scheduler_test_support.h" 34 #include "public/platform/scheduler/test/renderer_scheduler_test_support.h"
35 #include "testing/gmock/include/gmock/gmock.h" 35 #include "testing/gmock/include/gmock/gmock.h"
36 #include "testing/gtest/include/gtest/gtest.h" 36 #include "testing/gtest/include/gtest/gtest.h"
37 #include "third_party/skia/include/core/SkColorSpaceXform.h" 37 #include "third_party/skia/include/core/SkColorSpaceXform.h"
38 #include "third_party/skia/include/core/SkImage.h" 38 #include "third_party/skia/include/core/SkImage.h"
39 #include "third_party/skia/include/core/SkSurface.h" 39 #include "third_party/skia/include/core/SkSurface.h"
40 #include "third_party/skia/include/core/SkSwizzle.h"
40 41
41 using ::testing::Mock; 42 using ::testing::Mock;
42 43
43 namespace blink { 44 namespace blink {
44 45
45 namespace { 46 namespace {
46 47
47 gfx::ColorSpace AdobeRGBColorSpace() { 48 gfx::ColorSpace AdobeRGBColorSpace() {
48 return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::ADOBE_RGB, 49 return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::ADOBE_RGB,
49 gfx::ColorSpace::TransferID::GAMMA22); 50 gfx::ColorSpace::TransferID::GAMMA22);
(...skipping 1285 matching lines...) Expand 10 before | Expand all | Expand 10 after
1335 } 1336 }
1336 1337
1337 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( 1338 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(
1338 experimental_canvas_features_runtime_flag); 1339 experimental_canvas_features_runtime_flag);
1339 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( 1340 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(
1340 color_correct_rendering_runtime_flag); 1341 color_correct_rendering_runtime_flag);
1341 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled( 1342 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled(
1342 color_correct_rendering_default_mode_runtime_flag); 1343 color_correct_rendering_default_mode_runtime_flag);
1343 } 1344 }
1344 1345
1346 bool ConvertPixelsToColorSpaceAndPixelFormatForTest(
1347 DOMArrayBufferView* data_array,
1348 CanvasColorSpace src_color_space,
1349 CanvasColorSpace dst_color_space,
1350 CanvasPixelFormat dst_pixel_format,
1351 std::unique_ptr<uint8_t[]>& converted_pixels) {
1352 // Setting SkColorSpaceXform::apply parameters
1353 SkColorSpaceXform::ColorFormat src_color_format =
1354 SkColorSpaceXform::kRGBA_8888_ColorFormat;
1355
1356 unsigned data_length = data_array->byteLength() / data_array->TypeSize();
1357 unsigned num_pixels = data_length / 4;
1358 DOMUint8ClampedArray* u8_array = nullptr;
1359 DOMUint16Array* u16_array = nullptr;
1360 DOMFloat32Array* f32_array = nullptr;
1361 void* src_data = nullptr;
1362
1363 switch (data_array->GetType()) {
1364 case ArrayBufferView::ViewType::kTypeUint8Clamped:
1365 u8_array = const_cast<DOMUint8ClampedArray*>(
1366 static_cast<const DOMUint8ClampedArray*>(data_array));
1367 src_data = static_cast<void*>(u8_array->Data());
1368 break;
1369
1370 case ArrayBufferView::ViewType::kTypeUint16:
1371 u16_array = const_cast<DOMUint16Array*>(
1372 static_cast<const DOMUint16Array*>(data_array));
1373 src_color_format =
1374 SkColorSpaceXform::ColorFormat::kRGBA_U16_BE_ColorFormat;
1375 src_data = static_cast<void*>(u16_array->Data());
1376 break;
1377
1378 case ArrayBufferView::ViewType::kTypeFloat32:
1379 f32_array = const_cast<DOMFloat32Array*>(
1380 static_cast<const DOMFloat32Array*>(data_array));
1381 src_color_format = SkColorSpaceXform::kRGBA_F32_ColorFormat;
1382 src_data = static_cast<void*>(f32_array->Data());
1383 break;
1384 default:
1385 NOTREACHED();
1386 return false;
1387 }
1388
1389 SkColorSpaceXform::ColorFormat dst_color_format =
1390 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat;
1391 if (dst_pixel_format == kF16CanvasPixelFormat)
1392 dst_color_format = SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat;
1393
1394 sk_sp<SkColorSpace> src_sk_color_space = nullptr;
1395 if (u8_array) {
1396 src_sk_color_space = ImageData::GetSkColorSpaceForTest(
1397 src_color_space, kRGBA8CanvasPixelFormat);
1398 } else {
1399 src_sk_color_space = ImageData::GetSkColorSpaceForTest(
1400 src_color_space, kF16CanvasPixelFormat);
1401 }
1402
1403 sk_sp<SkColorSpace> dst_sk_color_space =
1404 ImageData::GetSkColorSpaceForTest(dst_color_space, dst_pixel_format);
1405
1406 // When the input dataArray is in Uint16, we normally should convert the
1407 // values from Little Endian to Big Endian before passing the buffer to
1408 // SkColorSpaceXform::apply. However, in this test scenario we are creating
1409 // the Uin16 dataArray by multiplying a Uint8Clamped array members by 257,
1410 // hence the Big Endian and Little Endian representations are the same.
1411
1412 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New(
1413 src_sk_color_space.get(), dst_sk_color_space.get());
1414
1415 if (!xform->apply(dst_color_format, converted_pixels.get(), src_color_format,
1416 src_data, num_pixels, kUnpremul_SkAlphaType))
1417 return false;
1418 return true;
1419 }
1420
1421 // The color settings of the surface of the canvas always remaines loyal to the
1422 // first created context 2D. Therefore, we have to test different canvas color
1423 // space settings for CanvasRenderingContext2D::putImageData() in different
1424 // tests.
1425 enum class CanvasColorSpaceSettings : uint8_t {
1426 CANVAS_SRGB = 0,
1427 CANVAS_LINEARSRGB = 1,
1428 CANVAS_REC2020 = 2,
1429 CANVAS_P3 = 3,
1430
1431 LAST = CANVAS_P3
1432 };
1433
1434 // This test verifies the correct behavior of putImageData member function in
1435 // color managed mode.
1436 void TestPutImageDataOnCanvasWithColorSpaceSettings(
1437 HTMLCanvasElement& canvas_element,
1438 CanvasColorSpaceSettings canvas_colorspace_setting,
1439 float color_tolerance) {
1440 bool experimental_canvas_features_runtime_flag =
1441 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled();
1442 bool color_correct_rendering_runtime_flag =
1443 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
1444 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(true);
1445 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(true);
1446
1447 bool test_passed = true;
1448 unsigned num_image_data_color_spaces = 3;
1449 CanvasColorSpace image_data_color_spaces[] = {
1450 kSRGBCanvasColorSpace, kRec2020CanvasColorSpace, kP3CanvasColorSpace,
1451 };
1452
1453 unsigned num_image_data_storage_formats = 3;
1454 ImageDataStorageFormat image_data_storage_formats[] = {
1455 kUint8ClampedArrayStorageFormat, kUint16ArrayStorageFormat,
1456 kFloat32ArrayStorageFormat,
1457 };
1458
1459 CanvasColorSpace canvas_color_spaces[] = {
1460 kSRGBCanvasColorSpace, kSRGBCanvasColorSpace, kRec2020CanvasColorSpace,
1461 kP3CanvasColorSpace,
1462 };
1463
1464 String canvas_color_space_names[] = {
1465 kSRGBCanvasColorSpaceName, kSRGBCanvasColorSpaceName,
1466 kRec2020CanvasColorSpaceName, kP3CanvasColorSpaceName};
1467
1468 CanvasPixelFormat canvas_pixel_formats[] = {
1469 kRGBA8CanvasPixelFormat, kF16CanvasPixelFormat, kF16CanvasPixelFormat,
1470 kF16CanvasPixelFormat,
1471 };
1472
1473 String canvas_pixel_format_names[] = {
1474 kRGBA8CanvasPixelFormatName, kF16CanvasPixelFormatName,
1475 kF16CanvasPixelFormatName, kF16CanvasPixelFormatName};
1476
1477 // Source pixels in RGBA32
1478 uint8_t u8_pixels[] = {255, 0, 0, 255, // Red
1479 0, 0, 0, 0, // Transparent
1480 255, 192, 128, 64, // Decreasing values
1481 93, 117, 205, 11}; // Random values
1482 unsigned data_length = 16;
1483
1484 uint16_t* u16_pixels = new uint16_t[data_length];
1485 for (unsigned i = 0; i < data_length; i++)
1486 u16_pixels[i] = u8_pixels[i] * 257;
1487
1488 float* f32_pixels = new float[data_length];
1489 for (unsigned i = 0; i < data_length; i++)
1490 f32_pixels[i] = u8_pixels[i] / 255.0;
1491
1492 DOMArrayBufferView* data_array = nullptr;
1493
1494 DOMUint8ClampedArray* data_u8 =
1495 DOMUint8ClampedArray::Create(u8_pixels, data_length);
1496 DCHECK(data_u8);
1497 EXPECT_EQ(data_length, data_u8->length());
1498 DOMUint16Array* data_u16 = DOMUint16Array::Create(u16_pixels, data_length);
1499 DCHECK(data_u16);
1500 EXPECT_EQ(data_length, data_u16->length());
1501 DOMFloat32Array* data_f32 = DOMFloat32Array::Create(f32_pixels, data_length);
1502 DCHECK(data_f32);
1503 EXPECT_EQ(data_length, data_f32->length());
1504
1505 ImageData* image_data = nullptr;
1506 ImageDataColorSettings color_settings;
1507
1508 // At most four bytes are needed for Float32 output per color component.
1509 std::unique_ptr<uint8_t[]> pixels_converted_manually(
1510 new uint8_t[data_length * 4]());
1511
1512 // Loop through different possible combinations of image data color space and
1513 // storage formats and create the respective test image data objects.
1514 for (unsigned i = 0; i < num_image_data_color_spaces; i++) {
1515 color_settings.setColorSpace(
1516 ImageData::CanvasColorSpaceName(image_data_color_spaces[i]));
1517
1518 for (unsigned j = 0; j < num_image_data_storage_formats; j++) {
1519 switch (image_data_storage_formats[j]) {
1520 case kUint8ClampedArrayStorageFormat:
1521 data_array = static_cast<DOMArrayBufferView*>(data_u8);
1522 color_settings.setStorageFormat(kUint8ClampedArrayStorageFormatName);
1523 break;
1524 case kUint16ArrayStorageFormat:
1525 data_array = static_cast<DOMArrayBufferView*>(data_u16);
1526 color_settings.setStorageFormat(kUint16ArrayStorageFormatName);
1527 break;
1528 case kFloat32ArrayStorageFormat:
1529 data_array = static_cast<DOMArrayBufferView*>(data_f32);
1530 color_settings.setStorageFormat(kFloat32ArrayStorageFormatName);
1531 break;
1532 default:
1533 NOTREACHED();
1534 }
1535
1536 image_data =
1537 ImageData::CreateForTest(IntSize(2, 2), data_array, &color_settings);
1538
1539 unsigned k = (unsigned)(canvas_colorspace_setting);
1540 // Convert the original data used to create ImageData to the
1541 // canvas color space and canvas pixel format.
1542 EXPECT_TRUE(ConvertPixelsToColorSpaceAndPixelFormatForTest(
1543 data_array, image_data_color_spaces[i], canvas_color_spaces[k],
1544 canvas_pixel_formats[k], pixels_converted_manually));
1545
1546 // Create a canvas and call putImageData and getImageData to make sure
1547 // the conversion is done correctly.
1548 CanvasContextCreationAttributes attributes;
1549 attributes.setAlpha(true);
1550 attributes.setColorSpace(canvas_color_space_names[k]);
1551 attributes.setPixelFormat(canvas_pixel_format_names[k]);
1552 CanvasRenderingContext2D* context =
1553 static_cast<CanvasRenderingContext2D*>(
1554 canvas_element.GetCanvasRenderingContext("2d", attributes));
1555 NonThrowableExceptionState exception_state;
1556 context->putImageData(image_data, 0, 0, exception_state);
1557
1558 void* pixels_from_get_image_data = nullptr;
1559 if (canvas_pixel_formats[k] == kRGBA8CanvasPixelFormat) {
1560 pixels_from_get_image_data =
1561 context->getImageData(0, 0, 2, 2, exception_state)->data()->Data();
1562 // Swizzle if needed
1563 if (kN32_SkColorType == kBGRA_8888_SkColorType) {
1564 SkSwapRB(static_cast<uint32_t*>(pixels_from_get_image_data),
1565 static_cast<uint32_t*>(pixels_from_get_image_data),
1566 data_length / 4);
1567 }
1568
1569 unsigned char* cpixels1 =
1570 static_cast<unsigned char*>(pixels_converted_manually.get());
1571 unsigned char* cpixels2 =
1572 static_cast<unsigned char*>(pixels_from_get_image_data);
1573 for (unsigned m = 0; m < data_length; m++) {
1574 if (abs(cpixels1[m] - cpixels2[m]) > color_tolerance)
1575 test_passed = false;
1576 }
1577 } else {
1578 pixels_from_get_image_data =
1579 context->getImageData(0, 0, 2, 2, exception_state)
1580 ->dataUnion()
1581 .getAsFloat32Array()
1582 .View()
1583 ->Data();
1584 float* fpixels1 = nullptr;
1585 float* fpixels2 = nullptr;
1586 void* vpointer = pixels_converted_manually.get();
1587 fpixels1 = static_cast<float*>(vpointer);
1588 fpixels2 = static_cast<float*>(pixels_from_get_image_data);
1589 for (unsigned m = 0; m < data_length; m++) {
1590 if (fpixels1[m] < 0)
1591 fpixels1[m] = 0;
1592 if (fabs(fpixels1[m] - fpixels2[m]) > color_tolerance) {
1593 test_passed = false;
1594 }
1595 }
1596
1597 ASSERT_TRUE(test_passed);
1598 }
1599 }
1600 }
1601 delete[] u16_pixels;
1602 delete[] f32_pixels;
1603
1604 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled(
1605 experimental_canvas_features_runtime_flag);
1606 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled(
1607 color_correct_rendering_runtime_flag);
1608 }
1609
1610 TEST_F(CanvasRenderingContext2DTest, ColorManagedPutImageDataOnSRGBCanvas) {
1611 TestPutImageDataOnCanvasWithColorSpaceSettings(
1612 CanvasElement(), CanvasColorSpaceSettings::CANVAS_SRGB, 0);
1613 }
1614
1615 TEST_F(CanvasRenderingContext2DTest,
1616 ColorManagedPutImageDataOnLinearSRGBCanvas) {
1617 TestPutImageDataOnCanvasWithColorSpaceSettings(
1618 CanvasElement(), CanvasColorSpaceSettings::CANVAS_LINEARSRGB, 0.15);
1619 }
1620
1621 TEST_F(CanvasRenderingContext2DTest, ColorManagedPutImageDataOnRec2020Canvas) {
1622 TestPutImageDataOnCanvasWithColorSpaceSettings(
1623 CanvasElement(), CanvasColorSpaceSettings::CANVAS_REC2020, 0.1);
1624 }
1625
1626 TEST_F(CanvasRenderingContext2DTest, ColorManagedPutImageDataOnP3Canvas) {
1627 TestPutImageDataOnCanvasWithColorSpaceSettings(
1628 CanvasElement(), CanvasColorSpaceSettings::CANVAS_P3, 0.1);
1629 }
1630
1345 void OverrideScriptEnabled(Settings& settings) { 1631 void OverrideScriptEnabled(Settings& settings) {
1346 // Simulate that we allow scripts, so that HTMLCanvasElement uses 1632 // Simulate that we allow scripts, so that HTMLCanvasElement uses
1347 // LayoutHTMLCanvas. 1633 // LayoutHTMLCanvas.
1348 settings.SetScriptEnabled(true); 1634 settings.SetScriptEnabled(true);
1349 } 1635 }
1350 1636
1351 class CanvasRenderingContext2DTestWithTestingPlatform 1637 class CanvasRenderingContext2DTestWithTestingPlatform
1352 : public CanvasRenderingContext2DTest { 1638 : public CanvasRenderingContext2DTest {
1353 protected: 1639 protected:
1354 void SetUp() override { 1640 void SetUp() override {
(...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after
1412 1698
1413 // Wake up again, which should request a compositing update synchronously. 1699 // Wake up again, which should request a compositing update synchronously.
1414 GetDocument().GetPage()->SetVisibilityState(kPageVisibilityStateVisible, 1700 GetDocument().GetPage()->SetVisibilityState(kPageVisibilityStateVisible,
1415 false); 1701 false);
1416 EXPECT_EQ(!!CANVAS2D_HIBERNATION_ENABLED, 1702 EXPECT_EQ(!!CANVAS2D_HIBERNATION_ENABLED,
1417 layer->NeedsCompositingInputsUpdate()); 1703 layer->NeedsCompositingInputsUpdate());
1418 RunUntilIdle(); // Clear task queue. 1704 RunUntilIdle(); // Clear task queue.
1419 } 1705 }
1420 1706
1421 } // namespace blink 1707 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698