Changeset 251874 in webkit


Ignore:
Timestamp:
Oct 31, 2019 1:41:56 PM (4 years ago)
Author:
commit-queue@webkit.org
Message:

Move ImageBuffer-related functionality from HTMLCanvasElement to CanvasBase
https://bugs.webkit.org/show_bug.cgi?id=182503

Patch by Zan Dobersek <zdobersek@igalia.com> and Chris Lord <Chris Lord> on 2019-10-31
Reviewed by Ryosuke Niwa.

Move the ImageBuffer member variable, other related member variables and
majority of methods that operate on these from the HTMLCanvasElement
class up to the CanvasBase class. This will make it possible for the
OffscreenCanvas implementation to leverage the same code when using 2D
contexts for painting.

Most of the moved methods are public, while the setImageBuffer() method
is made protected so that it's still accessible from the inheriting
class.

Along with setImageBuffer(), the active pixel memory counter is moved
into the CanvasBase class. It's still using static storage, but is now
a member of the class with protected access. The storage has been made
atomic so as to allow its consistency to be maintained when accessed
from multiple threads (which may happen in the future).

The m_size member variable is also moved up into the CanvasBase class.
Constructor is changed so that the passed-in IntSize argument is used
to initialize it. Canvas implementations are still the owners of their
respective canvas contexts and are responsible for the destruction of
both the context and the ImageBuffer, in that order.

HTMLCanvasElement destructor still has to invoke
CanvasBase::notifyObserversCanvasDestroyed() since some CanvasObserver
derivatives perform virtual method calls on the CanvasBase object for
typecasting purposes in their canvasDestroyed() implementation.
Calling virtual methods on an object that's being destroyed is normally
discouraged and should be fixed separately, but it works as long as
invocations are done before the HTMLCanvasElement object is destroyed
completely (as has been the case so far).

CanvasRenderingContext2DBase is already changed in unwindStateStack()
to call CanvasBase::existingDrawingContext() and not downcast the
CanvasBase object to HTMLCanvasElement. This is done now due to
unwindStateStack() being called from the destructor, which is now
invoked from the CanvasBase destructor and not the HTMLCanvasElement
destructor, avoiding virtual method calls on the CanvasBase object as
it's being destroyed.

This patch doesn't address various methods using const qualifier and
then working around that by requiring member variables to be mutable.
This should be amended as much as possible in a separate patch.

No new tests -- no change in functionality, only refactoring.

  • html/CanvasBase.cpp:

(WebCore::CanvasBase::CanvasBase):
(WebCore::CanvasBase::~CanvasBase):
(WebCore::CanvasBase::drawingContext const):
(WebCore::CanvasBase::existingDrawingContext const):
(WebCore::CanvasBase::buffer const):
(WebCore::CanvasBase::baseTransform const):
(WebCore::CanvasBase::makeRenderingResultsAvailable):
(WebCore::CanvasBase::memoryCost const):
(WebCore::CanvasBase::externalMemoryCost const):
(WebCore::CanvasBase::callTracingActive const):
(WebCore::CanvasBase::setImageBuffer const):
(WebCore::CanvasBase::activePixelMemory):
(WebCore::CanvasBase::resetGraphicsContextState const):

  • html/CanvasBase.h:

(WebCore::CanvasBase::width const):
(WebCore::CanvasBase::height const):
(WebCore::CanvasBase::size const):
(WebCore::CanvasBase::setSize):
(WebCore::CanvasBase::hasCreatedImageBuffer const):
(WebCore::CanvasBase::createImageBuffer const):

  • html/CustomPaintCanvas.cpp:

(WebCore::CustomPaintCanvas::CustomPaintCanvas):
(WebCore::CustomPaintCanvas::~CustomPaintCanvas):

  • html/CustomPaintCanvas.h:
  • html/HTMLCanvasElement.cpp:

(WebCore::HTMLCanvasElement::HTMLCanvasElement):
(WebCore::HTMLCanvasElement::~HTMLCanvasElement):
(WebCore::HTMLCanvasElement::setSize):
(WebCore::HTMLCanvasElement::createContext2d):
(WebCore::HTMLCanvasElement::reset):
(WebCore::HTMLCanvasElement::setSurfaceSize):
(WebCore::HTMLCanvasElement::toDataURL):
(WebCore::HTMLCanvasElement::toBlob):
(WebCore::HTMLCanvasElement::createImageBuffer const):
(WebCore::HTMLCanvasElement::setImageBufferAndMarkDirty):

  • html/HTMLCanvasElement.h:
  • html/OffscreenCanvas.cpp:

(WebCore::OffscreenCanvas::OffscreenCanvas):
(WebCore::OffscreenCanvas::~OffscreenCanvas):
(WebCore::OffscreenCanvas::setWidth):
(WebCore::OffscreenCanvas::setHeight):
(WebCore::OffscreenCanvas::transferToImageBitmap):
(WebCore::OffscreenCanvas::createImageBuffer const):

  • html/OffscreenCanvas.h:
