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

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: rename to isPaintable() 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::isPaintable() const
221 {
222 if (!m_context)
223 return canCreateImageBuffer(size());
224 return buffer();
225 }
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 // FIXME: crbug.com/438240; there is a bug with the new CSS blending and com positing feature.
358 if (!paintsIntoCanvasBuffer() && !document().printing()) 375 if (!m_context)
359 return; 376 return;
360 m_context->paintRenderingResultsToCanvas(FrontBuffer); 377 if (!paintsIntoCanvasBuffer() && !document().printing())
361 } 378 return;
362 379
380 m_context->paintRenderingResultsToCanvas(FrontBuffer);
363 if (hasImageBuffer()) { 381 if (hasImageBuffer()) {
364 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy; 382 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy;
365 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator); 383 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator);
366 } else { 384 } else {
367 // When alpha is false, we should draw to opaque black. 385 // When alpha is false, we should draw to opaque black.
368 if (m_context && !m_context->hasAlpha()) 386 if (!m_context->hasAlpha())
369 context->fillRect(FloatRect(r), Color(0, 0, 0)); 387 context->fillRect(FloatRect(r), Color(0, 0, 0));
370 } 388 }
371 389
372 if (is3D()) 390 if (is3D())
373 toWebGLRenderingContext(m_context.get())->markLayerComposited(); 391 toWebGLRenderingContext(m_context.get())->markLayerComposited();
374 } 392 }
375 393
376 bool HTMLCanvasElement::is3D() const 394 bool HTMLCanvasElement::is3D() const
377 { 395 {
378 return m_context && m_context->is3d(); 396 return m_context && m_context->is3d();
(...skipping 24 matching lines...) Expand all
403 return lowercaseMimeType; 421 return lowercaseMimeType;
404 } 422 }
405 423
406 const AtomicString HTMLCanvasElement::imageSourceURL() const 424 const AtomicString HTMLCanvasElement::imageSourceURL() const
407 { 425 {
408 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); 426 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer));
409 } 427 }
410 428
411 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const 429 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const
412 { 430 {
413 if (m_size.isEmpty() || !canCreateImageBuffer(size())) 431 if (!canCreateImageBuffer(size()))
414 return String("data:,"); 432 return String("data:,");
415 433
416 String encodingMimeType = toEncodingMimeType(mimeType); 434 String encodingMimeType = toEncodingMimeType(mimeType);
417 if (!m_context) { 435 if (!m_context) {
418 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); 436 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size);
419 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si ze(), imageData->data()->data()), encodingMimeType, quality); 437 return ImageEncoder::toDataURL(ImageEncoder::RawImageBytes(imageData->si ze(), imageData->data()->data()), encodingMimeType, quality);
420 } 438 }
421 439
422 if (m_context->is3d()) { 440 if (m_context->is3d()) {
423 // Get non-premultiplied data because of inaccurate premultiplied alpha conversion of buffer()->toDataURL(). 441 // 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(); 566 return surface.release();
549 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released 567 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released
550 } 568 }
551 569
552 return surfaceFactory->createSurface(deviceSize, opacityMode); 570 return surfaceFactory->createSurface(deviceSize, opacityMode);
553 } 571 }
554 572
555 void HTMLCanvasElement::createImageBuffer() 573 void HTMLCanvasElement::createImageBuffer()
556 { 574 {
557 createImageBufferInternal(); 575 createImageBufferInternal();
558 if (m_didFailToCreateImageBuffer && m_context && m_context->is2d()) 576 if (m_didFailToCreateImageBuffer && m_context->is2d())
559 toCanvasRenderingContext2D(m_context.get())->loseContext(); 577 toCanvasRenderingContext2D(m_context.get())->loseContext();
560 } 578 }
561 579
562 void HTMLCanvasElement::createImageBufferInternal() 580 void HTMLCanvasElement::createImageBufferInternal()
563 { 581 {
564 ASSERT(!m_imageBuffer); 582 ASSERT(!m_imageBuffer);
565 ASSERT(!m_contextStateSaver); 583 ASSERT(!m_contextStateSaver);
566 584
567 m_didFailToCreateImageBuffer = true; 585 m_didFailToCreateImageBuffer = true;
568 m_imageBufferIsClear = true; 586 m_imageBufferIsClear = true;
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const 675 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
658 { 676 {
659 if (!hasImageBuffer()) 677 if (!hasImageBuffer())
660 return nullptr; 678 return nullptr;
661 679
662 return drawingContext(); 680 return drawingContext();
663 } 681 }
664 682
665 ImageBuffer* HTMLCanvasElement::buffer() const 683 ImageBuffer* HTMLCanvasElement::buffer() const
666 { 684 {
685 ASSERT(m_context);
667 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) 686 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer)
668 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); 687 const_cast<HTMLCanvasElement*>(this)->createImageBuffer();
669 return m_imageBuffer.get(); 688 return m_imageBuffer.get();
670 } 689 }
671 690
672 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() 691 void HTMLCanvasElement::ensureUnacceleratedImageBuffer()
673 { 692 {
693 ASSERT(m_context);
674 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) 694 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer)
675 return; 695 return;
676 discardImageBuffer(); 696 discardImageBuffer();
677 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque; 697 OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque;
678 m_imageBuffer = ImageBuffer::create(size(), opacityMode); 698 m_imageBuffer = ImageBuffer::create(size(), opacityMode);
679 m_didFailToCreateImageBuffer = !m_imageBuffer; 699 m_didFailToCreateImageBuffer = !m_imageBuffer;
680 } 700 }
681 701
682 Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const 702 PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffe r) const
683 { 703 {
704 if (!canCreateImageBuffer(size()))
705 return nullptr;
706 if (!m_context)
707 return createTransparentImage(size());
708
684 if (!m_copiedImage && buffer()) { 709 if (!m_copiedImage && buffer()) {
685 if (m_context && m_context->is3d()) 710 if (m_context && m_context->is3d())
686 m_context->paintRenderingResultsToCanvas(sourceBuffer); 711 m_context->paintRenderingResultsToCanvas(sourceBuffer);
687 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); 712 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
688 updateExternallyAllocatedMemory(); 713 updateExternallyAllocatedMemory();
689 } 714 }
690 return m_copiedImage.get(); 715 return m_copiedImage;
691 } 716 }
692 717
693 void HTMLCanvasElement::discardImageBuffer() 718 void HTMLCanvasElement::discardImageBuffer()
694 { 719 {
695 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer 720 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer
696 m_imageBuffer.clear(); 721 m_imageBuffer.clear();
697 resetDirtyRect(); 722 resetDirtyRect();
698 updateExternallyAllocatedMemory(); 723 updateExternallyAllocatedMemory();
699 } 724 }
700 725
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 HTMLElement::didMoveToNewDocument(oldDocument); 762 HTMLElement::didMoveToNewDocument(oldDocument);
738 } 763 }
739 764
740 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const 765 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const
741 { 766 {
742 if (!width() || !height()) { 767 if (!width() || !height()) {
743 *status = ZeroSizeCanvasSourceImageStatus; 768 *status = ZeroSizeCanvasSourceImageStatus;
744 return nullptr; 769 return nullptr;
745 } 770 }
746 771
747 if (!buffer()) { 772 if (!isPaintable()) {
748 *status = InvalidSourceImageStatus; 773 *status = InvalidSourceImageStatus;
749 return nullptr; 774 return nullptr;
750 } 775 }
751 776
752 if (m_context && m_context->is3d()) { 777 if (!m_context) {
778 *status = NormalSourceImageStatus;
779 return createTransparentImage(size());
780 }
781
782 if (m_context->is3d()) {
753 m_context->paintRenderingResultsToCanvas(BackBuffer); 783 m_context->paintRenderingResultsToCanvas(BackBuffer);
754 *status = ExternalSourceImageStatus; 784 *status = ExternalSourceImageStatus;
755 785
756 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) 786 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap)
757 return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled); 787 return buffer()->copyImage(DontCopyBackingStore, Unscaled);
758 } 788 }
759 789
760 RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); 790 RefPtr<SkImage> image = buffer()->newImageSnapshot();
761 if (image) { 791 if (image) {
762 *status = NormalSourceImageStatus; 792 *status = NormalSourceImageStatus;
763
764 return StaticBitmapImage::create(image.release()); 793 return StaticBitmapImage::create(image.release());
765 } 794 }
766 795
767
768 *status = InvalidSourceImageStatus; 796 *status = InvalidSourceImageStatus;
769
770 return nullptr; 797 return nullptr;
771 } 798 }
772 799
773 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const 800 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const
774 { 801 {
775 return !originClean(); 802 return !originClean();
776 } 803 }
777 804
778 FloatSize HTMLCanvasElement::sourceSize() const 805 FloatSize HTMLCanvasElement::sourceSize() const
779 { 806 {
780 return FloatSize(width(), height()); 807 return FloatSize(width(), height());
781 } 808 }
782 809
783 } 810 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698