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

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

Issue 2797213002: Fix BaseRenderingContext2D create/put/get-ImageData() for color managed canvas (Closed)
Patch Set: Layout test added 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 2016 The Chromium Authors. All rights reserved. 1 // Copyright 2016 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/BaseRenderingContext2D.h" 5 #include "modules/canvas2d/BaseRenderingContext2D.h"
6 6
7 #include "bindings/core/v8/ExceptionMessages.h" 7 #include "bindings/core/v8/ExceptionMessages.h"
8 #include "bindings/core/v8/ExceptionState.h" 8 #include "bindings/core/v8/ExceptionState.h"
9 #include "bindings/core/v8/ScriptState.h" 9 #include "bindings/core/v8/ScriptState.h"
10 #include "core/css/cssom/CSSURLImageValue.h" 10 #include "core/css/cssom/CSSURLImageValue.h"
(...skipping 1478 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect); 1489 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect);
1490 if (!canvasIRect.intersect(transformedClipBounds)) 1490 if (!canvasIRect.intersect(transformedClipBounds))
1491 return false; 1491 return false;
1492 1492
1493 if (dirtyRect) 1493 if (dirtyRect)
1494 *dirtyRect = canvasIRect; 1494 *dirtyRect = canvasIRect;
1495 1495
1496 return true; 1496 return true;
1497 } 1497 }
1498 1498
1499 bool BaseRenderingContext2D::colorSettingsAsImageDataColorSettings(
1500 ImageDataColorSettings& colorSettings) const {
1501 if (!RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() ||
1502 !RuntimeEnabledFeatures::colorCorrectRenderingEnabled())
1503 return false;
1504 colorSettings.setColorSpace(renderingContext()->colorSpaceAsString());
1505 switch (renderingContext()->pixelFormat()) {
1506 case kRGBA8CanvasPixelFormat:
1507 colorSettings.setStorageFormat(kUint8ClampedArrayStorageFormatName);
1508 break;
1509 case kF16CanvasPixelFormat:
1510 colorSettings.setStorageFormat(kFloat32ArrayStorageFormatName);
1511 break;
1512 case kRGB10A2CanvasPixelFormat:
1513 case kRGBA12CanvasPixelFormat:
1514 default:
1515 NOTREACHED();
1516 return false;
1517 }
1518 return true;
1519 }
1520
1499 ImageData* BaseRenderingContext2D::createImageData( 1521 ImageData* BaseRenderingContext2D::createImageData(
1500 ImageData* imageData, 1522 ImageData* imageData,
1501 ExceptionState& exceptionState) const { 1523 ExceptionState& exceptionState) const {
1502 ImageData* result = ImageData::create(imageData->size()); 1524 ImageData* result = nullptr;
1525 if (RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
1526 RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) {
1527 ImageDataColorSettings colorSettings;
1528 if (colorSettingsAsImageDataColorSettings(colorSettings))
1529 result = ImageData::create(imageData->size(), &colorSettings);
1530 } else {
1531 result = ImageData::create(imageData->size());
1532 }
1503 if (!result) 1533 if (!result)
1504 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1534 exceptionState.throwRangeError("Out of memory at ImageData creation");
1505 return result; 1535 return result;
1506 } 1536 }
1507 1537
1508 ImageData* BaseRenderingContext2D::createImageData( 1538 ImageData* BaseRenderingContext2D::createImageData(
1509 int sw, 1539 int sw,
1510 int sh, 1540 int sh,
1511 ExceptionState& exceptionState) const { 1541 ExceptionState& exceptionState) const {
1512 if (!sw || !sh) { 1542 if (!sw || !sh) {
1513 exceptionState.throwDOMException( 1543 exceptionState.throwDOMException(
1514 IndexSizeError, 1544 IndexSizeError,
1515 String::format("The source %s is 0.", sw ? "height" : "width")); 1545 String::format("The source %s is 0.", sw ? "height" : "width"));
1516 return nullptr; 1546 return nullptr;
1517 } 1547 }
1518 1548
1519 IntSize size(abs(sw), abs(sh)); 1549 IntSize size(abs(sw), abs(sh));
1520 1550 ImageData* result = nullptr;
1521 ImageData* result = ImageData::create(size); 1551 if (RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
1552 RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) {
1553 ImageDataColorSettings colorSettings;
1554 if (colorSettingsAsImageDataColorSettings(colorSettings))
1555 result = ImageData::create(size, &colorSettings);
1556 } else {
1557 result = ImageData::create(size);
1558 }
1522 if (!result) 1559 if (!result)
1523 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1560 exceptionState.throwRangeError("Out of memory at ImageData creation");
1524 return result; 1561 return result;
1525 } 1562 }
1526 1563
1527 ImageData* BaseRenderingContext2D::getImageData( 1564 ImageData* BaseRenderingContext2D::getImageData(
1528 int sx, 1565 int sx,
1529 int sy, 1566 int sy,
1530 int sw, 1567 int sw,
1531 int sh, 1568 int sh,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
1566 10000000, 50)); 1603 10000000, 50));
1567 timer.emplace(scopedUsCounterDisplayList); 1604 timer.emplace(scopedUsCounterDisplayList);
1568 } else { 1605 } else {
1569 DEFINE_THREAD_SAFE_STATIC_LOCAL( 1606 DEFINE_THREAD_SAFE_STATIC_LOCAL(
1570 CustomCountHistogram, scopedUsCounterCPU, 1607 CustomCountHistogram, scopedUsCounterCPU,
1571 new CustomCountHistogram("Blink.Canvas.GetImageData.CPU", 0, 10000000, 1608 new CustomCountHistogram("Blink.Canvas.GetImageData.CPU", 0, 10000000,
1572 50)); 1609 50));
1573 timer.emplace(scopedUsCounterCPU); 1610 timer.emplace(scopedUsCounterCPU);
1574 } 1611 }
1575 1612
1613 ImageDataColorSettings colorSettings;
1614 bool canvasIsColorManaged =
1615 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
1616 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
1617 if (canvasIsColorManaged)
1618 canvasIsColorManaged = colorSettingsAsImageDataColorSettings(colorSettings);
1576 IntRect imageDataRect(sx, sy, sw, sh); 1619 IntRect imageDataRect(sx, sy, sw, sh);
1577 DVLOG(1) << sx << ", " << sy << ", " << sw << ", " << sh; 1620 DVLOG(1) << sx << ", " << sy << ", " << sw << ", " << sh;
1578 ImageBuffer* buffer = imageBuffer(); 1621 ImageBuffer* buffer = imageBuffer();
1579 if (!buffer || isContextLost()) { 1622 if (!buffer || isContextLost()) {
1580 ImageData* result = ImageData::create(imageDataRect.size()); 1623 ImageData* result = nullptr;
1624 if (canvasIsColorManaged)
1625 result = ImageData::create(imageDataRect.size(), &colorSettings);
1626 else
1627 result = ImageData::create(imageDataRect.size());
1581 if (!result) 1628 if (!result)
1582 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1629 exceptionState.throwRangeError("Out of memory at ImageData creation");
1583 return result; 1630 return result;
1584 } 1631 }
1585 1632
1586 WTF::ArrayBufferContents contents; 1633 WTF::ArrayBufferContents contents;
1587 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents)) { 1634 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents)) {
1588 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1635 exceptionState.throwRangeError("Out of memory at ImageData creation");
1589 return nullptr; 1636 return nullptr;
1590 } 1637 }
1591 1638
1592 DOMArrayBuffer* arrayBuffer = DOMArrayBuffer::create(contents); 1639 DOMArrayBuffer* arrayBuffer = nullptr;
1640 DOMArrayBufferView* arrayBufferView = nullptr;
1641 DOMFloat32Array* dataArray = nullptr;
1642
1643 if (canvasIsColorManaged) {
1644 ImageDataStorageFormat storageFormat =
1645 ImageData::imageDataStorageFormat(colorSettings.storageFormat());
1646 switch (storageFormat) {
1647 case kUint8ClampedArrayStorageFormat:
1648 arrayBuffer = DOMArrayBuffer::create(contents);
1649 return ImageData::create(
1650 imageDataRect.size(),
1651 DOMUint8ClampedArray::create(arrayBuffer, 0,
1652 arrayBuffer->byteLength()));
1653 break;
1654 case kUint16ArrayStorageFormat:
1655 NOTREACHED();
1656 break;
1657 case kFloat32ArrayStorageFormat:
1658 arrayBufferView = ImageData::
1659 convertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
1660 contents, renderingContext()->pixelFormat(), storageFormat);
1661 dataArray = const_cast<DOMFloat32Array*>(
1662 static_cast<const DOMFloat32Array*>(arrayBufferView));
1663 return ImageData::create(imageDataRect.size(), arrayBufferView,
1664 &colorSettings);
1665 default:
1666 NOTREACHED();
1667 }
1668 return nullptr;
1669 }
1670
1671 arrayBuffer = DOMArrayBuffer::create(contents);
1593 return ImageData::create( 1672 return ImageData::create(
1594 imageDataRect.size(), 1673 imageDataRect.size(),
1595 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength())); 1674 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength()));
1596 } 1675 }
1597 1676
1598 void BaseRenderingContext2D::putImageData(ImageData* data, 1677 void BaseRenderingContext2D::putImageData(ImageData* data,
1599 int dx, 1678 int dx,
1600 int dy, 1679 int dy,
1601 ExceptionState& exceptionState) { 1680 ExceptionState& exceptionState) {
1602 putImageData(data, dx, dy, 0, 0, data->width(), data->height(), 1681 putImageData(data, dx, dy, 0, 0, data->width(), data->height(),
1603 exceptionState); 1682 exceptionState);
1604 } 1683 }
1605 1684
1606 void BaseRenderingContext2D::putImageData(ImageData* data, 1685 void BaseRenderingContext2D::putImageData(ImageData* data,
1607 int dx, 1686 int dx,
1608 int dy, 1687 int dy,
1609 int dirtyX, 1688 int dirtyX,
1610 int dirtyY, 1689 int dirtyY,
1611 int dirtyWidth, 1690 int dirtyWidth,
1612 int dirtyHeight, 1691 int dirtyHeight,
1613 ExceptionState& exceptionState) { 1692 ExceptionState& exceptionState) {
1614 m_usageCounters.numPutImageDataCalls++; 1693 m_usageCounters.numPutImageDataCalls++;
1615 m_usageCounters.areaPutImageDataCalls += dirtyWidth * dirtyHeight; 1694 m_usageCounters.areaPutImageDataCalls += dirtyWidth * dirtyHeight;
1616 if (data->data()->bufferBase()->isNeutered()) { 1695
1696 bool canvasIsColorManaged =
1697 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
1698 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
Justin Novosad 2017/04/06 19:01:04 This check is copied in many placed, perhaps we co
zakerinasab 2017/04/11 19:52:59 Done.
1699
1700 bool dataIsNeutered = false;
1701 if (canvasIsColorManaged) {
1702 dataIsNeutered =
1703 (data->dataUnion().isUint8ClampedArray() &&
1704 data->dataUnion()
1705 .getAsUint8ClampedArray()
1706 ->bufferBase()
1707 ->isNeutered()) ||
1708 (data->dataUnion().isUint16Array() &&
1709 data->dataUnion().getAsUint16Array()->bufferBase()->isNeutered()) ||
1710 (data->dataUnion().isFloat32Array() &&
1711 data->dataUnion().getAsFloat32Array()->bufferBase()->isNeutered());
1712 } else {
1713 dataIsNeutered = data->data()->bufferBase()->isNeutered();
1714 }
1715 if (dataIsNeutered) {
1617 exceptionState.throwDOMException(InvalidStateError, 1716 exceptionState.throwDOMException(InvalidStateError,
1618 "The source data has been neutered."); 1717 "The source data has been neutered.");
1619 return; 1718 return;
1620 } 1719 }
1720
1621 ImageBuffer* buffer = imageBuffer(); 1721 ImageBuffer* buffer = imageBuffer();
1622 if (!buffer) 1722 if (!buffer)
1623 return; 1723 return;
1624 1724
1625 if (dirtyWidth < 0) { 1725 if (dirtyWidth < 0) {
1626 dirtyX += dirtyWidth; 1726 dirtyX += dirtyWidth;
1627 dirtyWidth = -dirtyWidth; 1727 dirtyWidth = -dirtyWidth;
1628 } 1728 }
1629 1729
1630 if (dirtyHeight < 0) { 1730 if (dirtyHeight < 0) {
(...skipping 29 matching lines...) Expand all
1660 50)); 1760 50));
1661 timer.emplace(scopedUsCounterCPU); 1761 timer.emplace(scopedUsCounterCPU);
1662 } 1762 }
1663 1763
1664 IntRect sourceRect(destRect); 1764 IntRect sourceRect(destRect);
1665 sourceRect.move(-destOffset); 1765 sourceRect.move(-destOffset);
1666 1766
1667 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, 1767 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage,
1668 UntransformedUnclippedFill); 1768 UntransformedUnclippedFill);
1669 1769
1670 buffer->putByteArray(Unmultiplied, data->data()->data(), 1770 if (RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
1671 IntSize(data->width(), data->height()), sourceRect, 1771 RuntimeEnabledFeatures::colorCorrectRenderingEnabled()) {
1672 IntPoint(destOffset)); 1772 unsigned dataLength = data->width() * data->height();
1673 1773 if (renderingContext()->pixelFormat() == kF16CanvasPixelFormat)
1774 dataLength *= 2;
1775 std::unique_ptr<uint8_t[]> convertedPixels(new uint8_t[4 * dataLength]);
1776 data->imageDataInCanvasColorSettings(renderingContext()->colorSpace(),
1777 renderingContext()->pixelFormat(),
1778 convertedPixels);
1779 buffer->putByteArray(Unmultiplied, convertedPixels.get(),
1780 IntSize(data->width(), data->height()), sourceRect,
1781 IntPoint(destOffset));
1782 } else {
1783 buffer->putByteArray(Unmultiplied, data->data()->data(),
1784 IntSize(data->width(), data->height()), sourceRect,
1785 IntPoint(destOffset));
1786 }
1674 didDraw(destRect); 1787 didDraw(destRect);
1675 } 1788 }
1676 1789
1677 void BaseRenderingContext2D::inflateStrokeRect(FloatRect& rect) const { 1790 void BaseRenderingContext2D::inflateStrokeRect(FloatRect& rect) const {
1678 // Fast approximation of the stroke's bounding rect. 1791 // Fast approximation of the stroke's bounding rect.
1679 // This yields a slightly oversized rect but is very fast 1792 // This yields a slightly oversized rect but is very fast
1680 // compared to Path::strokeBoundingRect(). 1793 // compared to Path::strokeBoundingRect().
1681 static const double root2 = sqrtf(2); 1794 static const double root2 = sqrtf(2);
1682 double delta = state().lineWidth() / 2; 1795 double delta = state().lineWidth() / 2;
1683 if (state().getLineJoin() == MiterJoin) 1796 if (state().getLineJoin() == MiterJoin)
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
2014 ExpensiveCanvasHeuristicParameters::ShadowFixedCost[index] * 2127 ExpensiveCanvasHeuristicParameters::ShadowFixedCost[index] *
2015 m_usageCounters.numBlurredShadows + 2128 m_usageCounters.numBlurredShadows +
2016 ExpensiveCanvasHeuristicParameters:: 2129 ExpensiveCanvasHeuristicParameters::
2017 ShadowVariableCostPerAreaTimesShadowBlurSquared[index] * 2130 ShadowVariableCostPerAreaTimesShadowBlurSquared[index] *
2018 m_usageCounters.boundingBoxAreaTimesShadowBlurSquared; 2131 m_usageCounters.boundingBoxAreaTimesShadowBlurSquared;
2019 2132
2020 return basicCostOfDrawCalls + fillTypeAdjustment + shadowAdjustment; 2133 return basicCostOfDrawCalls + fillTypeAdjustment + shadowAdjustment;
2021 } 2134 }
2022 2135
2023 } // namespace blink 2136 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698