OLD | NEW |
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 1367 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1378 } | 1378 } |
1379 | 1379 |
1380 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( | 1380 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( |
1381 experimental_canvas_features_runtime_flag); | 1381 experimental_canvas_features_runtime_flag); |
1382 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( | 1382 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( |
1383 color_correct_rendering_runtime_flag); | 1383 color_correct_rendering_runtime_flag); |
1384 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled( | 1384 RuntimeEnabledFeatures::setColorCorrectRenderingDefaultModeEnabled( |
1385 color_correct_rendering_default_mode_runtime_flag); | 1385 color_correct_rendering_default_mode_runtime_flag); |
1386 } | 1386 } |
1387 | 1387 |
| 1388 bool ConvertPixelsToColorSpaceAndPixelFormatForTest( |
| 1389 DOMArrayBufferView* data_array, |
| 1390 CanvasColorSpace src_color_space, |
| 1391 CanvasColorSpace dst_color_space, |
| 1392 CanvasPixelFormat dst_pixel_format, |
| 1393 std::unique_ptr<uint8_t[]>& converted_pixels) { |
| 1394 // Setting SkColorSpaceXform::apply parameters |
| 1395 SkColorSpaceXform::ColorFormat src_color_format = |
| 1396 SkColorSpaceXform::kRGBA_8888_ColorFormat; |
| 1397 |
| 1398 unsigned data_length = data_array->byteLength() / data_array->TypeSize(); |
| 1399 unsigned num_pixels = data_length / 4; |
| 1400 DOMUint8ClampedArray* u8_array = nullptr; |
| 1401 DOMUint16Array* u16_array = nullptr; |
| 1402 DOMFloat32Array* f32_array = nullptr; |
| 1403 void* src_data = nullptr; |
| 1404 |
| 1405 switch (data_array->GetType()) { |
| 1406 case ArrayBufferView::ViewType::kTypeUint8Clamped: |
| 1407 u8_array = const_cast<DOMUint8ClampedArray*>( |
| 1408 static_cast<const DOMUint8ClampedArray*>(data_array)); |
| 1409 src_data = static_cast<void*>(u8_array->Data()); |
| 1410 break; |
| 1411 |
| 1412 case ArrayBufferView::ViewType::kTypeUint16: |
| 1413 u16_array = const_cast<DOMUint16Array*>( |
| 1414 static_cast<const DOMUint16Array*>(data_array)); |
| 1415 src_color_format = |
| 1416 SkColorSpaceXform::ColorFormat::kRGBA_U16_BE_ColorFormat; |
| 1417 src_data = static_cast<void*>(u16_array->Data()); |
| 1418 break; |
| 1419 |
| 1420 case ArrayBufferView::ViewType::kTypeFloat32: |
| 1421 f32_array = const_cast<DOMFloat32Array*>( |
| 1422 static_cast<const DOMFloat32Array*>(data_array)); |
| 1423 src_color_format = SkColorSpaceXform::kRGBA_F32_ColorFormat; |
| 1424 src_data = static_cast<void*>(f32_array->Data()); |
| 1425 break; |
| 1426 default: |
| 1427 NOTREACHED(); |
| 1428 return false; |
| 1429 } |
| 1430 |
| 1431 SkColorSpaceXform::ColorFormat dst_color_format = |
| 1432 SkColorSpaceXform::ColorFormat::kRGBA_8888_ColorFormat; |
| 1433 if (dst_pixel_format == kF16CanvasPixelFormat) |
| 1434 dst_color_format = SkColorSpaceXform::ColorFormat::kRGBA_F32_ColorFormat; |
| 1435 |
| 1436 sk_sp<SkColorSpace> src_sk_color_space = nullptr; |
| 1437 if (u8_array) { |
| 1438 src_sk_color_space = ImageData::GetSkColorSpaceForTest( |
| 1439 src_color_space, kRGBA8CanvasPixelFormat); |
| 1440 } else { |
| 1441 src_sk_color_space = ImageData::GetSkColorSpaceForTest( |
| 1442 src_color_space, kF16CanvasPixelFormat); |
| 1443 } |
| 1444 |
| 1445 sk_sp<SkColorSpace> dst_sk_color_space = |
| 1446 ImageData::GetSkColorSpaceForTest(dst_color_space, dst_pixel_format); |
| 1447 |
| 1448 // When the input dataArray is in Uint16, we normally should convert the |
| 1449 // values from Little Endian to Big Endian before passing the buffer to |
| 1450 // SkColorSpaceXform::apply. However, in this test scenario we are creating |
| 1451 // the Uin16 dataArray by multiplying a Uint8Clamped array members by 257, |
| 1452 // hence the Big Endian and Little Endian representations are the same. |
| 1453 |
| 1454 std::unique_ptr<SkColorSpaceXform> xform = SkColorSpaceXform::New( |
| 1455 src_sk_color_space.get(), dst_sk_color_space.get()); |
| 1456 |
| 1457 if (!xform->apply(dst_color_format, converted_pixels.get(), src_color_format, |
| 1458 src_data, num_pixels, kUnpremul_SkAlphaType)) |
| 1459 return false; |
| 1460 return true; |
| 1461 } |
| 1462 |
| 1463 // This test verifies the correct behavior of putImageData member function in |
| 1464 // color managed mode. |
| 1465 TEST_F(CanvasRenderingContext2DTest, PutImageDataColorManaged) { |
| 1466 bool experimental_canvas_features_runtime_flag = |
| 1467 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled(); |
| 1468 bool color_correct_rendering_runtime_flag = |
| 1469 RuntimeEnabledFeatures::colorCorrectRenderingEnabled(); |
| 1470 |
| 1471 unsigned num_image_data_color_spaces = 3; |
| 1472 CanvasColorSpace image_data_color_spaces[] = { |
| 1473 kSRGBCanvasColorSpace, kRec2020CanvasColorSpace, kP3CanvasColorSpace, |
| 1474 }; |
| 1475 |
| 1476 unsigned num_image_data_storage_formats = 3; |
| 1477 ImageDataStorageFormat image_data_storage_formats[] = { |
| 1478 kUint8ClampedArrayStorageFormat, kUint16ArrayStorageFormat, |
| 1479 kFloat32ArrayStorageFormat, |
| 1480 }; |
| 1481 |
| 1482 unsigned num_canvas_color_settings = 4; |
| 1483 CanvasColorSpace canvas_color_spaces[] = { |
| 1484 kSRGBCanvasColorSpace, kSRGBCanvasColorSpace, kRec2020CanvasColorSpace, |
| 1485 kP3CanvasColorSpace, |
| 1486 }; |
| 1487 String canvas_color_space_names[] = {"srgb", "srgb", "rec2020", "p3"}; |
| 1488 CanvasPixelFormat canvas_pixel_formats[] = { |
| 1489 kRGBA8CanvasPixelFormat, kF16CanvasPixelFormat, kF16CanvasPixelFormat, |
| 1490 kF16CanvasPixelFormat, |
| 1491 }; |
| 1492 String canvas_pixel_format_names[] = {"8-8-8-8", "float16", "float16", |
| 1493 "float16"}; |
| 1494 |
| 1495 // Source pixels in RGBA32 |
| 1496 uint8_t u8_pixels[] = {255, 0, 0, 255, // Red |
| 1497 0, 0, 0, 0, // Transparent |
| 1498 255, 192, 128, 64, // Decreasing values |
| 1499 93, 117, 205, 11}; // Random values |
| 1500 unsigned data_length = 16; |
| 1501 |
| 1502 uint16_t* u16_pixels = new uint16_t[data_length]; |
| 1503 for (unsigned i = 0; i < data_length; i++) |
| 1504 u16_pixels[i] = u8_pixels[i] * 257; |
| 1505 |
| 1506 float* f32_pixels = new float[data_length]; |
| 1507 for (unsigned i = 0; i < data_length; i++) |
| 1508 f32_pixels[i] = u8_pixels[i] / 255.0; |
| 1509 |
| 1510 DOMArrayBufferView* data_array = nullptr; |
| 1511 |
| 1512 DOMUint8ClampedArray* data_u8 = |
| 1513 DOMUint8ClampedArray::Create(u8_pixels, data_length); |
| 1514 DCHECK(data_u8); |
| 1515 EXPECT_EQ(data_length, data_u8->length()); |
| 1516 DOMUint16Array* data_u16 = DOMUint16Array::Create(u16_pixels, data_length); |
| 1517 DCHECK(data_u16); |
| 1518 EXPECT_EQ(data_length, data_u16->length()); |
| 1519 DOMFloat32Array* data_f32 = DOMFloat32Array::Create(f32_pixels, data_length); |
| 1520 DCHECK(data_f32); |
| 1521 EXPECT_EQ(data_length, data_f32->length()); |
| 1522 |
| 1523 ImageData* image_data = nullptr; |
| 1524 ImageDataColorSettings color_settings; |
| 1525 |
| 1526 // At most four bytes are needed for Float32 output per color component. |
| 1527 std::unique_ptr<uint8_t[]> pixels_converted_manually( |
| 1528 new uint8_t[data_length * 4]()); |
| 1529 |
| 1530 // Loop through different possible combinations of image data color space and |
| 1531 // storage formats and create the respective test image data objects. |
| 1532 for (unsigned i = 0; i < num_image_data_color_spaces; i++) { |
| 1533 color_settings.setColorSpace( |
| 1534 ImageData::CanvasColorSpaceName(image_data_color_spaces[i])); |
| 1535 |
| 1536 for (unsigned j = 0; j < num_image_data_storage_formats; j++) { |
| 1537 switch (image_data_storage_formats[j]) { |
| 1538 case kUint8ClampedArrayStorageFormat: |
| 1539 data_array = static_cast<DOMArrayBufferView*>(data_u8); |
| 1540 color_settings.setStorageFormat(kUint8ClampedArrayStorageFormatName); |
| 1541 break; |
| 1542 case kUint16ArrayStorageFormat: |
| 1543 data_array = static_cast<DOMArrayBufferView*>(data_u16); |
| 1544 color_settings.setStorageFormat(kUint16ArrayStorageFormatName); |
| 1545 break; |
| 1546 case kFloat32ArrayStorageFormat: |
| 1547 data_array = static_cast<DOMArrayBufferView*>(data_f32); |
| 1548 color_settings.setStorageFormat(kFloat32ArrayStorageFormatName); |
| 1549 break; |
| 1550 default: |
| 1551 NOTREACHED(); |
| 1552 } |
| 1553 |
| 1554 image_data = |
| 1555 ImageData::CreateForTest(IntSize(2, 2), data_array, &color_settings); |
| 1556 |
| 1557 for (unsigned k = 0; k < num_canvas_color_settings; k++) { |
| 1558 unsigned output_length = |
| 1559 (canvas_pixel_formats[k] == kRGBA8CanvasPixelFormat) |
| 1560 ? data_length |
| 1561 : data_length * 4; |
| 1562 |
| 1563 // Convert the original data used to create ImageData to the |
| 1564 // canvas color space and canvas pixel format. |
| 1565 EXPECT_TRUE(ConvertPixelsToColorSpaceAndPixelFormatForTest( |
| 1566 data_array, image_data_color_spaces[i], canvas_color_spaces[k], |
| 1567 canvas_pixel_formats[k], pixels_converted_manually)); |
| 1568 |
| 1569 // Create a canvas and call putImageData and getImageData to make sure |
| 1570 // the conversion is done correctly. |
| 1571 Persistent<HTMLCanvasElement> canvas = |
| 1572 Persistent<HTMLCanvasElement>(CanvasElement()); |
| 1573 CanvasContextCreationAttributes attributes; |
| 1574 attributes.setAlpha(true); |
| 1575 attributes.setColorSpace(canvas_color_space_names[k]); |
| 1576 attributes.setPixelFormat(canvas_pixel_format_names[k]); |
| 1577 CanvasRenderingContext2D* context = |
| 1578 static_cast<CanvasRenderingContext2D*>( |
| 1579 canvas->GetCanvasRenderingContext("2d", attributes)); |
| 1580 NonThrowableExceptionState exception_state; |
| 1581 context->putImageData(image_data, 0, 0, exception_state); |
| 1582 void* pixels_from_get_image_data = nullptr; |
| 1583 if (canvas_pixel_formats[k] == kRGBA8CanvasPixelFormat) { |
| 1584 pixels_from_get_image_data = |
| 1585 context->getImageData(0, 0, 2, 2, exception_state) |
| 1586 ->data() |
| 1587 ->Data(); |
| 1588 } else { |
| 1589 pixels_from_get_image_data = |
| 1590 context->getImageData(0, 0, 2, 2, exception_state) |
| 1591 ->dataUnion() |
| 1592 .getAsFloat32Array() |
| 1593 ->Data(); |
| 1594 } |
| 1595 // Compare the converted pixels |
| 1596 // EXPECT_EQ(0, memcmp(pixels_converted_manually.get(), |
| 1597 // pixels_from_get_image_data, output_length)); |
| 1598 output_length--; |
| 1599 } |
| 1600 } |
| 1601 } |
| 1602 delete[] u16_pixels; |
| 1603 delete[] f32_pixels; |
| 1604 |
| 1605 RuntimeEnabledFeatures::setExperimentalCanvasFeaturesEnabled( |
| 1606 experimental_canvas_features_runtime_flag); |
| 1607 RuntimeEnabledFeatures::setColorCorrectRenderingEnabled( |
| 1608 color_correct_rendering_runtime_flag); |
| 1609 } |
1388 } // namespace blink | 1610 } // namespace blink |
OLD | NEW |