| Index: Source/core/html/HTMLCanvasElement.cpp
|
| diff --git a/Source/core/html/HTMLCanvasElement.cpp b/Source/core/html/HTMLCanvasElement.cpp
|
| index 398e2314071092d48ecda73f84c3e49c5c430842..2c11a5249288e29ee1344187a6629797c782939f 100644
|
| --- a/Source/core/html/HTMLCanvasElement.cpp
|
| +++ b/Source/core/html/HTMLCanvasElement.cpp
|
| @@ -46,6 +46,7 @@
|
| #include "core/rendering/RenderLayer.h"
|
| #include "platform/MIMETypeRegistry.h"
|
| #include "platform/RuntimeEnabledFeatures.h"
|
| +#include "platform/graphics/BitmapImage.h"
|
| #include "platform/graphics/Canvas2DImageBufferSurface.h"
|
| #include "platform/graphics/GraphicsContextStateSaver.h"
|
| #include "platform/graphics/RecordingImageBufferSurface.h"
|
| @@ -76,17 +77,26 @@ const int MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
|
| //In Skia, we will also limit width/height to 32767.
|
| const int MaxSkiaDim = 32767; // Maximum width/height in CSS pixels.
|
|
|
| -bool canCreateImageBuffer(const IntSize& deviceSize)
|
| +bool canCreateImageBuffer(const IntSize& size)
|
| {
|
| - if (deviceSize.width() * deviceSize.height() > MaxCanvasArea)
|
| + if (size.isEmpty())
|
| return false;
|
| - if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim)
|
| + if (size.width() * size.height() > MaxCanvasArea)
|
| return false;
|
| - if (!deviceSize.width() || !deviceSize.height())
|
| + if (size.width() > MaxSkiaDim || size.height() > MaxSkiaDim)
|
| return false;
|
| return true;
|
| }
|
|
|
| +PassRefPtr<Image> createTransparentImage(const IntSize& size)
|
| +{
|
| + ASSERT(canCreateImageBuffer(size));
|
| + SkBitmap bitmap;
|
| + bitmap.allocN32Pixels(size.width(), size.height());
|
| + bitmap.eraseColor(SK_ColorTRANSPARENT);
|
| + return BitmapImage::create(NativeImageSkia::create(bitmap));
|
| +}
|
| +
|
| } // namespace
|
|
|
| DEFINE_EMPTY_DESTRUCTOR_WILL_BE_REMOVED(CanvasObserver);
|
| @@ -207,6 +217,13 @@ CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, Canvas
|
| return nullptr;
|
| }
|
|
|
| +bool HTMLCanvasElement::isPaintable() const
|
| +{
|
| + if (!m_context)
|
| + return canCreateImageBuffer(size());
|
| + return buffer();
|
| +}
|
| +
|
| void HTMLCanvasElement::didDraw(const FloatRect& rect)
|
| {
|
| if (rect.isEmpty())
|
| @@ -354,18 +371,19 @@ bool HTMLCanvasElement::paintsIntoCanvasBuffer() const
|
|
|
| void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r)
|
| {
|
| - if (m_context) {
|
| - if (!paintsIntoCanvasBuffer() && !document().printing())
|
| - return;
|
| - m_context->paintRenderingResultsToCanvas(FrontBuffer);
|
| - }
|
| + // FIXME: crbug.com/438240; there is a bug with the new CSS blending and compositing feature.
|
| + if (!m_context)
|
| + return;
|
| + if (!paintsIntoCanvasBuffer() && !document().printing())
|
| + return;
|
|
|
| + m_context->paintRenderingResultsToCanvas(FrontBuffer);
|
| if (hasImageBuffer()) {
|
| CompositeOperator compositeOperator = !m_context || m_context->hasAlpha() ? CompositeSourceOver : CompositeCopy;
|
| context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeOperator);
|
| } else {
|
| // When alpha is false, we should draw to opaque black.
|
| - if (m_context && !m_context->hasAlpha())
|
| + if (!m_context->hasAlpha())
|
| context->fillRect(FloatRect(r), Color(0, 0, 0));
|
| }
|
|
|
| @@ -410,7 +428,7 @@ const AtomicString HTMLCanvasElement::imageSourceURL() const
|
|
|
| String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double* quality, SourceDrawingBuffer sourceBuffer) const
|
| {
|
| - if (m_size.isEmpty() || !canCreateImageBuffer(size()))
|
| + if (!canCreateImageBuffer(size()))
|
| return String("data:,");
|
|
|
| String encodingMimeType = toEncodingMimeType(mimeType);
|
| @@ -555,7 +573,7 @@ PassOwnPtr<ImageBufferSurface> HTMLCanvasElement::createImageBufferSurface(const
|
| void HTMLCanvasElement::createImageBuffer()
|
| {
|
| createImageBufferInternal();
|
| - if (m_didFailToCreateImageBuffer && m_context && m_context->is2d())
|
| + if (m_didFailToCreateImageBuffer && m_context->is2d())
|
| toCanvasRenderingContext2D(m_context.get())->loseContext();
|
| }
|
|
|
| @@ -664,6 +682,7 @@ GraphicsContext* HTMLCanvasElement::existingDrawingContext() const
|
|
|
| ImageBuffer* HTMLCanvasElement::buffer() const
|
| {
|
| + ASSERT(m_context);
|
| if (!hasImageBuffer() && !m_didFailToCreateImageBuffer)
|
| const_cast<HTMLCanvasElement*>(this)->createImageBuffer();
|
| return m_imageBuffer.get();
|
| @@ -671,23 +690,29 @@ ImageBuffer* HTMLCanvasElement::buffer() const
|
|
|
| void HTMLCanvasElement::ensureUnacceleratedImageBuffer()
|
| {
|
| + ASSERT(m_context);
|
| if ((hasImageBuffer() && !m_imageBuffer->isAccelerated()) || m_didFailToCreateImageBuffer)
|
| return;
|
| discardImageBuffer();
|
| - OpacityMode opacityMode = !m_context || m_context->hasAlpha() ? NonOpaque : Opaque;
|
| + OpacityMode opacityMode = m_context->hasAlpha() ? NonOpaque : Opaque;
|
| m_imageBuffer = ImageBuffer::create(size(), opacityMode);
|
| m_didFailToCreateImageBuffer = !m_imageBuffer;
|
| }
|
|
|
| -Image* HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const
|
| +PassRefPtr<Image> HTMLCanvasElement::copiedImage(SourceDrawingBuffer sourceBuffer) const
|
| {
|
| + if (!canCreateImageBuffer(size()))
|
| + return nullptr;
|
| + if (!m_context)
|
| + return createTransparentImage(size());
|
| +
|
| if (!m_copiedImage && buffer()) {
|
| if (m_context && m_context->is3d())
|
| m_context->paintRenderingResultsToCanvas(sourceBuffer);
|
| m_copiedImage = buffer()->copyImage(CopyBackingStore, Unscaled);
|
| updateExternallyAllocatedMemory();
|
| }
|
| - return m_copiedImage.get();
|
| + return m_copiedImage;
|
| }
|
|
|
| void HTMLCanvasElement::discardImageBuffer()
|
| @@ -744,29 +769,31 @@ PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod
|
| return nullptr;
|
| }
|
|
|
| - if (!buffer()) {
|
| + if (!isPaintable()) {
|
| *status = InvalidSourceImageStatus;
|
| return nullptr;
|
| }
|
|
|
| - if (m_context && m_context->is3d()) {
|
| + if (!m_context) {
|
| + *status = NormalSourceImageStatus;
|
| + return createTransparentImage(size());
|
| + }
|
| +
|
| + if (m_context->is3d()) {
|
| m_context->paintRenderingResultsToCanvas(BackBuffer);
|
| *status = ExternalSourceImageStatus;
|
|
|
| // can't create SkImage from WebGLImageBufferSurface (contains only SkBitmap)
|
| - return m_imageBuffer->copyImage(DontCopyBackingStore, Unscaled);
|
| + return buffer()->copyImage(DontCopyBackingStore, Unscaled);
|
| }
|
|
|
| - RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot();
|
| + RefPtr<SkImage> image = buffer()->newImageSnapshot();
|
| if (image) {
|
| *status = NormalSourceImageStatus;
|
| -
|
| return StaticBitmapImage::create(image.release());
|
| }
|
|
|
| -
|
| *status = InvalidSourceImageStatus;
|
| -
|
| return nullptr;
|
| }
|
|
|
|
|