Index: Source/core/html/HTMLCanvasElement.cpp |
diff --git a/Source/core/html/HTMLCanvasElement.cpp b/Source/core/html/HTMLCanvasElement.cpp |
index 7bc778110214f91b55eb0f5bd5b810742368f521..e8de8040d614344c71647283aae9ae7321b58ae4 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/ImageBuffer.h" |
@@ -76,15 +77,12 @@ 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) |
+PassRefPtr<Image> createTransparentImage(const IntSize& size) |
{ |
- if (deviceSize.width() * deviceSize.height() > MaxCanvasArea) |
- return false; |
- if (deviceSize.width() > MaxSkiaDim || deviceSize.height() > MaxSkiaDim) |
- return false; |
- if (!deviceSize.width() || !deviceSize.height()) |
- return false; |
- return true; |
+ SkBitmap bitmap; |
+ bitmap.allocN32Pixels(size.width(), size.height()); |
+ bitmap.eraseColor(SK_ColorTRANSPARENT); |
+ return BitmapImage::create(NativeImageSkia::create(bitmap)); |
} |
} // namespace |
@@ -354,21 +352,21 @@ 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 (hasImageBuffer()) { |
- CompositeOperator compositeOperator = !m_context || m_context->hasAlpha() ? CompositeSourceOver : CompositeCopy; |
- context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeOperator); |
- } else { |
+ if (!m_context) |
+ return; |
+ if (!paintsIntoCanvasBuffer() && !document().printing()) |
+ return; |
+ 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
|
// 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)); |
+ return; |
} |
+ m_context->paintRenderingResultsToCanvas(FrontBuffer); |
+ CompositeOperator compositeOperator = m_context->hasAlpha() ? CompositeSourceOver : CompositeCopy; |
+ context->drawImageBuffer(buffer(), pixelSnappedIntRect(r), 0, compositeOperator); |
+ |
if (is3D()) |
toWebGLRenderingContext(m_context.get())->markLayerComposited(); |
} |
@@ -410,7 +408,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()) |
return String("data:,"); |
String encodingMimeType = toEncodingMimeType(mimeType); |
@@ -555,7 +553,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(); |
} |
@@ -567,7 +565,7 @@ void HTMLCanvasElement::createImageBufferInternal() |
m_didFailToCreateImageBuffer = true; |
m_imageBufferIsClear = true; |
- if (!canCreateImageBuffer(size())) |
+ if (!canCreateImageBuffer()) |
return; |
int msaaSampleCount; |
@@ -609,6 +607,17 @@ void HTMLCanvasElement::createImageBufferInternal() |
setNeedsCompositingUpdate(); |
} |
+bool HTMLCanvasElement::canCreateImageBuffer() const |
+{ |
+ if (m_size.isEmpty()) |
+ return false; |
+ if (m_size.width() * m_size.height() > MaxCanvasArea) |
+ return false; |
+ if (m_size.width() > MaxSkiaDim || m_size.height() > MaxSkiaDim) |
+ return false; |
+ return true; |
+} |
+ |
void HTMLCanvasElement::notifySurfaceInvalid() |
{ |
if (m_context && m_context->is2d()) { |
@@ -664,6 +673,7 @@ GraphicsContext* HTMLCanvasElement::existingDrawingContext() const |
ImageBuffer* HTMLCanvasElement::buffer() const |
{ |
+ ASSERT(m_context); |
dshwang
2014/11/26 21:36:54
It means that we can move imageBuffer to CanvasRen
|
if (!hasImageBuffer() && !m_didFailToCreateImageBuffer) |
const_cast<HTMLCanvasElement*>(this)->createImageBuffer(); |
return m_imageBuffer.get(); |
@@ -671,23 +681,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()) |
+ 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 +760,31 @@ PassRefPtr<Image> HTMLCanvasElement::getSourceImageForCanvas(SourceImageMode mod |
return nullptr; |
} |
- if (!buffer()) { |
+ if (!canCreateImageBuffer()) { |
*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); |
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"
|
} |
- RefPtr<SkImage> image = m_imageBuffer->newImageSnapshot(); |
+ RefPtr<SkImage> image = buffer()->newImageSnapshot(); |
Justin Novosad
2014/11/27 00:49:30
here too
|
if (image) { |
*status = NormalSourceImageStatus; |
- |
return StaticBitmapImage::create(image.release()); |
} |
- |
*status = InvalidSourceImageStatus; |
- |
return nullptr; |
} |