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

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: Addressing comments 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 17 matching lines...) Expand all
28 #include "platform/graphics/Image.h" 28 #include "platform/graphics/Image.h"
29 #include "platform/graphics/ImageBuffer.h" 29 #include "platform/graphics/ImageBuffer.h"
30 #include "platform/graphics/StrokeData.h" 30 #include "platform/graphics/StrokeData.h"
31 #include "platform/graphics/paint/PaintCanvas.h" 31 #include "platform/graphics/paint/PaintCanvas.h"
32 #include "platform/graphics/paint/PaintFlags.h" 32 #include "platform/graphics/paint/PaintFlags.h"
33 #include "platform/graphics/skia/SkiaUtils.h" 33 #include "platform/graphics/skia/SkiaUtils.h"
34 34
35 namespace blink { 35 namespace blink {
36 36
37 BaseRenderingContext2D::BaseRenderingContext2D() 37 BaseRenderingContext2D::BaseRenderingContext2D()
38 : m_clipAntialiasing(NotAntiAliased) { 38 : m_clipAntialiasing(NotAntiAliased), m_isColorManaged(false) {
39 m_stateStack.push_back(CanvasRenderingContext2DState::create()); 39 m_stateStack.push_back(CanvasRenderingContext2DState::create());
40 m_isColorManaged =
41 RuntimeEnabledFeatures::experimentalCanvasFeaturesEnabled() &&
42 RuntimeEnabledFeatures::colorCorrectRenderingEnabled();
40 } 43 }
41 44
42 BaseRenderingContext2D::~BaseRenderingContext2D() {} 45 BaseRenderingContext2D::~BaseRenderingContext2D() {}
43 46
44 CanvasRenderingContext2DState& BaseRenderingContext2D::modifiableState() { 47 CanvasRenderingContext2DState& BaseRenderingContext2D::modifiableState() {
45 realizeSaves(); 48 realizeSaves();
46 return *m_stateStack.back(); 49 return *m_stateStack.back();
47 } 50 }
48 51
49 void BaseRenderingContext2D::realizeSaves() { 52 void BaseRenderingContext2D::realizeSaves() {
(...skipping 1439 matching lines...) Expand 10 before | Expand all | Expand 10 after
1489 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect); 1492 static_cast<SkRect>(canvasRect).roundOut(&canvasIRect);
1490 if (!canvasIRect.intersect(transformedClipBounds)) 1493 if (!canvasIRect.intersect(transformedClipBounds))
1491 return false; 1494 return false;
1492 1495
1493 if (dirtyRect) 1496 if (dirtyRect)
1494 *dirtyRect = canvasIRect; 1497 *dirtyRect = canvasIRect;
1495 1498
1496 return true; 1499 return true;
1497 } 1500 }
1498 1501
1502 bool BaseRenderingContext2D::colorSettingsAsImageDataColorSettings(
1503 ImageDataColorSettings& colorSettings) const {
1504 if (!m_isColorManaged)
1505 return false;
1506 colorSettings.setColorSpace(renderingContext()->colorSpaceAsString());
1507 switch (renderingContext()->pixelFormat()) {
1508 case kRGBA8CanvasPixelFormat:
1509 colorSettings.setStorageFormat(kUint8ClampedArrayStorageFormatName);
1510 break;
1511 case kF16CanvasPixelFormat:
1512 colorSettings.setStorageFormat(kFloat32ArrayStorageFormatName);
1513 break;
1514 case kRGB10A2CanvasPixelFormat:
1515 case kRGBA12CanvasPixelFormat:
1516 default:
1517 NOTREACHED();
1518 return false;
1519 }
1520 return true;
1521 }
1522
1499 ImageData* BaseRenderingContext2D::createImageData( 1523 ImageData* BaseRenderingContext2D::createImageData(
1500 ImageData* imageData, 1524 ImageData* imageData,
1501 ExceptionState& exceptionState) const { 1525 ExceptionState& exceptionState) const {
1502 ImageData* result = ImageData::create(imageData->size()); 1526 ImageData* result = nullptr;
1527 if (m_isColorManaged) {
1528 ImageDataColorSettings colorSettings;
1529 if (colorSettingsAsImageDataColorSettings(colorSettings))
1530 result = ImageData::create(imageData->size(), &colorSettings);
1531 } else {
1532 result = ImageData::create(imageData->size());
1533 }
1503 if (!result) 1534 if (!result)
1504 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1535 exceptionState.throwRangeError("Out of memory at ImageData creation");
1505 return result; 1536 return result;
1506 } 1537 }
1507 1538
1508 ImageData* BaseRenderingContext2D::createImageData( 1539 ImageData* BaseRenderingContext2D::createImageData(
1509 int sw, 1540 int sw,
1510 int sh, 1541 int sh,
1511 ExceptionState& exceptionState) const { 1542 ExceptionState& exceptionState) const {
1512 if (!sw || !sh) { 1543 if (!sw || !sh) {
1513 exceptionState.throwDOMException( 1544 exceptionState.throwDOMException(
1514 IndexSizeError, 1545 IndexSizeError,
1515 String::format("The source %s is 0.", sw ? "height" : "width")); 1546 String::format("The source %s is 0.", sw ? "height" : "width"));
1516 return nullptr; 1547 return nullptr;
1517 } 1548 }
1518 1549
1519 IntSize size(abs(sw), abs(sh)); 1550 IntSize size(abs(sw), abs(sh));
1520 1551 ImageData* result = nullptr;
1521 ImageData* result = ImageData::create(size); 1552 if (m_isColorManaged) {
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 validColorSettings = false;
1615 if (m_isColorManaged)
1616 validColorSettings = colorSettingsAsImageDataColorSettings(colorSettings);
1576 IntRect imageDataRect(sx, sy, sw, sh); 1617 IntRect imageDataRect(sx, sy, sw, sh);
1577 DVLOG(1) << sx << ", " << sy << ", " << sw << ", " << sh; 1618 DVLOG(1) << sx << ", " << sy << ", " << sw << ", " << sh;
1578 ImageBuffer* buffer = imageBuffer(); 1619 ImageBuffer* buffer = imageBuffer();
1579 if (!buffer || isContextLost()) { 1620 if (!buffer || isContextLost()) {
1580 ImageData* result = ImageData::create(imageDataRect.size()); 1621 ImageData* result = nullptr;
1622 if (validColorSettings)
1623 result = ImageData::create(imageDataRect.size(), &colorSettings);
1624 else
1625 result = ImageData::create(imageDataRect.size());
1581 if (!result) 1626 if (!result)
1582 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1627 exceptionState.throwRangeError("Out of memory at ImageData creation");
1583 return result; 1628 return result;
1584 } 1629 }
1585 1630
1586 WTF::ArrayBufferContents contents; 1631 WTF::ArrayBufferContents contents;
1587 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents)) { 1632 if (!buffer->getImageData(Unmultiplied, imageDataRect, contents)) {
1588 exceptionState.throwRangeError("Out of memory at ImageData creation"); 1633 exceptionState.throwRangeError("Out of memory at ImageData creation");
1589 return nullptr; 1634 return nullptr;
1590 } 1635 }
1591 1636
1592 DOMArrayBuffer* arrayBuffer = DOMArrayBuffer::create(contents); 1637 DOMArrayBuffer* arrayBuffer = nullptr;
1638 DOMArrayBufferView* arrayBufferView = nullptr;
1639 DOMFloat32Array* dataArray = nullptr;
1640
1641 if (m_isColorManaged) {
1642 ImageDataStorageFormat storageFormat =
1643 ImageData::imageDataStorageFormat(colorSettings.storageFormat());
1644 switch (storageFormat) {
1645 case kUint8ClampedArrayStorageFormat:
1646 arrayBuffer = DOMArrayBuffer::create(contents);
1647 return ImageData::create(
1648 imageDataRect.size(),
1649 DOMUint8ClampedArray::create(arrayBuffer, 0,
1650 arrayBuffer->byteLength()));
1651 break;
1652 case kUint16ArrayStorageFormat:
1653 NOTREACHED();
1654 break;
1655 case kFloat32ArrayStorageFormat:
1656 arrayBufferView = ImageData::
1657 convertPixelsFromCanvasPixelFormatToImageDataStorageFormat(
1658 contents, renderingContext()->pixelFormat(), storageFormat);
1659 dataArray = const_cast<DOMFloat32Array*>(
1660 static_cast<const DOMFloat32Array*>(arrayBufferView));
1661 return ImageData::create(imageDataRect.size(), arrayBufferView,
1662 &colorSettings);
1663 default:
1664 NOTREACHED();
1665 }
1666 return nullptr;
1667 }
1668
1669 arrayBuffer = DOMArrayBuffer::create(contents);
1593 return ImageData::create( 1670 return ImageData::create(
1594 imageDataRect.size(), 1671 imageDataRect.size(),
1595 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength())); 1672 DOMUint8ClampedArray::create(arrayBuffer, 0, arrayBuffer->byteLength()));
1596 } 1673 }
1597 1674
1598 void BaseRenderingContext2D::putImageData(ImageData* data, 1675 void BaseRenderingContext2D::putImageData(ImageData* data,
1599 int dx, 1676 int dx,
1600 int dy, 1677 int dy,
1601 ExceptionState& exceptionState) { 1678 ExceptionState& exceptionState) {
1602 putImageData(data, dx, dy, 0, 0, data->width(), data->height(), 1679 putImageData(data, dx, dy, 0, 0, data->width(), data->height(),
1603 exceptionState); 1680 exceptionState);
1604 } 1681 }
1605 1682
1606 void BaseRenderingContext2D::putImageData(ImageData* data, 1683 void BaseRenderingContext2D::putImageData(ImageData* data,
1607 int dx, 1684 int dx,
1608 int dy, 1685 int dy,
1609 int dirtyX, 1686 int dirtyX,
1610 int dirtyY, 1687 int dirtyY,
1611 int dirtyWidth, 1688 int dirtyWidth,
1612 int dirtyHeight, 1689 int dirtyHeight,
1613 ExceptionState& exceptionState) { 1690 ExceptionState& exceptionState) {
1614 m_usageCounters.numPutImageDataCalls++; 1691 m_usageCounters.numPutImageDataCalls++;
1615 m_usageCounters.areaPutImageDataCalls += dirtyWidth * dirtyHeight; 1692 m_usageCounters.areaPutImageDataCalls += dirtyWidth * dirtyHeight;
1616 if (data->data()->bufferBase()->isNeutered()) { 1693
1694 bool dataIsNeutered = false;
1695 if (m_isColorManaged) {
1696 dataIsNeutered =
1697 (data->dataUnion().isUint8ClampedArray() &&
1698 data->dataUnion()
1699 .getAsUint8ClampedArray()
1700 ->bufferBase()
1701 ->isNeutered()) ||
1702 (data->dataUnion().isUint16Array() &&
1703 data->dataUnion().getAsUint16Array()->bufferBase()->isNeutered()) ||
1704 (data->dataUnion().isFloat32Array() &&
1705 data->dataUnion().getAsFloat32Array()->bufferBase()->isNeutered());
1706 } else {
1707 dataIsNeutered = data->data()->bufferBase()->isNeutered();
1708 }
1709 if (dataIsNeutered) {
1617 exceptionState.throwDOMException(InvalidStateError, 1710 exceptionState.throwDOMException(InvalidStateError,
1618 "The source data has been neutered."); 1711 "The source data has been neutered.");
1619 return; 1712 return;
1620 } 1713 }
1714
1621 ImageBuffer* buffer = imageBuffer(); 1715 ImageBuffer* buffer = imageBuffer();
1622 if (!buffer) 1716 if (!buffer)
1623 return; 1717 return;
1624 1718
1625 if (dirtyWidth < 0) { 1719 if (dirtyWidth < 0) {
1626 dirtyX += dirtyWidth; 1720 dirtyX += dirtyWidth;
1627 dirtyWidth = -dirtyWidth; 1721 dirtyWidth = -dirtyWidth;
1628 } 1722 }
1629 1723
1630 if (dirtyHeight < 0) { 1724 if (dirtyHeight < 0) {
(...skipping 29 matching lines...) Expand all
1660 50)); 1754 50));
1661 timer.emplace(scopedUsCounterCPU); 1755 timer.emplace(scopedUsCounterCPU);
1662 } 1756 }
1663 1757
1664 IntRect sourceRect(destRect); 1758 IntRect sourceRect(destRect);
1665 sourceRect.move(-destOffset); 1759 sourceRect.move(-destOffset);
1666 1760
1667 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage, 1761 checkOverdraw(destRect, 0, CanvasRenderingContext2DState::NoImage,
1668 UntransformedUnclippedFill); 1762 UntransformedUnclippedFill);
1669 1763
1670 buffer->putByteArray(Unmultiplied, data->data()->data(), 1764 if (m_isColorManaged) {
1671 IntSize(data->width(), data->height()), sourceRect, 1765 unsigned dataLength = data->width() * data->height();
1672 IntPoint(destOffset)); 1766 if (renderingContext()->pixelFormat() == kF16CanvasPixelFormat)
1673 1767 dataLength *= 2;
1768 std::unique_ptr<uint8_t[]> convertedPixels(new uint8_t[4 * dataLength]);
1769 data->imageDataInCanvasColorSettings(renderingContext()->colorSpace(),
1770 renderingContext()->pixelFormat(),
1771 convertedPixels);
1772 buffer->putByteArray(Unmultiplied, convertedPixels.get(),
1773 IntSize(data->width(), data->height()), sourceRect,
1774 IntPoint(destOffset));
1775 } else {
1776 buffer->putByteArray(Unmultiplied, data->data()->data(),
1777 IntSize(data->width(), data->height()), sourceRect,
1778 IntPoint(destOffset));
1779 }
1674 didDraw(destRect); 1780 didDraw(destRect);
1675 } 1781 }
1676 1782
1677 void BaseRenderingContext2D::inflateStrokeRect(FloatRect& rect) const { 1783 void BaseRenderingContext2D::inflateStrokeRect(FloatRect& rect) const {
1678 // Fast approximation of the stroke's bounding rect. 1784 // Fast approximation of the stroke's bounding rect.
1679 // This yields a slightly oversized rect but is very fast 1785 // This yields a slightly oversized rect but is very fast
1680 // compared to Path::strokeBoundingRect(). 1786 // compared to Path::strokeBoundingRect().
1681 static const double root2 = sqrtf(2); 1787 static const double root2 = sqrtf(2);
1682 double delta = state().lineWidth() / 2; 1788 double delta = state().lineWidth() / 2;
1683 if (state().getLineJoin() == MiterJoin) 1789 if (state().getLineJoin() == MiterJoin)
(...skipping 330 matching lines...) Expand 10 before | Expand all | Expand 10 after
2014 ExpensiveCanvasHeuristicParameters::ShadowFixedCost[index] * 2120 ExpensiveCanvasHeuristicParameters::ShadowFixedCost[index] *
2015 m_usageCounters.numBlurredShadows + 2121 m_usageCounters.numBlurredShadows +
2016 ExpensiveCanvasHeuristicParameters:: 2122 ExpensiveCanvasHeuristicParameters::
2017 ShadowVariableCostPerAreaTimesShadowBlurSquared[index] * 2123 ShadowVariableCostPerAreaTimesShadowBlurSquared[index] *
2018 m_usageCounters.boundingBoxAreaTimesShadowBlurSquared; 2124 m_usageCounters.boundingBoxAreaTimesShadowBlurSquared;
2019 2125
2020 return basicCostOfDrawCalls + fillTypeAdjustment + shadowAdjustment; 2126 return basicCostOfDrawCalls + fillTypeAdjustment + shadowAdjustment;
2021 } 2127 }
2022 2128
2023 } // namespace blink 2129 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698