| OLD | NEW |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 Loading... |
| 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 |
| OLD | NEW |