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

Side by Side Diff: Source/core/html/HTMLCanvasElement.cpp

Issue 758493004: canvas: make a temporary buffer when a context doesn't exist. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Don't create temp imageBuffer again Created 6 years 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 /* 1 /*
2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Alp Toker <alp@atoker.com> 3 * Copyright (C) 2007 Alp Toker <alp@atoker.com>
4 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. 4 * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
5 * 5 *
6 * Redistribution and use in source and binary forms, with or without 6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions 7 * modification, are permitted provided that the following conditions
8 * are met: 8 * are met:
9 * 1. Redistributions of source code must retain the above copyright 9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 28 matching lines...) Expand all
39 #include "core/html/ImageData.h" 39 #include "core/html/ImageData.h"
40 #include "core/html/canvas/Canvas2DContextAttributes.h" 40 #include "core/html/canvas/Canvas2DContextAttributes.h"
41 #include "core/html/canvas/CanvasRenderingContext2D.h" 41 #include "core/html/canvas/CanvasRenderingContext2D.h"
42 #include "core/html/canvas/WebGLContextAttributes.h" 42 #include "core/html/canvas/WebGLContextAttributes.h"
43 #include "core/html/canvas/WebGLContextEvent.h" 43 #include "core/html/canvas/WebGLContextEvent.h"
44 #include "core/html/canvas/WebGLRenderingContext.h" 44 #include "core/html/canvas/WebGLRenderingContext.h"
45 #include "core/rendering/RenderHTMLCanvas.h" 45 #include "core/rendering/RenderHTMLCanvas.h"
46 #include "core/rendering/RenderLayer.h" 46 #include "core/rendering/RenderLayer.h"
47 #include "platform/MIMETypeRegistry.h" 47 #include "platform/MIMETypeRegistry.h"
48 #include "platform/RuntimeEnabledFeatures.h" 48 #include "platform/RuntimeEnabledFeatures.h"
49 #include "platform/graphics/BitmapImage.h"
49 #include "platform/graphics/Canvas2DImageBufferSurface.h" 50 #include "platform/graphics/Canvas2DImageBufferSurface.h"
50 #include "platform/graphics/GraphicsContextStateSaver.h" 51 #include "platform/graphics/GraphicsContextStateSaver.h"
51 #include "platform/graphics/RecordingImageBufferSurface.h" 52 #include "platform/graphics/RecordingImageBufferSurface.h"
52 #include "platform/graphics/StaticBitmapImage.h" 53 #include "platform/graphics/StaticBitmapImage.h"
53 #include "platform/graphics/UnacceleratedImageBufferSurface.h" 54 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
54 #include "platform/graphics/gpu/WebGLImageBufferSurface.h" 55 #include "platform/graphics/gpu/WebGLImageBufferSurface.h"
55 #include "platform/image-encoders/ImageEncoder.h" 56 #include "platform/image-encoders/ImageEncoder.h"
56 #include "platform/transforms/AffineTransform.h" 57 #include "platform/transforms/AffineTransform.h"
57 #include "public/platform/Platform.h" 58 #include "public/platform/Platform.h"
58 #include <math.h> 59 #include <math.h>
(...skipping 10 matching lines...) Expand all
69 const int DefaultHeight = 150; 70 const int DefaultHeight = 150;
70 71
71 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo re it 72 // Firefox limits width/height to 32767 pixels, but slows down dramatically befo re it
72 // reaches that limit. We limit by area instead, giving us larger maximum dimens ions, 73 // reaches that limit. We limit by area instead, giving us larger maximum dimens ions,
73 // in exchange for a smaller maximum canvas size. 74 // in exchange for a smaller maximum canvas size.
74 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels 75 const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
75 76
76 //In Skia, we will also limit width/height to 32767. 77 //In Skia, we will also limit width/height to 32767.
77 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels. 78 const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels.
78 79
79 bool canCreateImageBuffer(const IntSize& deviceSize) 80 bool canCreateImageBuffer(const IntSize& size)
80 { 81 {
81 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) 82 if (size.isEmpty())
82 return false; 83 return false;
83 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) 84 if (size.width() * size.height() > MaxCanvasArea)
84 return false; 85 return false;
85 if (!deviceSize.width() || !deviceSize.height()) 86 if (size.width() > MaxSkiaDim || size.height() > MaxSkiaDim)
86 return false; 87 return false;
87 return true; 88 return true;
88 } 89 }
89 90
91 PassRefPtr<Image> createTransparentImage(const IntSize& size)
92 {
93 ASSERT(canCreateImageBuffer(size));
94 SkBitmap bitmap;
95 bitmap.allocN32Pixels(size.width(), size.height());
96 bitmap.eraseColor(SK_ColorTRANSPARENT);
97 return BitmapImage::create(NativeImageSkia::create(bitmap));
98 }
99
90 } // namespace 100 } // namespace
91 101
92 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); 102 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver);
93 103
94 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) 104 inline HTMLCanvasElement::HTMLCanvasElement(Document& document)
95 : HTMLElement(canvasTag, document) 105 : HTMLElement(canvasTag, document)
96 , DocumentVisibilityObserver(document) 106 , DocumentVisibilityObserver(document)
97 , m_size(DefaultWidth, DefaultHeight) 107 , m_size(DefaultWidth, DefaultHeight)
98 , m_ignoreReset(false) 108 , m_ignoreReset(false)
99 , m_accelerationDisabled(false) 109 , m_accelerationDisabled(false)
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after
200 } else if (!m_context->is3d()) { 210 } else if (!m_context->is3d()) {
201 dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontext creationerror, false, true, "Canvas has an existing, non-WebGL context")); 211 dispatchEvent(WebGLContextEvent::create(EventTypeNames::webglcontext creationerror, false, true, "Canvas has an existing, non-WebGL context"));
202 return nullptr; 212 return nullptr;
203 } 213 }
204 return m_context.get(); 214 return m_context.get();
205 } 215 }
206 216
207 return nullptr; 217 return nullptr;
208 } 218 }
209 219
220 bool HTMLCanvasElement::isDrawable() const
Justin Novosad 2014/12/02 15:48:16 I think isPaintable would be more consistent with
221 {
222 if (!m_context)
223 return canCreateImageBuffer(size());
224 return buffer();
225 }
dshwang 2014/12/01 14:31:12 Introduce this class to replace buffer() in some c
226
210 void HTMLCanvasElement::didDraw(const FloatRect& rect) 227 void HTMLCanvasElement::didDraw(const FloatRect& rect)
211 { 228 {
212 if (rect.isEmpty()) 229 if (rect.isEmpty())
213 return; 230 return;
214 m_imageBufferIsClear = false; 231 m_imageBufferIsClear = false;
215 clearCopiedImage(); 232 clearCopiedImage();
216 if (m_dirtyRect.isEmpty()) 233 if (m_dirtyRect.isEmpty())
217 blink::Platform::current()->currentThread()->addTaskObserver(this); 234 blink::Platform::current()->currentThread()->addTaskObserver(this);
218 m_dirtyRect.unite(rect); 235 m_dirtyRect.unite(rect);
219 } 236 }
(...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 364
348 if (renderBox() && renderBox()->hasAcceleratedCompositing()) 365 if (renderBox() && renderBox()->hasAcceleratedCompositing())
349 return false; 366 return false;
350 367
351 return true; 368 return true;
352 } 369 }
353 370
354 371
355 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) 372 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r)
356 { 373 {
357 if (m_context) { 374 if (!m_context)
358 if (!paintsIntoCanvasBuffer() && !document().printing()) 375 return;
Justin Novosad 2014/12/02 15:48:16 I think this is going to be a problem problem with
359 return; 376 if (!paintsIntoCanvasBuffer() && !document().printing())
360 m_context->paintRenderingResultsToCanvas(FrontBuffer); 377 return;
361 }
362 378
379 m_context->paintRenderingResultsToCanvas(FrontBuffer);
363 if (hasImageBuffer()) { 380 if (hasImageBuffer()) {
364 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy; 381 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy;
365 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator); 382 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator);
366 } else { 383 } else {
367 // When alpha is false, we should draw to opaque black. 384 // When alpha is false, we should draw to opaque black.
368 if (m_context && !m_context->hasAlpha()) 385 if (!m_context->hasAlpha())
369 context->fillRect(FloatRect(r), Color(0, 0, 0)); 386 context->fillRect(FloatRect(r), Color(0, 0, 0));
370 } 387 }
371 388
372 if (is3D()) 389 if (is3D())
373 toWebGLRenderingContext(m_context.get())->markLayerComposited(); 390 toWebGLRenderingContext(m_context.get())->markLayerComposited();
374 } 391 }
375 392
376 bool HTMLCanvasElement::is3D() const 393 bool HTMLCanvasElement::is3D() const
377 { 394 {
378 return m_context && m_context->is3d(); 395 return m_context && m_context->is3d();
(...skipping 24 matching lines...) Expand all
403 return lowercaseMimeType; 420 return lowercaseMimeType;
404 } 421 }
405 422
406 const AtomicString HTMLCanvasElement::imageSourceURL() const 423 const AtomicString HTMLCanvasElement::imageSourceURL() const
407 { 424 {
408 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); 425 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer));
409 } 426 }
410 427
411 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const 428 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const
412 { 429 {
413 if (m_size.isEmpty() || !canCreateImageBuffer(size())) 430 if (!canCreateImageBuffer(size()))
414 return String("data:,"); 431 return String("data:,");
415 432
416 String encodingMimeType = toEncodingMimeType(mimeType); 433 String encodingMimeType = toEncodingMimeType(mimeType);
417 if (!m_context) { 434 if (!m_context) {
418 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); 435 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size);
419 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si ze(), imageData->data()->data()), encodingMimeType, quality); 436 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si ze(), imageData->data()->data()), encodingMimeType, quality);
420 } 437 }
421 438
422 if (m_context->is3d()) { 439 if (m_context->is3d()) {
423 // Get non-premultiplied data because of inaccurate premultiplied alpha conversion of buffer()->toDataURL(). 440 // Get non-premultiplied data because of inaccurate premultiplied alpha conversion of buffer()->toDataURL().
(...skipping 124 matching lines...) Expand 10 before | Expand all | Expand 10 after
548 return surface.release(); 565 return surface.release();
549 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released 566 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released
550 } 567 }
551 568
552 return surfaceFactory->createSurface(deviceSize, opacityMode); 569 return surfaceFactory->createSurface(deviceSize, opacityMode);
553 } 570 }
554 571
555 void HTMLCanvasElement::createImageBuffer() 572 void HTMLCanvasElement::createImageBuffer()
556 { 573 {
557 createImageBufferInternal(); 574 createImageBufferInternal();
558 if (m_didFailToCreateImageBuffer && m_context && m_context->is2d()) 575 if (m_didFailToCreateImageBuffer && m_context->is2d())
559 toCanvasRenderingContext2D(m_context.get())->loseContext(); 576 toCanvasRenderingContext2D(m_context.get())->loseContext();
560 } 577 }
561 578
562 void HTMLCanvasElement::createImageBufferInternal() 579 void HTMLCanvasElement::createImageBufferInternal()
563 { 580 {
564 ASSERT(!m_imageBuffer); 581 ASSERT(!m_imageBuffer);
565 ASSERT(!m_contextStateSaver); 582 ASSERT(!m_contextStateSaver);
566 583
567 m_didFailToCreateImageBuffer = true; 584 m_didFailToCreateImageBuffer = true;
568 m_imageBufferIsClear = true; 585 m_imageBufferIsClear = true;
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const 674 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
658 { 675 {
659 if (!hasImageBuffer()) 676 if (!hasImageBuffer())
660 return nullptr; 677 return nullptr;
661 678
662 return drawingContext(); 679 return drawingContext();
663 } 680 }
664 681
665 ImageBuffer* HTMLCanvasElement::buffer() const 682 ImageBuffer* HTMLCanvasElement::buffer() const
666 { 683 {
684 ASSERT(m_context);
667 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) 685 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer)
668 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); 686 const_cast<HTMLCanvasElement*>(this)->createImageBuffer();
669 return m_imageBuffer.get(); 687 return m_imageBuffer.get();
670 } 688 }
671 689
672 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() 690 void HTMLCanvasElement::ensureUnacceleratedImageBuffer()
673 { 691 {
692 ASSERT(m_context);
674 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) 693 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer)
675 return; 694 return;
676 discardImageBuffer(); 695 discardImageBuffer();
677 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque; 696 OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque;
678 m_imageBuffer = ImageBuffer::create(size(), opacityMode); 697 m_imageBuffer = ImageBuffer::create(size(), opacityMode);
679 m_didFailToCreateImageBuffer = !m_imageBuffer; 698 m_didFailToCreateImageBuffer = !m_imageBuffer;
680 } 699 }
681 700
682 Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const 701 PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffe r) const
683 { 702 {
703 if (!canCreateImageBuffer(size()))
704 return nullptr;
705 if (!m_context)
706 return createTransparentImage(size());
707
684 if (!m_copiedImage && buffer()) { 708 if (!m_copiedImage && buffer()) {
685 if (m_context && m_context->is3d()) 709 if (m_context && m_context->is3d())
686 m_context->paintRenderingResultsToCanvas(sourceBuffer); 710 m_context->paintRenderingResultsToCanvas(sourceBuffer);
687 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); 711 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
688 updateExternallyAllocatedMemory(); 712 updateExternallyAllocatedMemory();
689 } 713 }
690 return m_copiedImage.get(); 714 return m_copiedImage;
691 } 715 }
692 716
693 void HTMLCanvasElement::discardImageBuffer() 717 void HTMLCanvasElement::discardImageBuffer()
694 { 718 {
695 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer 719 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer
696 m_imageBuffer.clear(); 720 m_imageBuffer.clear();
697 resetDirtyRect(); 721 resetDirtyRect();
698 updateExternallyAllocatedMemory(); 722 updateExternallyAllocatedMemory();
699 } 723 }
700 724
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 HTMLElement::didMoveToNewDocument(oldDocument); 761 HTMLElement::didMoveToNewDocument(oldDocument);
738 } 762 }
739 763
740 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const 764 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const
741 { 765 {
742 if (!width() || !height()) { 766 if (!width() || !height()) {
743 *status = ZeroSizeCanvasSourceImageStatus; 767 *status = ZeroSizeCanvasSourceImageStatus;
744 return nullptr; 768 return nullptr;
745 } 769 }
746 770
747 if (!buffer()) { 771 if (!isDrawable()) {
dshwang 2014/12/01 14:31:12 for example of using isDrawable()
748 *status = InvalidSourceImageStatus; 772 *status = InvalidSourceImageStatus;
749 return nullptr; 773 return nullptr;
750 } 774 }
751 775
752 if (m_context && m_context->is3d()) { 776 if (!m_context) {
777 *status = NormalSourceImageStatus;
778 return createTransparentImage(size());
779 }
780
781 if (m_context->is3d()) {
753 m_context->paintRenderingResultsToCanvas(BackBuffer); 782 m_context->paintRenderingResultsToCanvas(BackBuffer);
754 *status = ExternalSourceImageStatus; 783 *status = ExternalSourceImageStatus;
755 784
756 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) 785 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap)
757 return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled); 786 return buffer()->copyImage(DontCopyBackingStore, Unscaled);
758 } 787 }
759 788
760 RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); 789 RefPtr<SkImage> image = buffer()->newImageSnapshot();
761 if (image) { 790 if (image) {
762 *status = NormalSourceImageStatus; 791 *status = NormalSourceImageStatus;
763
764 return StaticBitmapImage::create(image.release()); 792 return StaticBitmapImage::create(image.release());
765 } 793 }
766 794
767
768 *status = InvalidSourceImageStatus; 795 *status = InvalidSourceImageStatus;
769
770 return nullptr; 796 return nullptr;
771 } 797 }
772 798
773 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const 799 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const
774 { 800 {
775 return !originClean(); 801 return !originClean();
776 } 802 }
777 803
778 FloatSize HTMLCanvasElement::sourceSize() const 804 FloatSize HTMLCanvasElement::sourceSize() const
779 { 805 {
780 return FloatSize(width(), height()); 806 return FloatSize(width(), height());
781 } 807 }
782 808
783 } 809 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698