3a3c7411dc931a5be1956e7424ca21626fd315c8
[WebKit-https.git] / Source / WebCore / html / HTMLCanvasElement.cpp
1 /*
2  * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
3  * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4  * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
16  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
19  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
26  */
27
28 #include "config.h"
29 #include "HTMLCanvasElement.h"
30
31 #include "CanvasGradient.h"
32 #include "CanvasPattern.h"
33 #include "CanvasRenderingContext2D.h"
34 #include "Chrome.h"
35 #include "ChromeClient.h"
36 #include "Document.h"
37 #include "ExceptionCode.h"
38 #include "Frame.h"
39 #include "FrameLoaderClient.h"
40 #include "GeometryUtilities.h"
41 #include "GraphicsContext.h"
42 #include "HTMLNames.h"
43 #include "HTMLParserIdioms.h"
44 #include "ImageData.h"
45 #include "MIMETypeRegistry.h"
46 #include "Page.h"
47 #include "RenderHTMLCanvas.h"
48 #include "ScriptController.h"
49 #include "Settings.h"
50 #include <math.h>
51 #include <runtime/JSCInlines.h>
52 #include <runtime/JSLock.h>
53 #include <wtf/RAMSize.h>
54 #include <wtf/text/StringBuilder.h>
55
56 #if ENABLE(WEBGL)    
57 #include "WebGLContextAttributes.h"
58 #include "WebGLRenderingContextBase.h"
59 #endif
60
61 namespace WebCore {
62
63 using namespace HTMLNames;
64
65 // These values come from the WhatWG/W3C HTML spec.
66 const int defaultWidth = 300;
67 const int defaultHeight = 150;
68
69 // Firefox limits width/height to 32767 pixels, but slows down dramatically before it
70 // reaches that limit. We limit by area instead, giving us larger maximum dimensions,
71 // in exchange for a smaller maximum canvas size. The maximum canvas size is in device pixels.
72 #if PLATFORM(IOS)
73 const unsigned maxCanvasArea = 4096 * 4096;
74 #elif PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED < 101100
75 const unsigned maxCanvasArea = 8192 * 8192;
76 #else
77 const unsigned maxCanvasArea = 16384 * 16384;
78 #endif
79
80 #if USE(CG)
81 // FIXME: It seems strange that the default quality is not the one that is literally named "default".
82 // Should fix names to make this easier to understand, or write an excellent comment here explaining why not.
83 const InterpolationQuality defaultInterpolationQuality = InterpolationLow;
84 #else
85 const InterpolationQuality defaultInterpolationQuality = InterpolationDefault;
86 #endif
87
88 static size_t activePixelMemory = 0;
89
90 HTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document& document)
91     : HTMLElement(tagName, document)
92     , m_size(defaultWidth, defaultHeight)
93 {
94     ASSERT(hasTagName(canvasTag));
95 }
96
97 Ref<HTMLCanvasElement> HTMLCanvasElement::create(Document& document)
98 {
99     return adoptRef(*new HTMLCanvasElement(canvasTag, document));
100 }
101
102 Ref<HTMLCanvasElement> HTMLCanvasElement::create(const QualifiedName& tagName, Document& document)
103 {
104     return adoptRef(*new HTMLCanvasElement(tagName, document));
105 }
106
107 static void removeFromActivePixelMemory(size_t pixelsReleased)
108 {
109     if (!pixelsReleased)
110         return;
111
112     if (pixelsReleased < activePixelMemory)
113         activePixelMemory -= pixelsReleased;
114     else
115         activePixelMemory = 0;
116 }
117     
118 HTMLCanvasElement::~HTMLCanvasElement()
119 {
120     for (auto& observer : m_observers)
121         observer->canvasDestroyed(*this);
122
123     m_context = nullptr; // Ensure this goes away before the ImageBuffer.
124
125     releaseImageBufferAndContext();
126 }
127
128 void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
129 {
130     if (name == widthAttr || name == heightAttr)
131         reset();
132     HTMLElement::parseAttribute(name, value);
133 }
134
135 RenderPtr<RenderElement> HTMLCanvasElement::createElementRenderer(RenderStyle&& style, const RenderTreePosition& insertionPosition)
136 {
137     Frame* frame = document().frame();
138     if (frame && frame->script().canExecuteScripts(NotAboutToExecuteScript))
139         return createRenderer<RenderHTMLCanvas>(*this, WTFMove(style));
140     return HTMLElement::createElementRenderer(WTFMove(style), insertionPosition);
141 }
142
143 bool HTMLCanvasElement::canContainRangeEndPoint() const
144 {
145     return false;
146 }
147
148 bool HTMLCanvasElement::canStartSelection() const
149 {
150     return false;
151 }
152
153 void HTMLCanvasElement::addObserver(CanvasObserver& observer)
154 {
155     m_observers.add(&observer);
156 }
157
158 void HTMLCanvasElement::removeObserver(CanvasObserver& observer)
159 {
160     m_observers.remove(&observer);
161 }
162
163 void HTMLCanvasElement::setHeight(unsigned value)
164 {
165     setAttributeWithoutSynchronization(heightAttr, AtomicString::number(limitToOnlyHTMLNonNegative(value, defaultHeight)));
166 }
167
168 void HTMLCanvasElement::setWidth(unsigned value)
169 {
170     setAttributeWithoutSynchronization(widthAttr, AtomicString::number(limitToOnlyHTMLNonNegative(value, defaultWidth)));
171 }
172
173 #if ENABLE(WEBGL)
174 static bool requiresAcceleratedCompositingForWebGL()
175 {
176 #if PLATFORM(GTK) || PLATFORM(EFL)
177     return false;
178 #else
179     return true;
180 #endif
181
182 }
183 static bool shouldEnableWebGL(Settings* settings)
184 {
185     if (!settings)
186         return false;
187
188     if (!settings->webGLEnabled())
189         return false;
190
191     if (!requiresAcceleratedCompositingForWebGL())
192         return true;
193
194     return settings->acceleratedCompositingEnabled();
195 }
196 #endif
197
198 static inline size_t maxActivePixelMemory()
199 {
200     static size_t maxPixelMemory;
201     static std::once_flag onceFlag;
202     std::call_once(onceFlag, [] {
203         maxPixelMemory = std::max(ramSize() / 4, 2151 * MB);
204     });
205     return maxPixelMemory;
206 }
207
208 CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs)
209 {
210     if (is2dType(type)) {
211         if (m_context && !m_context->is2d())
212             return nullptr;
213         if (!m_context) {
214             bool usesDashboardCompatibilityMode = false;
215 #if ENABLE(DASHBOARD_SUPPORT)
216             if (Settings* settings = document().settings())
217                 usesDashboardCompatibilityMode = settings->usesDashboardBackwardCompatibilityMode();
218 #endif
219
220             // Make sure we don't use more pixel memory than the system can support.
221             size_t requestedPixelMemory = 4 * width() * height();
222             if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
223                 StringBuilder stringBuilder;
224                 stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
225                 stringBuilder.appendNumber(maxActivePixelMemory() / 1024 / 1024);
226                 stringBuilder.appendLiteral(" MB).");
227                 document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
228                 return nullptr;
229             }
230
231             m_context = std::make_unique<CanvasRenderingContext2D>(this, document().inQuirksMode(), usesDashboardCompatibilityMode);
232
233             downcast<CanvasRenderingContext2D>(*m_context).setUsesDisplayListDrawing(m_usesDisplayListDrawing);
234             downcast<CanvasRenderingContext2D>(*m_context).setTracksDisplayListReplay(m_tracksDisplayListReplay);
235
236 #if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
237             // Need to make sure a RenderLayer and compositing layer get created for the Canvas
238             invalidateStyleAndLayerComposition();
239 #endif
240         }
241         return m_context.get();
242     }
243 #if ENABLE(WEBGL)
244     if (shouldEnableWebGL(document().settings())) {
245
246         if (is3dType(type)) {
247             if (m_context && !m_context->is3d())
248                 return nullptr;
249             if (!m_context) {
250                 m_context = WebGLRenderingContextBase::create(this, static_cast<WebGLContextAttributes*>(attrs), type);
251                 if (m_context) {
252                     // Need to make sure a RenderLayer and compositing layer get created for the Canvas
253                     invalidateStyleAndLayerComposition();
254                 }
255             }
256             return m_context.get();
257         }
258     }
259 #else
260     UNUSED_PARAM(attrs);
261 #endif
262     return nullptr;
263 }
264
265 bool HTMLCanvasElement::is2dType(const String& type)
266 {
267     return type == "2d";
268 }
269
270 #if ENABLE(WEBGL)
271 bool HTMLCanvasElement::is3dType(const String& type)
272 {
273     // Retain support for the legacy "webkit-3d" name.
274     return type == "webgl" || type == "experimental-webgl"
275 #if ENABLE(WEBGL2)
276         || type == "webgl2"
277 #endif
278         || type == "webkit-3d";
279 }
280 #endif
281
282 void HTMLCanvasElement::didDraw(const FloatRect& rect)
283 {
284     clearCopiedImage();
285
286     FloatRect dirtyRect = rect;
287     if (RenderBox* ro = renderBox()) {
288         FloatRect destRect = ro->contentBoxRect();
289         // Inflate dirty rect to cover antialiasing on image buffers.
290         if (drawingContext() && drawingContext()->shouldAntialias())
291             dirtyRect.inflate(1);
292         FloatRect r = mapRect(dirtyRect, FloatRect(0, 0, size().width(), size().height()), destRect);
293         r.intersect(destRect);
294         if (r.isEmpty() || m_dirtyRect.contains(r))
295             return;
296
297         m_dirtyRect.unite(r);
298         ro->repaintRectangle(enclosingIntRect(m_dirtyRect));
299     }
300     notifyObserversCanvasChanged(dirtyRect);
301 }
302
303 void HTMLCanvasElement::notifyObserversCanvasChanged(const FloatRect& rect)
304 {
305     for (auto& observer : m_observers)
306         observer->canvasChanged(*this, rect);
307 }
308
309 void HTMLCanvasElement::reset()
310 {
311     if (m_ignoreReset)
312         return;
313
314     bool hadImageBuffer = hasCreatedImageBuffer();
315
316     int w = limitToOnlyHTMLNonNegative(attributeWithoutSynchronization(widthAttr), defaultWidth);
317     int h = limitToOnlyHTMLNonNegative(attributeWithoutSynchronization(heightAttr), defaultHeight);
318
319     if (m_contextStateSaver) {
320         // Reset to the initial graphics context state.
321         m_contextStateSaver->restore();
322         m_contextStateSaver->save();
323     }
324
325     if (m_context && m_context->is2d()) {
326         CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext2D*>(m_context.get());
327         context2D->reset();
328     }
329
330     IntSize oldSize = size();
331     IntSize newSize(w, h);
332     // If the size of an existing buffer matches, we can just clear it instead of reallocating.
333     // This optimization is only done for 2D canvases for now.
334     if (m_hasCreatedImageBuffer && oldSize == newSize && m_context && m_context->is2d()) {
335         if (!m_didClearImageBuffer)
336             clearImageBuffer();
337         return;
338     }
339
340     setSurfaceSize(newSize);
341
342 #if ENABLE(WEBGL)
343     if (is3D() && oldSize != size())
344         static_cast<WebGLRenderingContextBase*>(m_context.get())->reshape(width(), height());
345 #endif
346
347     auto renderer = this->renderer();
348     if (is<RenderHTMLCanvas>(renderer)) {
349         auto& canvasRenderer = downcast<RenderHTMLCanvas>(*renderer);
350         if (oldSize != size()) {
351             canvasRenderer.canvasSizeChanged();
352             if (canvasRenderer.hasAcceleratedCompositing())
353                 canvasRenderer.contentChanged(CanvasChanged);
354         }
355         if (hadImageBuffer)
356             canvasRenderer.repaint();
357     }
358
359     for (auto& observer : m_observers)
360         observer->canvasResized(*this);
361 }
362
363 bool HTMLCanvasElement::paintsIntoCanvasBuffer() const
364 {
365     ASSERT(m_context);
366 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
367     if (m_context->is2d())
368         return true;
369 #endif
370
371     if (!m_context->isAccelerated())
372         return true;
373
374     if (renderBox() && renderBox()->hasAcceleratedCompositing())
375         return false;
376
377     return true;
378 }
379
380
381 void HTMLCanvasElement::paint(GraphicsContext& context, const LayoutRect& r)
382 {
383     // Clear the dirty rect
384     m_dirtyRect = FloatRect();
385
386     if (context.paintingDisabled())
387         return;
388     
389     if (m_context) {
390         if (!paintsIntoCanvasBuffer() && !document().printing())
391             return;
392
393         m_context->paintRenderingResultsToCanvas();
394     }
395
396     if (hasCreatedImageBuffer()) {
397         ImageBuffer* imageBuffer = buffer();
398         if (imageBuffer) {
399             if (m_presentedImage) {
400                 ImageOrientationDescription orientationDescription;
401 #if ENABLE(CSS_IMAGE_ORIENTATION)
402                 orientationDescription.setImageOrientationEnum(renderer()->style().imageOrientation());
403 #endif 
404                 context.drawImage(*m_presentedImage, snappedIntRect(r), ImagePaintingOptions(orientationDescription));
405             } else
406                 context.drawImageBuffer(*imageBuffer, snappedIntRect(r));
407         }
408     }
409
410 #if ENABLE(WEBGL)    
411     if (is3D())
412         static_cast<WebGLRenderingContextBase*>(m_context.get())->markLayerComposited();
413 #endif
414 }
415
416 #if ENABLE(WEBGL)
417 bool HTMLCanvasElement::is3D() const
418 {
419     return m_context && m_context->is3d();
420 }
421 #endif
422
423 void HTMLCanvasElement::makeRenderingResultsAvailable()
424 {
425     if (m_context)
426         m_context->paintRenderingResultsToCanvas();
427 }
428
429 void HTMLCanvasElement::makePresentationCopy()
430 {
431     if (!m_presentedImage) {
432         // The buffer contains the last presented data, so save a copy of it.
433         m_presentedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
434     }
435 }
436
437 void HTMLCanvasElement::clearPresentationCopy()
438 {
439     m_presentedImage = nullptr;
440 }
441
442 void HTMLCanvasElement::releaseImageBufferAndContext()
443 {
444     m_contextStateSaver = nullptr;
445     setImageBuffer(nullptr);
446 }
447     
448 void HTMLCanvasElement::setSurfaceSize(const IntSize& size)
449 {
450     m_size = size;
451     m_hasCreatedImageBuffer = false;
452     releaseImageBufferAndContext();
453     clearCopiedImage();
454 }
455
456 String HTMLCanvasElement::toEncodingMimeType(const String& mimeType)
457 {
458     if (!MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
459         return ASCIILiteral("image/png");
460     return mimeType.convertToASCIILowercase();
461 }
462
463 String HTMLCanvasElement::toDataURL(const String& mimeType, const double* quality, ExceptionCode& ec)
464 {
465     if (!m_originClean) {
466         ec = SECURITY_ERR;
467         return String();
468     }
469
470     if (m_size.isEmpty() || !buffer())
471         return ASCIILiteral("data:,");
472
473     String encodingMIMEType = toEncodingMimeType(mimeType);
474
475 #if USE(CG)
476     // Try to get ImageData first, as that may avoid lossy conversions.
477     if (auto imageData = getImageData())
478         return ImageDataToDataURL(*imageData, encodingMIMEType, quality);
479 #endif
480
481     makeRenderingResultsAvailable();
482
483     return buffer()->toDataURL(encodingMIMEType, quality);
484 }
485
486 RefPtr<ImageData> HTMLCanvasElement::getImageData()
487 {
488 #if ENABLE(WEBGL)
489     if (!is3D())
490         return nullptr;
491
492     WebGLRenderingContextBase* ctx = static_cast<WebGLRenderingContextBase*>(m_context.get());
493
494     return ctx->paintRenderingResultsToImageData();
495 #else
496     return nullptr;
497 #endif
498 }
499
500 FloatRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const
501 {
502     FloatRect deviceRect(logicalRect);
503
504     float x = floorf(deviceRect.x());
505     float y = floorf(deviceRect.y());
506     float w = ceilf(deviceRect.maxX() - x);
507     float h = ceilf(deviceRect.maxY() - y);
508     deviceRect.setX(x);
509     deviceRect.setY(y);
510     deviceRect.setWidth(w);
511     deviceRect.setHeight(h);
512
513     return deviceRect;
514 }
515
516 FloatSize HTMLCanvasElement::convertLogicalToDevice(const FloatSize& logicalSize) const
517 {
518     float width = ceilf(logicalSize.width());
519     float height = ceilf(logicalSize.height());
520     return FloatSize(width, height);
521 }
522
523 FloatSize HTMLCanvasElement::convertDeviceToLogical(const FloatSize& deviceSize) const
524 {
525     float width = ceilf(deviceSize.width());
526     float height = ceilf(deviceSize.height());
527     return FloatSize(width, height);
528 }
529
530 SecurityOrigin* HTMLCanvasElement::securityOrigin() const
531 {
532     return document().securityOrigin();
533 }
534
535 bool HTMLCanvasElement::shouldAccelerate(const IntSize& size) const
536 {
537 #if USE(IOSURFACE_CANVAS_BACKING_STORE)
538     UNUSED_PARAM(size);
539     return document().settings() && document().settings()->canvasUsesAcceleratedDrawing();
540 #elif ENABLE(ACCELERATED_2D_CANVAS)
541     if (m_context && !m_context->is2d())
542         return false;
543
544     Settings* settings = document().settings();
545     if (!settings || !settings->accelerated2dCanvasEnabled())
546         return false;
547
548     // Do not use acceleration for small canvas.
549     if (size.width() * size.height() < settings->minimumAccelerated2dCanvasSize())
550         return false;
551
552     return true;
553 #else
554     UNUSED_PARAM(size);
555     return false;
556 #endif
557 }
558
559 size_t HTMLCanvasElement::memoryCost() const
560 {
561     if (!m_imageBuffer)
562         return 0;
563     return m_imageBuffer->memoryCost();
564 }
565
566 size_t HTMLCanvasElement::externalMemoryCost() const
567 {
568     if (!m_imageBuffer)
569         return 0;
570     return m_imageBuffer->externalMemoryCost();
571 }
572
573 void HTMLCanvasElement::setUsesDisplayListDrawing(bool usesDisplayListDrawing)
574 {
575     if (usesDisplayListDrawing == m_usesDisplayListDrawing)
576         return;
577     
578     m_usesDisplayListDrawing = usesDisplayListDrawing;
579
580     if (m_context && is<CanvasRenderingContext2D>(*m_context))
581         downcast<CanvasRenderingContext2D>(*m_context).setUsesDisplayListDrawing(m_usesDisplayListDrawing);
582 }
583
584 void HTMLCanvasElement::setTracksDisplayListReplay(bool tracksDisplayListReplay)
585 {
586     if (tracksDisplayListReplay == m_tracksDisplayListReplay)
587         return;
588
589     m_tracksDisplayListReplay = tracksDisplayListReplay;
590
591     if (m_context && is<CanvasRenderingContext2D>(*m_context))
592         downcast<CanvasRenderingContext2D>(*m_context).setTracksDisplayListReplay(m_tracksDisplayListReplay);
593 }
594
595 String HTMLCanvasElement::displayListAsText(DisplayList::AsTextFlags flags) const
596 {
597     if (m_context && is<CanvasRenderingContext2D>(*m_context))
598         return downcast<CanvasRenderingContext2D>(*m_context).displayListAsText(flags);
599
600     return String();
601 }
602
603 String HTMLCanvasElement::replayDisplayListAsText(DisplayList::AsTextFlags flags) const
604 {
605     if (m_context && is<CanvasRenderingContext2D>(*m_context))
606         return downcast<CanvasRenderingContext2D>(*m_context).replayDisplayListAsText(flags);
607
608     return String();
609 }
610
611 void HTMLCanvasElement::createImageBuffer() const
612 {
613     ASSERT(!m_imageBuffer);
614
615     m_hasCreatedImageBuffer = true;
616     m_didClearImageBuffer = true;
617
618     FloatSize logicalSize = size();
619     FloatSize deviceSize = convertLogicalToDevice(logicalSize);
620     if (!deviceSize.isExpressibleAsIntSize())
621         return;
622
623     if (deviceSize.width() * deviceSize.height() > maxCanvasArea) {
624         StringBuilder stringBuilder;
625         stringBuilder.appendLiteral("Canvas area exceeds the maximum limit (width * height > ");
626         stringBuilder.appendNumber(maxCanvasArea);
627         stringBuilder.appendLiteral(").");
628         document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
629         return;
630     }
631     
632     // Make sure we don't use more pixel memory than the system can support.
633     size_t requestedPixelMemory = 4 * width() * height();
634     if (activePixelMemory + requestedPixelMemory > maxActivePixelMemory()) {
635         StringBuilder stringBuilder;
636         stringBuilder.appendLiteral("Total canvas memory use exceeds the maximum limit (");
637         stringBuilder.appendNumber(maxActivePixelMemory() / 1024 / 1024);
638         stringBuilder.appendLiteral(" MB).");
639         document().addConsoleMessage(MessageSource::JS, MessageLevel::Warning, stringBuilder.toString());
640         return;
641     }
642
643     IntSize bufferSize(deviceSize.width(), deviceSize.height());
644     if (!bufferSize.width() || !bufferSize.height())
645         return;
646
647     RenderingMode renderingMode = shouldAccelerate(bufferSize) ? Accelerated : Unaccelerated;
648
649     setImageBuffer(ImageBuffer::create(size(), renderingMode));
650     if (!m_imageBuffer)
651         return;
652     m_imageBuffer->context().setShadowsIgnoreTransforms(true);
653     m_imageBuffer->context().setImageInterpolationQuality(defaultInterpolationQuality);
654     if (document().settings() && !document().settings()->antialiased2dCanvasEnabled())
655         m_imageBuffer->context().setShouldAntialias(false);
656     m_imageBuffer->context().setStrokeThickness(1);
657     m_contextStateSaver = std::make_unique<GraphicsContextStateSaver>(m_imageBuffer->context());
658
659     JSC::JSLockHolder lock(scriptExecutionContext()->vm());
660     scriptExecutionContext()->vm().heap.reportExtraMemoryAllocated(memoryCost());
661
662 #if USE(IOSURFACE_CANVAS_BACKING_STORE) || ENABLE(ACCELERATED_2D_CANVAS)
663     if (m_context && m_context->is2d())
664         // Recalculate compositing requirements if acceleration state changed.
665         const_cast<HTMLCanvasElement*>(this)->invalidateStyleAndLayerComposition();
666 #endif
667 }
668
669 void HTMLCanvasElement::setImageBuffer(std::unique_ptr<ImageBuffer> buffer) const
670 {
671     removeFromActivePixelMemory(memoryCost());
672
673     m_imageBuffer = WTFMove(buffer);
674
675     activePixelMemory += memoryCost();
676 }
677
678 GraphicsContext* HTMLCanvasElement::drawingContext() const
679 {
680     return buffer() ? &m_imageBuffer->context() : nullptr;
681 }
682
683 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
684 {
685     if (!m_hasCreatedImageBuffer)
686         return nullptr;
687
688     return drawingContext();
689 }
690
691 ImageBuffer* HTMLCanvasElement::buffer() const
692 {
693     if (!m_hasCreatedImageBuffer)
694         createImageBuffer();
695     return m_imageBuffer.get();
696 }
697
698 Image* HTMLCanvasElement::copiedImage() const
699 {
700     if (!m_copiedImage && buffer()) {
701         if (m_context)
702             m_context->paintRenderingResultsToCanvas();
703         m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
704     }
705     return m_copiedImage.get();
706 }
707
708 void HTMLCanvasElement::clearImageBuffer() const
709 {
710     ASSERT(m_hasCreatedImageBuffer);
711     ASSERT(!m_didClearImageBuffer);
712     ASSERT(m_context);
713
714     m_didClearImageBuffer = true;
715
716     if (m_context->is2d()) {
717         CanvasRenderingContext2D* context2D = static_cast<CanvasRenderingContext2D*>(m_context.get());
718         // No need to undo transforms/clip/etc. because we are called right after the context is reset.
719         context2D->clearRect(0, 0, width(), height());
720     }
721 }
722
723 void HTMLCanvasElement::clearCopiedImage()
724 {
725     m_copiedImage = nullptr;
726     m_didClearImageBuffer = false;
727 }
728
729 AffineTransform HTMLCanvasElement::baseTransform() const
730 {
731     ASSERT(m_hasCreatedImageBuffer);
732     FloatSize unscaledSize = size();
733     FloatSize deviceSize = convertLogicalToDevice(unscaledSize);
734     IntSize size(deviceSize.width(), deviceSize.height());
735     AffineTransform transform;
736     if (size.width() && size.height())
737         transform.scaleNonUniform(size.width() / unscaledSize.width(), size.height() / unscaledSize.height());
738     return m_imageBuffer->baseTransform() * transform;
739 }
740
741 }