Chromium Code Reviews| Index: Source/core/html/HTMLCanvasElement.cpp |
| diff --git a/Source/core/html/HTMLCanvasElement.cpp b/Source/core/html/HTMLCanvasElement.cpp |
| index 398e2314071092d48ecda73f84c3e49c5c430842..f0a55c2d6bd2c72c300f632238879e19c2217c79 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::isDrawable() const |
|
Justin Novosad
2014/12/02 15:48:16
I think isPaintable would be more consistent with
|
| +{ |
| + if (!m_context) |
| + return canCreateImageBuffer(size()); |
| + return buffer(); |
| +} |
|
dshwang
2014/12/01 14:31:12
Introduce this class to replace buffer() in some c
|
| + |
| void HTMLCanvasElement::didDraw(const FloatRect& rect) |
| { |
| if (rect.isEmpty()) |
| @@ -354,18 +371,18 @@ bool HTMLCanvasElement::paintsIntoCanvasBuffer() const |
| void HTMLCanvasElement::paint(GraphicsContext* context, const LayoutRect& r) |
| { |
| - if (m_context) { |
| - if (!paintsIntoCanvasBuffer() && !document().printing()) |
| - return; |
| - m_context->paintRenderingResultsToCanvas(FrontBuffer); |
| - } |
| + if (!m_context) |
| + return; |
|
Justin Novosad
2014/12/02 15:48:16
I think this is going to be a problem problem with
|
| + 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 +427,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 +572,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 +681,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 +689,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 +768,31 @@ PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod |
| return nullptr; |
| } |
| - if (!buffer()) { |
| + if (!isDrawable()) { |
|
dshwang
2014/12/01 14:31:12
for example of using isDrawable()
|
| *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; |
| } |