#include "config.h"
#include "core/html/HTMLCanvasElement.h"
-#include <math.h>
#include "HTMLNames.h"
#include "RuntimeEnabledFeatures.h"
#include "bindings/v8/ExceptionMessages.h"
#include "platform/graphics/gpu/WebGLImageBufferSurface.h"
#include "platform/transforms/AffineTransform.h"
#include "public/platform/Platform.h"
+#include <math.h>
namespace WebCore {
: HTMLElement(canvasTag, document)
, DocumentVisibilityObserver(document)
, m_size(DefaultWidth, DefaultHeight)
- , m_rendererIsCanvas(false)
, m_ignoreReset(false)
, m_accelerationDisabled(false)
, m_externallyAllocatedMemory(0)
ScriptWrappable::init(this);
}
-PassRefPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document)
+PassRefPtrWillBeRawPtr<HTMLCanvasElement> HTMLCanvasElement::create(Document& document)
{
- return adoptRef(new HTMLCanvasElement(document));
+ return adoptRefWillBeRefCountedGarbageCollected(new HTMLCanvasElement(document));
}
HTMLCanvasElement::~HTMLCanvasElement()
for (HashSet<CanvasObserver*>::iterator it = m_observers.begin(); it != end; ++it)
(*it)->canvasDestroyed(this);
+#if !ENABLE(OILPAN)
m_context.clear(); // Ensure this goes away before the ImageBuffer.
+#endif
}
void HTMLCanvasElement::parseAttribute(const QualifiedName& name, const AtomicString& value)
RenderObject* HTMLCanvasElement::createRenderer(RenderStyle* style)
{
LocalFrame* frame = document().frame();
- if (frame && frame->script().canExecuteScripts(NotAboutToExecuteScript)) {
- m_rendererIsCanvas = true;
+ if (frame && frame->script().canExecuteScripts(NotAboutToExecuteScript))
return new RenderHTMLCanvas(this);
- }
-
- m_rendererIsCanvas = false;
return HTMLElement::createRenderer(style);
}
if (!m_context) {
blink::Platform::current()->histogramEnumeration("Canvas.ContextType", Context2d, ContextTypeCount);
m_context = CanvasRenderingContext2D::create(this, static_cast<Canvas2DContextAttributes*>(attrs), document().inQuirksMode());
- if (m_context)
- scheduleLayerUpdate();
+ setNeedsCompositingUpdate();
}
return m_context.get();
}
- // Accept the legacy "webkit-3d" name as well as the provisional "experimental-webgl" name.
- // Now that WebGL is ratified, we will also accept "webgl" as the context name in Chrome.
+ // Accept the the provisional "experimental-webgl" or official "webgl" context ID.
ContextType contextType;
bool is3dContext = true;
- if (type == "webkit-3d")
- contextType = ContextWebkit3d;
- else if (type == "experimental-webgl")
+ if (type == "experimental-webgl")
contextType = ContextExperimentalWebgl;
else if (type == "webgl")
contextType = ContextWebgl;
if (!m_context) {
blink::Platform::current()->histogramEnumeration("Canvas.ContextType", contextType, ContextTypeCount);
m_context = WebGLRenderingContext::create(this, static_cast<WebGLContextAttributes*>(attrs));
- if (m_context) {
- scheduleLayerUpdate();
- updateExternallyAllocatedMemory();
- }
+ setNeedsCompositingUpdate();
+ updateExternallyAllocatedMemory();
}
return m_context.get();
}
toWebGLRenderingContext(m_context.get())->reshape(width(), height());
if (RenderObject* renderer = this->renderer()) {
- if (m_rendererIsCanvas) {
+ if (renderer->isCanvas()) {
if (oldSize != size()) {
toRenderHTMLCanvas(renderer)->canvasSizeChanged();
if (renderBox() && renderBox()->hasAcceleratedCompositing())
if (m_presentedImage)
context->drawImage(m_presentedImage.get(), pixelSnappedIntRect(r), compositeOperator, DoNotRespectImageOrientation);
else
- context->drawImageBuffer(imageBuffer, pixelSnappedIntRect(r), compositeOperator, blink::WebBlendModeNormal);
+ context->drawImageBuffer(imageBuffer, pixelSnappedIntRect(r), 0, compositeOperator);
}
+ } else {
+ // When alpha is false, we should draw to opaque black.
+ if (m_context && !m_context->hasAlpha())
+ context->fillRect(FloatRect(0, 0, width(), height()), Color(0, 0, 0));
}
if (is3D())
m_didFailToCreateImageBuffer = false;
discardImageBuffer();
clearCopiedImage();
+ if (m_context && m_context->is2d()) {
+ CanvasRenderingContext2D* context2d = toCanvasRenderingContext2D(m_context.get());
+ if (context2d->isContextLost()) {
+ context2d->restoreContext();
+ }
+ }
}
String HTMLCanvasElement::toEncodingMimeType(const String& mimeType)
return lowercaseMimeType;
}
-String HTMLCanvasElement::toDataURL(const String& mimeType, const double* quality, ExceptionState& exceptionState)
+const AtomicString HTMLCanvasElement::imageSourceURL() const
{
- if (!m_originClean) {
- exceptionState.throwSecurityError("Tainted canvases may not be exported.");
- return String();
- }
+ return AtomicString(toDataURLInternal("image/png", 0));
+}
+String HTMLCanvasElement::toDataURLInternal(const String& mimeType, const double* quality) const
+{
if (m_size.isEmpty() || !buffer())
return String("data:,");
String encodingMimeType = toEncodingMimeType(mimeType);
// Try to get ImageData first, as that may avoid lossy conversions.
- RefPtr<ImageData> imageData = getImageData();
+ RefPtrWillBeRawPtr<ImageData> imageData = getImageData();
if (imageData)
return ImageDataToDataURL(ImageDataBuffer(imageData->size(), imageData->data()), encodingMimeType, quality);
return buffer()->toDataURL(encodingMimeType, quality);
}
-PassRefPtr<ImageData> HTMLCanvasElement::getImageData()
+String HTMLCanvasElement::toDataURL(const String& mimeType, const double* quality, ExceptionState& exceptionState) const
+{
+ if (!m_originClean) {
+ exceptionState.throwSecurityError("Tainted canvases may not be exported.");
+ return String();
+ }
+
+ return toDataURLInternal(mimeType, quality);
+}
+
+PassRefPtrWillBeRawPtr<ImageData> HTMLCanvasElement::getImageData() const
{
if (!m_context || !m_context->is3d())
return nullptr;
void HTMLCanvasElement::createImageBuffer()
{
+ createImageBufferInternal();
+ if (m_didFailToCreateImageBuffer && m_context && m_context->is2d())
+ toCanvasRenderingContext2D(m_context.get())->loseContext();
+}
+
+void HTMLCanvasElement::createImageBufferInternal()
+{
ASSERT(!m_imageBuffer);
ASSERT(!m_contextStateSaver);
OwnPtr<ImageBufferSurface> surface = createImageBufferSurface(deviceSize, &msaaSampleCount);
if (!surface->isValid())
return;
+
m_imageBuffer = ImageBuffer::create(surface.release());
+ m_imageBuffer->setClient(this);
m_didFailToCreateImageBuffer = false;
return;
}
+ m_imageBuffer->setClient(this);
m_imageBuffer->context()->setShouldClampToSourceRect(false);
+ m_imageBuffer->context()->disableAntialiasingOptimizationForHairlineImages();
m_imageBuffer->context()->setImageInterpolationQuality(CanvasDefaultInterpolationQuality);
// Enabling MSAA overrides a request to disable antialiasing. This is true regardless of whether the
// rendering mode is accelerated or not. For consistency, we don't want to apply AA in accelerated
m_imageBuffer->context()->setStrokeThickness(1);
m_contextStateSaver = adoptPtr(new GraphicsContextStateSaver(*m_imageBuffer->context()));
- // Recalculate compositing requirements if acceleration state changed.
if (m_context)
- scheduleLayerUpdate();
+ setNeedsCompositingUpdate();
+}
+
+void HTMLCanvasElement::notifySurfaceInvalid()
+{
+ if (m_context && m_context->is2d()) {
+ CanvasRenderingContext2D* context2d = toCanvasRenderingContext2D(m_context.get());
+ context2d->loseContext();
+ }
+}
+
+void HTMLCanvasElement::trace(Visitor* visitor)
+{
+ visitor->trace(m_context);
+ HTMLElement::trace(visitor);
}
void HTMLCanvasElement::updateExternallyAllocatedMemory() const
updateExternallyAllocatedMemory();
}
+bool HTMLCanvasElement::hasValidImageBuffer() const
+{
+ return m_imageBuffer && m_imageBuffer->isSurfaceValid();
+}
+
void HTMLCanvasElement::clearCopiedImage()
{
m_copiedImage.clear();