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

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: 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/ImageBuffer.h" 52 #include "platform/graphics/ImageBuffer.h"
52 #include "platform/graphics/RecordingImageBufferSurface.h" 53 #include "platform/graphics/RecordingImageBufferSurface.h"
53 #include "platform/graphics/StaticBitmapImage.h" 54 #include "platform/graphics/StaticBitmapImage.h"
54 #include "platform/graphics/UnacceleratedImageBufferSurface.h" 55 #include "platform/graphics/UnacceleratedImageBufferSurface.h"
55 #include "platform/graphics/gpu/WebGLImageBufferSurface.h" 56 #include "platform/graphics/gpu/WebGLImageBufferSurface.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 PassRefPtr<Image> createTransparentImage(const IntSize& size)
80 { 81 {
81 if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) 82 SkBitmap bitmap;
82 return false; 83 bitmap.allocN32Pixels(size.width(), size.height());
83 if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) 84 bitmap.eraseColor(SK_ColorTRANSPARENT);
84 return false; 85 return BitmapImage::create(NativeImageSkia::create(bitmap));
85 if (!deviceSize.width() || !deviceSize.height())
86 return false;
87 return true;
88 } 86 }
89 87
90 } // namespace 88 } // namespace
91 89
92 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver); 90 DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver);
93 91
94 inline HTMLCanvasElement::HTMLCanvasElement(Document& document) 92 inline HTMLCanvasElement::HTMLCanvasElement(Document& document)
95 : HTMLElement(canvasTag, document) 93 : HTMLElement(canvasTag, document)
96 , DocumentVisibilityObserver(document) 94 , DocumentVisibilityObserver(document)
97 , m_size(DefaultWidth, DefaultHeight) 95 , m_size(DefaultWidth, DefaultHeight)
(...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after
347 345
348 if (renderBox() && renderBox()->hasAcceleratedCompositing()) 346 if (renderBox() && renderBox()->hasAcceleratedCompositing())
349 return false; 347 return false;
350 348
351 return true; 349 return true;
352 } 350 }
353 351
354 352
355 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) 353 void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r)
356 { 354 {
357 if (m_context) { 355 if (!m_context)
358 if (!paintsIntoCanvasBuffer() && !document().printing()) 356 return;
359 return; 357 if (!paintsIntoCanvasBuffer() && !document().printing())
360 m_context->paintRenderingResultsToCanvas(FrontBuffer); 358 return;
359 if (!canCreateImageBuffer()) {
Justin Novosad 2014/11/27 00:49:31 I disagree with this part. We should not create an
dshwang 2014/11/27 15:12:11 Thank you for explaining. I rollback this code in
360 // When alpha is false, we should draw to opaque black.
361 if (!m_context->hasAlpha())
362 context->fillRect(FloatRect(r), Color(0, 0, 0));
363 return;
361 } 364 }
362 365
363 if (hasImageBuffer()) { 366 m_context->paintRenderingResultsToCanvas(FrontBuffer);
364 CompositeOperator compositeOperator = !m_context || m_context->hasAlpha( ) ? CompositeSourceOver : CompositeCopy; 367 CompositeOperator compositeOperator = m_context->hasAlpha() ? CompositeSourc eOver : CompositeCopy;
365 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeO perator); 368 context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeOpera tor);
366 } else {
367 // When alpha is false, we should draw to opaque black.
368 if (m_context && !m_context->hasAlpha())
369 context->fillRect(FloatRect(r), Color(0, 0, 0));
370 }
371 369
372 if (is3D()) 370 if (is3D())
373 toWebGLRenderingContext(m_context.get())->markLayerComposited(); 371 toWebGLRenderingContext(m_context.get())->markLayerComposited();
374 } 372 }
375 373
376 bool HTMLCanvasElement::is3D() const 374 bool HTMLCanvasElement::is3D() const
377 { 375 {
378 return m_context && m_context->is3d(); 376 return m_context && m_context->is3d();
379 } 377 }
380 378
(...skipping 22 matching lines...) Expand all
403 return lowercaseMimeType; 401 return lowercaseMimeType;
404 } 402 }
405 403
406 const AtomicString HTMLCanvasElement::imageSourceURL() const 404 const AtomicString HTMLCanvasElement::imageSourceURL() const
407 { 405 {
408 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer)); 406 return AtomicString(toDataURLInternal("image/png", 0, FrontBuffer));
409 } 407 }
410 408
411 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const 409 String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double * quality, SourceDrawingBuffer sourceBuffer) const
412 { 410 {
413 if (m_size.isEmpty() || !canCreateImageBuffer(size())) 411 if (!canCreateImageBuffer())
414 return String("data:,"); 412 return String("data:,");
415 413
416 String encodingMimeType = toEncodingMimeType(mimeType); 414 String encodingMimeType = toEncodingMimeType(mimeType);
417 if (!m_context) { 415 if (!m_context) {
418 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size); 416 RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(m_size);
419 return ImageDataToDataURL(ImageDataBuffer(imageData->size(), imageData-> data()), encodingMimeType, quality); 417 return ImageDataToDataURL(ImageDataBuffer(imageData->size(), imageData-> data()), encodingMimeType, quality);
420 } 418 }
421 419
422 if (m_context->is3d()) { 420 if (m_context->is3d()) {
423 // Get non-premultiplied data because of inaccurate premultiplied alpha conversion of buffer()->toDataURL(). 421 // 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(); 546 return surface.release();
549 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released 547 surfaceFactory = createSurfaceFactory(deviceSize, msaaSampleCount); // r ecreate because old previous one was released
550 } 548 }
551 549
552 return surfaceFactory->createSurface(deviceSize, opacityMode); 550 return surfaceFactory->createSurface(deviceSize, opacityMode);
553 } 551 }
554 552
555 void HTMLCanvasElement::createImageBuffer() 553 void HTMLCanvasElement::createImageBuffer()
556 { 554 {
557 createImageBufferInternal(); 555 createImageBufferInternal();
558 if (m_didFailToCreateImageBuffer && m_context && m_context->is2d()) 556 if (m_didFailToCreateImageBuffer && m_context->is2d())
559 toCanvasRenderingContext2D(m_context.get())->loseContext(); 557 toCanvasRenderingContext2D(m_context.get())->loseContext();
560 } 558 }
561 559
562 void HTMLCanvasElement::createImageBufferInternal() 560 void HTMLCanvasElement::createImageBufferInternal()
563 { 561 {
564 ASSERT(!m_imageBuffer); 562 ASSERT(!m_imageBuffer);
565 ASSERT(!m_contextStateSaver); 563 ASSERT(!m_contextStateSaver);
566 564
567 m_didFailToCreateImageBuffer = true; 565 m_didFailToCreateImageBuffer = true;
568 m_imageBufferIsClear = true; 566 m_imageBufferIsClear = true;
569 567
570 if (!canCreateImageBuffer(size())) 568 if (!canCreateImageBuffer())
571 return; 569 return;
572 570
573 int msaaSampleCount; 571 int msaaSampleCount;
574 OwnPtr<ImageBufferSurface> surface = createImageBufferSurface(size(), &msaaS ampleCount); 572 OwnPtr<ImageBufferSurface> surface = createImageBufferSurface(size(), &msaaS ampleCount);
575 if (!surface->isValid()) 573 if (!surface->isValid())
576 return; 574 return;
577 575
578 m_imageBuffer = ImageBuffer::create(surface.release()); 576 m_imageBuffer = ImageBuffer::create(surface.release());
579 m_imageBuffer->setClient(this); 577 m_imageBuffer->setClient(this);
580 578
(...skipping 21 matching lines...) Expand all
602 m_imageBuffer->context()->setStrokeThickness(1); 600 m_imageBuffer->context()->setStrokeThickness(1);
603 #if ENABLE(ASSERT) 601 #if ENABLE(ASSERT)
604 m_imageBuffer->context()->disableDestructionChecks(); // 2D canvas is allowe d to leave context in an unfinalized state. 602 m_imageBuffer->context()->disableDestructionChecks(); // 2D canvas is allowe d to leave context in an unfinalized state.
605 #endif 603 #endif
606 m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer- >context())); 604 m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer- >context()));
607 605
608 if (m_context) 606 if (m_context)
609 setNeedsCompositingUpdate(); 607 setNeedsCompositingUpdate();
610 } 608 }
611 609
610 bool HTMLCanvasElement::canCreateImageBuffer() const
611 {
612 if (m_size.isEmpty())
613 return false;
614 if (m_size.width() * m_size.height() > MaxCanvasArea)
615 return false;
616 if (m_size.width() > MaxSkiaDim || m_size.height() > MaxSkiaDim)
617 return false;
618 return true;
619 }
620
612 void HTMLCanvasElement::notifySurfaceInvalid() 621 void HTMLCanvasElement::notifySurfaceInvalid()
613 { 622 {
614 if (m_context && m_context->is2d()) { 623 if (m_context && m_context->is2d()) {
615 CanvasRenderingContext2D* context2d = toCanvasRenderingContext2D(m_conte xt.get()); 624 CanvasRenderingContext2D* context2d = toCanvasRenderingContext2D(m_conte xt.get());
616 context2d->loseContext(); 625 context2d->loseContext();
617 } 626 }
618 } 627 }
619 628
620 void HTMLCanvasElement::trace(Visitor* visitor) 629 void HTMLCanvasElement::trace(Visitor* visitor)
621 { 630 {
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
657 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const 666 GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
658 { 667 {
659 if (!hasImageBuffer()) 668 if (!hasImageBuffer())
660 return nullptr; 669 return nullptr;
661 670
662 return drawingContext(); 671 return drawingContext();
663 } 672 }
664 673
665 ImageBuffer* HTMLCanvasElement::buffer() const 674 ImageBuffer* HTMLCanvasElement::buffer() const
666 { 675 {
676 ASSERT(m_context);
dshwang 2014/11/26 21:36:54 It means that we can move imageBuffer to CanvasRen
667 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) 677 if (!hasImageBuffer() && !m_didFailToCreateImageBuffer)
668 const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); 678 const_cast<HTMLCanvasElement*>(this)->createImageBuffer();
669 return m_imageBuffer.get(); 679 return m_imageBuffer.get();
670 } 680 }
671 681
672 void HTMLCanvasElement::ensureUnacceleratedImageBuffer() 682 void HTMLCanvasElement::ensureUnacceleratedImageBuffer()
673 { 683 {
684 ASSERT(m_context);
674 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer) 685 if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCrea teImageBuffer)
675 return; 686 return;
676 discardImageBuffer(); 687 discardImageBuffer();
677 OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque; 688 OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque;
678 m_imageBuffer = ImageBuffer::create(size(), opacityMode); 689 m_imageBuffer = ImageBuffer::create(size(), opacityMode);
679 m_didFailToCreateImageBuffer = !m_imageBuffer; 690 m_didFailToCreateImageBuffer = !m_imageBuffer;
680 } 691 }
681 692
682 Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const 693 PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffe r) const
683 { 694 {
695 if (!canCreateImageBuffer())
696 return nullptr;
697 if (!m_context)
698 return createTransparentImage(size());
699
684 if (!m_copiedImage && buffer()) { 700 if (!m_copiedImage && buffer()) {
685 if (m_context && m_context->is3d()) 701 if (m_context && m_context->is3d())
686 m_context->paintRenderingResultsToCanvas(sourceBuffer); 702 m_context->paintRenderingResultsToCanvas(sourceBuffer);
687 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled); 703 m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
688 updateExternallyAllocatedMemory(); 704 updateExternallyAllocatedMemory();
689 } 705 }
690 return m_copiedImage.get(); 706 return m_copiedImage;
691 } 707 }
692 708
693 void HTMLCanvasElement::discardImageBuffer() 709 void HTMLCanvasElement::discardImageBuffer()
694 { 710 {
695 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer 711 m_contextStateSaver.clear(); // uses context owned by m_imageBuffer
696 m_imageBuffer.clear(); 712 m_imageBuffer.clear();
697 resetDirtyRect(); 713 resetDirtyRect();
698 updateExternallyAllocatedMemory(); 714 updateExternallyAllocatedMemory();
699 } 715 }
700 716
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
737 HTMLElement::didMoveToNewDocument(oldDocument); 753 HTMLElement::didMoveToNewDocument(oldDocument);
738 } 754 }
739 755
740 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const 756 PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod e, SourceImageStatus* status) const
741 { 757 {
742 if (!width() || !height()) { 758 if (!width() || !height()) {
743 *status = ZeroSizeCanvasSourceImageStatus; 759 *status = ZeroSizeCanvasSourceImageStatus;
744 return nullptr; 760 return nullptr;
745 } 761 }
746 762
747 if (!buffer()) { 763 if (!canCreateImageBuffer()) {
748 *status = InvalidSourceImageStatus; 764 *status = InvalidSourceImageStatus;
749 return nullptr; 765 return nullptr;
750 } 766 }
751 767
752 if (m_context && m_context->is3d()) { 768 if (!m_context) {
769 *status = NormalSourceImageStatus;
770 return createTransparentImage(size());
771 }
772
773 if (m_context->is3d()) {
753 m_context->paintRenderingResultsToCanvas(BackBuffer); 774 m_context->paintRenderingResultsToCanvas(BackBuffer);
754 *status = ExternalSourceImageStatus; 775 *status = ExternalSourceImageStatus;
755 776
756 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap) 777 // can't create SkImage from WebGLImageBufferSurface (contains only SkBi tmap)
757 return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled); 778 return buffer()->copyImage(DontCopyBackingStore, Unscaled);
Justin Novosad 2014/11/27 00:49:31 Here: not safe to assume buffer is non-null
dshwang 2014/11/27 15:12:11 Yes, true In next patch set, above "if statement"
758 } 779 }
759 780
760 RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); 781 RefPtr<SkImage> image = buffer()->newImageSnapshot();
Justin Novosad 2014/11/27 00:49:30 here too
761 if (image) { 782 if (image) {
762 *status = NormalSourceImageStatus; 783 *status = NormalSourceImageStatus;
763
764 return StaticBitmapImage::create(image.release()); 784 return StaticBitmapImage::create(image.release());
765 } 785 }
766 786
767
768 *status = InvalidSourceImageStatus; 787 *status = InvalidSourceImageStatus;
769
770 return nullptr; 788 return nullptr;
771 } 789 }
772 790
773 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const 791 bool HTMLCanvasElement::wouldTaintOrigin(SecurityOrigin*) const
774 { 792 {
775 return !originClean(); 793 return !originClean();
776 } 794 }
777 795
778 FloatSize HTMLCanvasElement::sourceSize() const 796 FloatSize HTMLCanvasElement::sourceSize() const
779 { 797 {
780 return FloatSize(width(), height()); 798 return FloatSize(width(), height());
781 } 799 }
782 800
783 } 801 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698