Location:
trunk/Source/WebCore
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r251871 r251874  
     12019-10-31  Zan Dobersek  <zdobersek@igalia.com>  and  Chris Lord  <clord@igalia.com>
     2
     3        Move ImageBuffer-related functionality from HTMLCanvasElement to CanvasBase
     4        https://bugs.webkit.org/show_bug.cgi?id=182503
     5
     6        Reviewed by Ryosuke Niwa.
     7
     8        Move the ImageBuffer member variable, other related member variables and
     9        majority of methods that operate on these from the HTMLCanvasElement
     10        class up to the CanvasBase class. This will make it possible for the
     11        OffscreenCanvas implementation to leverage the same code when using 2D
     12        contexts for painting.
     13
     14        Most of the moved methods are public, while the setImageBuffer() method
     15        is made protected so that it's still accessible from the inheriting
     16        class.
     17
     18        Along with setImageBuffer(), the active pixel memory counter is moved
     19        into the CanvasBase class. It's still using static storage, but is now
     20        a member of the class with protected access. The storage has been made
     21        atomic so as to allow its consistency to be maintained when accessed
     22        from multiple threads (which may happen in the future).
     23
     24        The m_size member variable is also moved up into the CanvasBase class.
     25        Constructor is changed so that the passed-in IntSize argument is used
     26        to initialize it. Canvas implementations are still the owners of their
     27        respective canvas contexts and are responsible for the destruction of
     28        both the context and the ImageBuffer, in that order.
     29
     30        HTMLCanvasElement destructor still has to invoke
     31        CanvasBase::notifyObserversCanvasDestroyed() since some CanvasObserver
     32        derivatives perform virtual method calls on the CanvasBase object for
     33        typecasting purposes in their canvasDestroyed() implementation.
     34        Calling virtual methods on an object that's being destroyed is normally
     35        discouraged and should be fixed separately, but it works as long as
     36        invocations are done before the HTMLCanvasElement object is destroyed
     37        completely (as has been the case so far).
     38
     39        CanvasRenderingContext2DBase is already changed in unwindStateStack()
     40        to call CanvasBase::existingDrawingContext() and not downcast the
     41        CanvasBase object to HTMLCanvasElement. This is done now due to
     42        unwindStateStack() being called from the destructor, which is now
     43        invoked from the CanvasBase destructor and not the HTMLCanvasElement
     44        destructor, avoiding virtual method calls on the CanvasBase object as
     45        it's being destroyed.
     46
     47        This patch doesn't address various methods using const qualifier and
     48        then working around that by requiring member variables to be mutable.
     49        This should be amended as much as possible in a separate patch.
     50
     51        No new tests -- no change in functionality, only refactoring.
     52
     53        * html/CanvasBase.cpp:
     54        (WebCore::CanvasBase::CanvasBase):
     55        (WebCore::CanvasBase::~CanvasBase):
     56        (WebCore::CanvasBase::drawingContext const):
     57        (WebCore::CanvasBase::existingDrawingContext const):
     58        (WebCore::CanvasBase::buffer const):
     59        (WebCore::CanvasBase::baseTransform const):
     60        (WebCore::CanvasBase::makeRenderingResultsAvailable):
     61        (WebCore::CanvasBase::memoryCost const):
     62        (WebCore::CanvasBase::externalMemoryCost const):
     63        (WebCore::CanvasBase::callTracingActive const):
     64        (WebCore::CanvasBase::setImageBuffer const):
     65        (WebCore::CanvasBase::activePixelMemory):
     66        (WebCore::CanvasBase::resetGraphicsContextState const):
     67        * html/CanvasBase.h:
     68        (WebCore::CanvasBase::width const):
     69        (WebCore::CanvasBase::height const):
     70        (WebCore::CanvasBase::size const):
     71        (WebCore::CanvasBase::setSize):
     72        (WebCore::CanvasBase::hasCreatedImageBuffer const):
     73        (WebCore::CanvasBase::createImageBuffer const):
     74        * html/CustomPaintCanvas.cpp:
     75        (WebCore::CustomPaintCanvas::CustomPaintCanvas):
     76        (WebCore::CustomPaintCanvas::~CustomPaintCanvas):
     77        * html/CustomPaintCanvas.h:
     78        * html/HTMLCanvasElement.cpp:
     79        (WebCore::HTMLCanvasElement::HTMLCanvasElement):
     80        (WebCore::HTMLCanvasElement::~HTMLCanvasElement):
     81        (WebCore::HTMLCanvasElement::setSize):
     82        (WebCore::HTMLCanvasElement::createContext2d):
     83        (WebCore::HTMLCanvasElement::reset):
     84        (WebCore::HTMLCanvasElement::setSurfaceSize):
     85        (WebCore::HTMLCanvasElement::toDataURL):
     86        (WebCore::HTMLCanvasElement::toBlob):
     87        (WebCore::HTMLCanvasElement::createImageBuffer const):
     88        (WebCore::HTMLCanvasElement::setImageBufferAndMarkDirty):
     89        * html/HTMLCanvasElement.h:
     90        * html/OffscreenCanvas.cpp:
     91        (WebCore::OffscreenCanvas::OffscreenCanvas):
     92        (WebCore::OffscreenCanvas::~OffscreenCanvas):
     93        (WebCore::OffscreenCanvas::setWidth):
     94        (WebCore::OffscreenCanvas::setHeight):
     95        (WebCore::OffscreenCanvas::transferToImageBitmap):
     96        (WebCore::OffscreenCanvas::createImageBuffer const):
     97        * html/OffscreenCanvas.h:
     98
    1992019-10-31  Devin Rousso  <drousso@apple.com>
    2100
  • trunk/Source/WebCore/html/CanvasBase.cpp

    r243820 r251874  
    3232#include "FloatRect.h"
    3333#include "InspectorInstrumentation.h"
     34#include <JavaScriptCore/JSCInlines.h>
     35#include <JavaScriptCore/JSLock.h>
     36#include <atomic>
    3437#include <wtf/Vector.h>
    3538
     39static std::atomic<size_t> s_activePixelMemory { 0 };
     40
    3641namespace WebCore {
    3742
    38 CanvasBase::CanvasBase()
     43#if USE(CG)
     44// FIXME: It seems strange that the default quality is not the one that is literally named "default".
     45// Should fix names to make this easier to understand, or write an excellent comment here explaining why not.
     46const InterpolationQuality defaultInterpolationQuality = InterpolationLow;
     47#else
     48const InterpolationQuality defaultInterpolationQuality = InterpolationDefault;
     49#endif
     50
     51CanvasBase::CanvasBase(IntSize size)
     52    : m_size(size)
    3953{
    4054}
     
    4256CanvasBase::~CanvasBase()
    4357{
    44     ASSERT(!m_context); // Should have been set to null by base class.
    4558    ASSERT(m_didNotifyObserversCanvasDestroyed);
    4659    ASSERT(m_observers.isEmpty());
    47 }
    48 
    49 CanvasRenderingContext* CanvasBase::renderingContext() const
    50 {
    51     return m_context.get();
     60    ASSERT(!m_imageBuffer);
     61}
     62
     63GraphicsContext* CanvasBase::drawingContext() const
     64{
     65    auto* context = renderingContext();
     66    if (context && !context->is2d())
     67        return nullptr;
     68
     69    return buffer() ? &m_imageBuffer->context() : nullptr;
     70}
     71
     72GraphicsContext* CanvasBase::existingDrawingContext() const
     73{
     74    if (!hasCreatedImageBuffer())
     75        return nullptr;
     76
     77    return drawingContext();
     78}
     79
     80ImageBuffer* CanvasBase::buffer() const
     81{
     82    if (!hasCreatedImageBuffer())
     83        createImageBuffer();
     84    return m_imageBuffer.get();
     85}
     86
     87AffineTransform CanvasBase::baseTransform() const
     88{
     89    ASSERT(hasCreatedImageBuffer());
     90    return m_imageBuffer->baseTransform();
     91}
     92
     93void CanvasBase::makeRenderingResultsAvailable()
     94{
     95    if (auto* context = renderingContext())
     96        context->paintRenderingResultsToCanvas();
     97}
     98
     99size_t CanvasBase::memoryCost() const
     100{
     101    // memoryCost() may be invoked concurrently from a GC thread, and we need to be careful
     102    // about what data we access here and how. We need to hold a lock to prevent m_imageBuffer
     103    // from being changed while we access it.
     104    auto locker = holdLock(m_imageBufferAssignmentLock);
     105    if (!m_imageBuffer)
     106        return 0;
     107    return m_imageBuffer->memoryCost();
     108}
     109
     110size_t CanvasBase::externalMemoryCost() const
     111{
     112    // externalMemoryCost() may be invoked concurrently from a GC thread, and we need to be careful
     113    // about what data we access here and how. We need to hold a lock to prevent m_imageBuffer
     114    // from being changed while we access it.
     115    auto locker = holdLock(m_imageBufferAssignmentLock);
     116    if (!m_imageBuffer)
     117        return 0;
     118    return m_imageBuffer->externalMemoryCost();
    52119}
    53120
     
    112179bool CanvasBase::callTracingActive() const
    113180{
    114     return m_context && m_context->callTracingActive();
    115 }
    116 
    117 }
     181    auto* context = renderingContext();
     182    return context && context->callTracingActive();
     183}
     184
     185void CanvasBase::setImageBuffer(std::unique_ptr<ImageBuffer>&& buffer) const
     186{
     187    {
     188        auto locker = holdLock(m_imageBufferAssignmentLock);
     189        m_contextStateSaver = nullptr;
     190        m_imageBuffer = WTFMove(buffer);
     191    }
     192
     193    if (m_imageBuffer && m_size != m_imageBuffer->internalSize())
     194        m_size = m_imageBuffer->internalSize();
     195
     196    size_t previousMemoryCost = m_imageBufferCost;
     197    m_imageBufferCost = memoryCost();
     198    s_activePixelMemory += m_imageBufferCost - previousMemoryCost;
     199
     200    auto* context = renderingContext();
     201    if (context && m_imageBuffer && previousMemoryCost != m_imageBufferCost)
     202        InspectorInstrumentation::didChangeCanvasMemory(*context);
     203
     204    if (!m_imageBuffer)
     205        return;
     206
     207    m_imageBuffer->context().setShadowsIgnoreTransforms(true);
     208    m_imageBuffer->context().setImageInterpolationQuality(defaultInterpolationQuality);
     209    m_imageBuffer->context().setStrokeThickness(1);
     210    m_contextStateSaver = makeUnique<GraphicsContextStateSaver>(m_imageBuffer->context());
     211
     212    JSC::JSLockHolder lock(scriptExecutionContext()->vm());
     213    scriptExecutionContext()->vm().heap.reportExtraMemoryAllocated(m_imageBufferCost);
     214}
     215
     216size_t CanvasBase::activePixelMemory()
     217{
     218    return s_activePixelMemory.load();
     219}
     220
     221void CanvasBase::resetGraphicsContextState() const
     222{
     223    if (m_contextStateSaver) {
     224        // Reset to the initial graphics context state.
     225        m_contextStateSaver->restore();
     226        m_contextStateSaver->save();
     227    }
     228}
     229
     230}
  • trunk/Source/WebCore/html/CanvasBase.h

    r243820 r251874  
    2626#pragma once
    2727
     28#include "IntSize.h"
    2829#include <wtf/HashSet.h>
    2930#include <wtf/TypeCasts.h>
     
    3637class Element;
    3738class GraphicsContext;
     39class GraphicsContextStateSaver;
    3840class Image;
    3941class ImageBuffer;
    40 class IntSize;
    4142class FloatRect;
    4243class ScriptExecutionContext;
     
    6566    virtual bool isCustomPaintCanvas() const { return false; }
    6667
    67     virtual unsigned width() const = 0;
    68     virtual unsigned height() const = 0;
    69     virtual const IntSize& size() const  = 0;
    70     virtual void setSize(const IntSize&) = 0;
     68    unsigned width() const { return m_size.width(); }
     69    unsigned height() const { return m_size.height(); }
     70    const IntSize& size() const { return m_size; }
     71
     72    ImageBuffer* buffer() const;
     73
     74    virtual AffineTransform baseTransform() const;
     75
     76    void makeRenderingResultsAvailable();
     77
     78    size_t memoryCost() const;
     79    size_t externalMemoryCost() const;
    7180
    7281    void setOriginClean() { m_originClean = true; }
     
    7786    ScriptExecutionContext* scriptExecutionContext() const { return canvasBaseScriptExecutionContext();  }
    7887
    79     CanvasRenderingContext* renderingContext() const;
     88    virtual CanvasRenderingContext* renderingContext() const = 0;
    8089
    8190    void addObserver(CanvasObserver&);
     
    8796    HashSet<Element*> cssCanvasClients() const;
    8897
    89     virtual GraphicsContext* drawingContext() const = 0;
    90     virtual GraphicsContext* existingDrawingContext() const = 0;
     98    virtual GraphicsContext* drawingContext() const;
     99    virtual GraphicsContext* existingDrawingContext() const;
    91100
    92     virtual void makeRenderingResultsAvailable() = 0;
    93101    virtual void didDraw(const FloatRect&) = 0;
    94102
    95     virtual AffineTransform baseTransform() const = 0;
    96103    virtual Image* copiedImage() const = 0;
    97 
    98104    bool callTracingActive() const;
    99105
    100106protected:
    101     CanvasBase();
     107    explicit CanvasBase(IntSize);
    102108
    103109    virtual ScriptExecutionContext* canvasBaseScriptExecutionContext() const = 0;
    104110
    105     std::unique_ptr<CanvasRenderingContext> m_context;
     111    virtual void setSize(const IntSize& size) { m_size = size; }
     112
     113    void setImageBuffer(std::unique_ptr<ImageBuffer>&&) const;
     114    virtual bool hasCreatedImageBuffer() const { return false; }
     115    static size_t activePixelMemory();
     116
     117    void resetGraphicsContextState() const;
    106118
    107119private:
     120    virtual void createImageBuffer() const { }
     121
     122    mutable IntSize m_size;
     123    mutable Lock m_imageBufferAssignmentLock;
     124    mutable std::unique_ptr<ImageBuffer> m_imageBuffer;
     125    mutable size_t m_imageBufferCost { 0 };
     126    mutable std::unique_ptr<GraphicsContextStateSaver> m_contextStateSaver;
     127
    108128    bool m_originClean { true };
    109129#ifndef NDEBUG
  • trunk/Source/WebCore/html/CustomPaintCanvas.cpp

    r243820 r251874  
    2929#if ENABLE(CSS_PAINTING_API)
    3030
     31#include "CanvasRenderingContext.h"
    3132#include "ImageBitmap.h"
    3233#include "PaintRenderingContext2D.h"
     
    4041
    4142CustomPaintCanvas::CustomPaintCanvas(ScriptExecutionContext& context, unsigned width, unsigned height)
    42     : ContextDestructionObserver(&context)
    43     , m_size(width, height)
     43    : CanvasBase(IntSize(width, height))
     44    , ContextDestructionObserver(&context)
    4445{
    4546}
     
    5051
    5152    m_context = nullptr; // Ensure this goes away before the ImageBuffer.
    52 }
    53 
    54 unsigned CustomPaintCanvas::width() const
    55 {
    56     return m_size.width();
    57 }
    58 
    59 void CustomPaintCanvas::setWidth(unsigned newWidth)
    60 {
    61     return m_size.setWidth(newWidth);
    62 }
    63 
    64 unsigned CustomPaintCanvas::height() const
    65 {
    66     return m_size.height();
    67 }
    68 
    69 void CustomPaintCanvas::setHeight(unsigned newHeight)
    70 {
    71     return m_size.setHeight(newHeight);
    72 }
    73 
    74 const IntSize& CustomPaintCanvas::size() const
    75 {
    76     return m_size;
    77 }
    78 
    79 void CustomPaintCanvas::setSize(const IntSize& newSize)
    80 {
    81     m_size = newSize;
     53    setImageBuffer(nullptr);
    8254}
    8355
     
    145117}
    146118
    147 void CustomPaintCanvas::makeRenderingResultsAvailable()
    148 {
    149     if (m_context)
    150         m_context->paintRenderingResultsToCanvas();
    151 }
    152 
    153119}
    154120#endif
  • trunk/Source/WebCore/html/CustomPaintCanvas.h

    r250735 r251874  
    4242namespace WebCore {
    4343
     44class CanvasRenderingContext;
    4445class ImageBitmap;
    4546class PaintRenderingContext2D;
     
    5354    bool isCustomPaintCanvas() const final { return true; }
    5455
    55     unsigned width() const final;
    56     void setWidth(unsigned);
    57     unsigned height() const final;
    58     void setHeight(unsigned);
    59 
    60     const IntSize& size() const final;
    61     void setSize(const IntSize&) final;
    62 
    6356    ExceptionOr<RefPtr<PaintRenderingContext2D>> getContext();
    6457
     58    CanvasRenderingContext* renderingContext() const final { return m_context.get(); }
    6559    GraphicsContext* drawingContext() const final;
    6660    GraphicsContext* existingDrawingContext() const final;
    6761
    68     void makeRenderingResultsAvailable() final;
    6962    void didDraw(const FloatRect&) final { }
    7063
     
    8376    ScriptExecutionContext* canvasBaseScriptExecutionContext() const final { return ContextDestructionObserver::scriptExecutionContext(); }
    8477
     78    std::unique_ptr<CanvasRenderingContext> m_context;
    8579    mutable GraphicsContext* m_destinationGraphicsContext = nullptr;
    86     mutable IntSize m_size;
    8780    mutable std::unique_ptr<ImageBuffer> m_copiedBuffer;
    8881    mutable RefPtr<Image> m_copiedImage;
  • trunk/Source/WebCore/html/HTMLCanvasElement.cpp

    r251425 r251874  
    5656#include "StringAdaptors.h"
    5757#include <JavaScriptCore/JSCInlines.h>
    58 #include <JavaScriptCore/JSLock.h>
    5958#include <math.h>
    6059#include <wtf/IsoMallocInlines.h>
     
    105104#endif
    106105
    107 #if USE(CG)
    108 // FIXME: It seems strange that the default quality is not the one that is literally named "default".
    109 // Should fix names to make this easier to understand, or write an excellent comment here explaining why not.
    110 const InterpolationQuality defaultInterpolationQuality = InterpolationLow;
    111 #else
    112 const InterpolationQuality defaultInterpolationQuality = InterpolationDefault;
    113 #endif
    114 
    115 static size_t activePixelMemory = 0;
    116106static size_t maxActivePixelMemoryForTesting = 0;
    117107
    118108HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& document)
    119109    : HTMLElement(tagName, document)
    120     , m_size(defaultWidth, defaultHeight)
     110    , CanvasBase(IntSize(defaultWidth, defaultHeight))
    121111{
    122112    ASSERT(hasTagName(canvasTag));
     
    133123}
    134124
    135 static void removeFromActivePixelMemory(size_t pixelsReleased)
    136 {
    137     if (!pixelsReleased)
    138         return;
    139 
    140     if (pixelsReleased < activePixelMemory)
    141         activePixelMemory -= pixelsReleased;
    142     else
    143         activePixelMemory = 0;
    144 }
    145    
    146125HTMLCanvasElement::~HTMLCanvasElement()
    147126{
     127    // FIXME: This has to be called here because CSSCanvasValue::CanvasObserverProxy::canvasDestroyed()
     128    // downcasts the CanvasBase object to HTMLCanvasElement. That invokes virtual methods, which should be
     129    // avoided in destructors, but works as long as it's done before HTMLCanvasElement destructs completely.
    148130    notifyObserversCanvasDestroyed();
    149131
    150132    m_context = nullptr; // Ensure this goes away before the ImageBuffer.
    151 
    152     releaseImageBufferAndContext();
     133    setImageBuffer(nullptr);
    153134}
    154135
     
    192173    setAttributeWithoutSynchronization(widthAttr, AtomString::number(limitToOnlyHTMLNonNegative(value, defaultWidth)));
    193174    return { };
     175}
     176
     177void HTMLCanvasElement::setSize(const IntSize& newSize)
     178{
     179    if (newSize == size())
     180        return;
     181
     182    m_ignoreReset = true;
     183    setWidth(newSize.width());
     184    setHeight(newSize.height());
     185    m_ignoreReset = false;
     186    reset();
    194187}
    195188
     
    342335    // Make sure we don't use more pixel memory than the system can support.
    343336    size_t requestedPixelMemory = 4 * width() * height();
    344     if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
     337    if (activePixelMemory() + requestedPixelMemory > maxActivePixelMemory()) {
    345338        StringBuilder stringBuilder;
    346339        stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
     
    548541    int h = limitToOnlyHTMLNonNegative(attributeWithoutSynchronization(heightAttr), defaultHeight);
    549542
    550     if (m_contextStateSaver) {
    551         // Reset to the initial graphics context state.
    552         m_contextStateSaver->restore();
    553         m_contextStateSaver->save();
    554     }
    555 
     543    resetGraphicsContextState();
    556544    if (is<CanvasRenderingContext2D>(m_context.get()))
    557545        downcast<CanvasRenderingContext2D>(*m_context).reset();
     
    641629}
    642630
    643 void HTMLCanvasElement::makeRenderingResultsAvailable()
    644 {
    645     if (m_context)
    646         m_context->paintRenderingResultsToCanvas();
    647 }
    648 
    649631void HTMLCanvasElement::makePresentationCopy()
    650632{
     
    660642}
    661643
    662 void HTMLCanvasElement::releaseImageBufferAndContext()
    663 {
    664     m_contextStateSaver = nullptr;
     644void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
     645{
     646    CanvasBase::setSize(size);
     647    m_hasCreatedImageBuffer = false;
    665648    setImageBuffer(nullptr);
    666 }
    667    
    668 void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
    669 {
    670     m_size = size;
    671     m_hasCreatedImageBuffer = false;
    672     releaseImageBufferAndContext();
    673649    clearCopiedImage();
    674650}
     
    699675        return Exception { SecurityError };
    700676
    701     if (m_size.isEmpty() || !buffer())
     677    if (size().isEmpty() || !buffer())
    702678        return UncachedString { "data:,"_s };
    703679    if (RuntimeEnabledFeatures::sharedFeatures().webAPIStatisticsEnabled())
     
    728704        return Exception { SecurityError };
    729705
    730     if (m_size.isEmpty() || !buffer()) {
     706    if (size().isEmpty() || !buffer()) {
    731707        callback->scheduleCallback(context, nullptr);
    732708        return { };
     
    841817}
    842818
    843 size_t HTMLCanvasElement::memoryCost() const
    844 {
    845     // memoryCost() may be invoked concurrently from a GC thread, and we need to be careful
    846     // about what data we access here and how. We need to hold a lock to prevent m_imageBuffer
    847     // from being changed while we access it.
    848     auto locker = holdLock(m_imageBufferAssignmentLock);
    849     if (!m_imageBuffer)
    850         return 0;
    851     return m_imageBuffer->memoryCost();
    852 }
    853 
    854 size_t HTMLCanvasElement::externalMemoryCost() const
    855 {
    856     // externalMemoryCost() may be invoked concurrently from a GC thread, and we need to be careful
    857     // about what data we access here and how. We need to hold a lock to prevent m_imageBuffer
    858     // from being changed while we access it.
    859     auto locker = holdLock(m_imageBufferAssignmentLock);
    860     if (!m_imageBuffer)
    861         return 0;
    862     return m_imageBuffer->externalMemoryCost();
    863 }
    864 
    865819void HTMLCanvasElement::setUsesDisplayListDrawing(bool usesDisplayListDrawing)
    866820{
     
    903857void HTMLCanvasElement::createImageBuffer() const
    904858{
    905     ASSERT(!m_imageBuffer);
     859    ASSERT(!hasCreatedImageBuffer());
    906860
    907861    m_hasCreatedImageBuffer = true;
     
    920874    // Make sure we don't use more pixel memory than the system can support.
    921875    size_t requestedPixelMemory = 4 * width() * height();
    922     if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
     876    if (activePixelMemory() + requestedPixelMemory > maxActivePixelMemory()) {
    923877        StringBuilder stringBuilder;
    924878        stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
     
    936890    auto hostWindow = (document().view() && document().view()->root()) ? document().view()->root()->hostWindow() : nullptr;
    937891    setImageBuffer(ImageBuffer::create(size(), renderingMode, 1, ColorSpaceSRGB, hostWindow));
    938 }
    939 
    940 void HTMLCanvasElement::setImageBuffer(std::unique_ptr<ImageBuffer>&& buffer) const
    941 {
    942     size_t previousMemoryCost = memoryCost();
    943     removeFromActivePixelMemory(previousMemoryCost);
    944 
    945     {
    946         auto locker = holdLock(m_imageBufferAssignmentLock);
    947         m_contextStateSaver = nullptr;
    948         m_imageBuffer = WTFMove(buffer);
    949     }
    950 
    951     if (m_imageBuffer && m_size != m_imageBuffer->internalSize())
    952         m_size = m_imageBuffer->internalSize();
    953 
    954     size_t currentMemoryCost = memoryCost();
    955     activePixelMemory += currentMemoryCost;
    956 
    957     if (m_context && m_imageBuffer && previousMemoryCost != currentMemoryCost)
    958         InspectorInstrumentation::didChangeCanvasMemory(*m_context);
    959 
    960     if (!m_imageBuffer)
    961         return;
    962     m_imageBuffer->context().setShadowsIgnoreTransforms(true);
    963     m_imageBuffer->context().setImageInterpolationQuality(defaultInterpolationQuality);
    964     m_imageBuffer->context().setStrokeThickness(1);
    965     m_contextStateSaver = makeUnique<GraphicsContextStateSaver>(m_imageBuffer->context());
    966 
    967     JSC::JSLockHolder lock(HTMLElement::scriptExecutionContext()->vm());
    968     HTMLElement::scriptExecutionContext()->vm().heap.reportExtraMemoryAllocated(memoryCost());
    969892
    970893#if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
     
    980903    m_hasCreatedImageBuffer = true;
    981904    setImageBuffer(WTFMove(buffer));
    982     didDraw(FloatRect(FloatPoint(), m_size));
    983 }
    984 
    985 GraphicsContext* HTMLCanvasElement::drawingContext() const
    986 {
    987     if (m_context && !m_context->is2d())
    988         return nullptr;
    989 
    990     return buffer() ? &m_imageBuffer->context() : nullptr;
    991 }
    992 
    993 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
    994 {
    995     if (!m_hasCreatedImageBuffer)
    996         return nullptr;
    997 
    998     return drawingContext();
    999 }
    1000 
    1001 ImageBuffer* HTMLCanvasElement::buffer() const
    1002 {
    1003     if (!m_hasCreatedImageBuffer)
    1004         createImageBuffer();
    1005     return m_imageBuffer.get();
     905    didDraw(FloatRect(FloatPoint(), size()));
    1006906}
    1007907
     
    1036936}
    1037937
    1038 AffineTransform HTMLCanvasElement::baseTransform() const
    1039 {
    1040     ASSERT(m_hasCreatedImageBuffer);
    1041     return m_imageBuffer->baseTransform();
    1042 }
    1043 
    1044 }
     938}
  • trunk/Source/WebCore/html/HTMLCanvasElement.h

    r251425 r251874  
    3232#include "HTMLElement.h"
    3333#include "ImageBitmapRenderingContextSettings.h"
    34 #include "IntSize.h"
    3534#include <memory>
    3635#include <wtf/Forward.h>
     
    4342
    4443class BlobCallback;
     44class CanvasRenderingContext;
    4545class CanvasRenderingContext2D;
    4646class GraphicsContext;
    47 class GraphicsContextStateSaver;
    4847class Image;
    4948class ImageBuffer;
     
    6665    virtual ~HTMLCanvasElement();
    6766
    68     unsigned width() const final { return size().width(); }
    69     unsigned height() const final { return size().height(); }
    70 
    7167    WEBCORE_EXPORT ExceptionOr<void> setWidth(unsigned);
    7268    WEBCORE_EXPORT ExceptionOr<void> setHeight(unsigned);
    7369
    74     const IntSize& size() const final { return m_size; }
     70    void setSize(const IntSize& newSize) override;
    7571
    76     void setSize(const IntSize& newSize) override
    77     {
    78         if (newSize == size())
    79             return;
    80         m_ignoreReset = true;
    81         setWidth(newSize.width());
    82         setHeight(newSize.height());
    83         m_ignoreReset = false;
    84         reset();
    85     }
    86 
     72    CanvasRenderingContext* renderingContext() const final { return m_context.get(); }
    8773    ExceptionOr<Optional<RenderingContext>> getContext(JSC::JSGlobalObject&, const String& contextId, Vector<JSC::Strong<JSC::Unknown>>&& arguments);
    8874
     
    117103    void paint(GraphicsContext&, const LayoutRect&);
    118104
    119     GraphicsContext* drawingContext() const final;
    120     GraphicsContext* existingDrawingContext() const final;
    121 
    122105#if ENABLE(MEDIA_STREAM)
    123106    RefPtr<MediaSample> toMediaSample();
     
    125108#endif
    126109
    127     ImageBuffer* buffer() const;
    128110    Image* copiedImage() const final;
    129111    void clearCopiedImage();
     
    134116    SecurityOrigin* securityOrigin() const final;
    135117
    136     AffineTransform baseTransform() const final;
    137 
    138     void makeRenderingResultsAvailable() final;
    139     bool hasCreatedImageBuffer() const { return m_hasCreatedImageBuffer; }
    140 
    141118    bool shouldAccelerate(const IntSize&) const;
    142119
     
    145122    WEBCORE_EXPORT String displayListAsText(DisplayList::AsTextFlags) const;
    146123    WEBCORE_EXPORT String replayDisplayListAsText(DisplayList::AsTextFlags) const;
    147 
    148     size_t memoryCost() const;
    149     size_t externalMemoryCost() const;
    150124
    151125    // FIXME: Only some canvas rendering contexts need an ImageBuffer.
     
    168142    void reset();
    169143
    170     void createImageBuffer() const;
     144    void createImageBuffer() const final;
    171145    void clearImageBuffer() const;
    172146
     147    bool hasCreatedImageBuffer() const final { return m_hasCreatedImageBuffer; }
     148
    173149    void setSurfaceSize(const IntSize&);
    174     void setImageBuffer(std::unique_ptr<ImageBuffer>&&) const;
    175     void releaseImageBufferAndContext();
    176150
    177151    bool paintsIntoCanvasBuffer() const;
     
    185159
    186160    FloatRect m_dirtyRect;
    187     mutable IntSize m_size;
    188161
    189162    bool m_ignoreReset { false };
     
    192165    bool m_tracksDisplayListReplay { false };
    193166
    194     mutable Lock m_imageBufferAssignmentLock;
    195    
    196     // m_createdImageBuffer means we tried to malloc the buffer. We didn't necessarily get it.
     167    std::unique_ptr<CanvasRenderingContext> m_context;
     168
     169    // m_hasCreatedImageBuffer means we tried to malloc the buffer. We didn't necessarily get it.
    197170    mutable bool m_hasCreatedImageBuffer { false };
    198171    mutable bool m_didClearImageBuffer { false };
    199     mutable std::unique_ptr<ImageBuffer> m_imageBuffer;
    200     mutable std::unique_ptr<GraphicsContextStateSaver> m_contextStateSaver;
    201    
     172
    202173    mutable RefPtr<Image> m_presentedImage;
    203174    mutable RefPtr<Image> m_copiedImage; // FIXME: This is temporary for platforms that have to copy the image buffer to render (and for CSSCanvasValue).
  • trunk/Source/WebCore/html/OffscreenCanvas.cpp

    r251630 r251874  
    4545
    4646OffscreenCanvas::OffscreenCanvas(ScriptExecutionContext& context, unsigned width, unsigned height)
    47     : ContextDestructionObserver(&context)
    48     , m_size(width, height)
     47    : CanvasBase(IntSize(width, height))
     48    , ContextDestructionObserver(&context)
    4949{
    5050}
     
    5454    notifyObserversCanvasDestroyed();
    5555
    56     m_context = nullptr;
    57 }
    58 
    59 unsigned OffscreenCanvas::width() const
    60 {
    61     return m_size.width();
     56    m_context = nullptr; // Ensure this goes away before the ImageBuffer.
     57    setImageBuffer(nullptr);
    6258}
    6359
    6460void OffscreenCanvas::setWidth(unsigned newWidth)
    6561{
    66     return m_size.setWidth(newWidth);
    67 }
    68 
    69 unsigned OffscreenCanvas::height() const
    70 {
    71     return m_size.height();
     62    setSize(IntSize(newWidth, height()));
    7263}
    7364
    7465void OffscreenCanvas::setHeight(unsigned newHeight)
    7566{
    76     return m_size.setHeight(newHeight);
    77 }
    78 
    79 const IntSize& OffscreenCanvas::size() const
    80 {
    81     return m_size;
    82 }
    83 
    84 void OffscreenCanvas::setSize(const IntSize& newSize)
    85 {
    86     m_size = newSize;
     67    setSize(IntSize(width(), newHeight));
    8768}
    8869
     
    124105    // create a new bitmap and paint into it.
    125106
    126     auto imageBitmap = ImageBitmap::create(m_size);
     107    auto imageBitmap = ImageBitmap::create(size());
    127108    if (!imageBitmap->buffer())
    128109        return nullptr;
     
    147128}
    148129
     130void OffscreenCanvas::createImageBuffer() const
     131{
     132}
     133
    149134}
    150135
  • trunk/Source/WebCore/html/OffscreenCanvas.h

    r251630 r251874  
    4242namespace WebCore {
    4343
     44class CanvasRenderingContext;
    4445class ImageBitmap;
    4546class WebGLRenderingContext;
     
    6667    virtual ~OffscreenCanvas();
    6768
    68     unsigned width() const final;
    6969    void setWidth(unsigned);
    70     unsigned height() const final;
    7170    void setHeight(unsigned);
    7271
    73     const IntSize& size() const final;
    74     void setSize(const IntSize&) final;
     72    CanvasRenderingContext* renderingContext() const final { return m_context.get(); }
    7573
    7674#if ENABLE(WEBGL)
     
    8078    // void convertToBlob(ImageEncodeOptions options);
    8179
    82     GraphicsContext* drawingContext() const final { return nullptr; }
    83     GraphicsContext* existingDrawingContext() const final { return nullptr; }
    84 
    85     void makeRenderingResultsAvailable() final { }
    8680    void didDraw(const FloatRect&) final { }
    8781
    88     AffineTransform baseTransform() const final { return { }; }
    8982    Image* copiedImage() const final { return nullptr; }
    9083
     
    108101    void derefCanvasBase() final { deref(); }
    109102
    110     IntSize m_size;
     103    void createImageBuffer() const final;
     104
     105    std::unique_ptr<CanvasRenderingContext> m_context;
    111106};
    112107
Note: See TracChangeset for help on using the changeset viewer.