diff options
Diffstat (limited to 'Source/WebCore/dom/CanvasSurface.cpp')
-rw-r--r-- | Source/WebCore/dom/CanvasSurface.cpp | 196 |
1 files changed, 196 insertions, 0 deletions
diff --git a/Source/WebCore/dom/CanvasSurface.cpp b/Source/WebCore/dom/CanvasSurface.cpp new file mode 100644 index 0000000..988864b --- /dev/null +++ b/Source/WebCore/dom/CanvasSurface.cpp @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2010 Google Inc. All rights reserved. + * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "CanvasSurface.h" + +#include "AffineTransform.h" +#include "ExceptionCode.h" +#include "FloatRect.h" +#include "GraphicsContext.h" +#include "HTMLCanvasElement.h" +#include "ImageBuffer.h" +#include "MIMETypeRegistry.h" + +namespace WebCore { + +// These values come from the WhatWG spec. +const int CanvasSurface::DefaultWidth = 300; +const int CanvasSurface::DefaultHeight = 150; + +// Firefox limits width/height to 32767 pixels, but slows down dramatically before it +// reaches that limit. We limit by area instead, giving us larger maximum dimensions, +// in exchange for a smaller maximum canvas size. +const float CanvasSurface::MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels + +CanvasSurface::CanvasSurface(float pageScaleFactor) + : m_size(DefaultWidth, DefaultHeight) +#if PLATFORM(ANDROID) + /* In Android we capture the drawing into a displayList, and then replay + * that list at various scale factors (sometimes zoomed out, other times + * zoomed in for "normal" reading, yet other times at arbitrary zoom values + * based on the user's choice). In all of these cases, we do not re-record + * the displayList, hence it is usually harmful to perform any pre-rounding, + * since we just don't know the actual drawing resolution at record time. + */ + // TODO - may be better to move the ifdef to the call site of this + // constructor + , m_pageScaleFactor(1.0f) +#else + , m_pageScaleFactor(pageScaleFactor) +#endif + , m_originClean(true) + , m_hasCreatedImageBuffer(false) +{ +} + +CanvasSurface::~CanvasSurface() +{ +} + +void CanvasSurface::setSurfaceSize(const IntSize& size) +{ + m_size = size; + m_hasCreatedImageBuffer = false; + m_imageBuffer.clear(); +} + +String CanvasSurface::toDataURL(const String& mimeType, const double* quality, ExceptionCode& ec) +{ + if (!m_originClean) { + ec = SECURITY_ERR; + return String(); + } + + if (m_size.isEmpty() || !buffer()) + return String("data:,"); + + String lowercaseMimeType = mimeType.lower(); + + // FIXME: Make isSupportedImageMIMETypeForEncoding threadsafe (to allow this method to be used on a worker thread). + if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(lowercaseMimeType)) + return buffer()->toDataURL("image/png"); + + return buffer()->toDataURL(lowercaseMimeType, quality); +} + +void CanvasSurface::willDraw(const FloatRect&) +{ + if (m_imageBuffer) + m_imageBuffer->clearImage(); +} + +IntRect CanvasSurface::convertLogicalToDevice(const FloatRect& logicalRect) const +{ + return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size())); +} + +IntSize CanvasSurface::convertLogicalToDevice(const FloatSize& logicalSize) const +{ + float wf = ceilf(logicalSize.width() * m_pageScaleFactor); + float hf = ceilf(logicalSize.height() * m_pageScaleFactor); + + if (!(wf >= 1 && hf >= 1 && wf * hf <= MaxCanvasArea)) + return IntSize(); + + return IntSize(static_cast<unsigned>(wf), static_cast<unsigned>(hf)); +} + +IntPoint CanvasSurface::convertLogicalToDevice(const FloatPoint& logicalPos) const +{ + float xf = logicalPos.x() * m_pageScaleFactor; + float yf = logicalPos.y() * m_pageScaleFactor; + + return IntPoint(static_cast<unsigned>(xf), static_cast<unsigned>(yf)); +} + +void CanvasSurface::createImageBuffer() const +{ + ASSERT(!m_imageBuffer); + + m_hasCreatedImageBuffer = true; + + FloatSize unscaledSize(width(), height()); + IntSize size = convertLogicalToDevice(unscaledSize); + if (!size.width() || !size.height()) + return; + + m_imageBuffer = ImageBuffer::create(size); + // The convertLogicalToDevice MaxCanvasArea check should prevent common cases + // where ImageBuffer::create() returns 0, however we could still be low on memory. + if (!m_imageBuffer) + return; + m_imageBuffer->context()->scale(FloatSize(size.width() / unscaledSize.width(), size.height() / unscaledSize.height())); + m_imageBuffer->context()->setShadowsIgnoreTransforms(true); +} + +GraphicsContext* CanvasSurface::drawingContext() const +{ + return buffer() ? m_imageBuffer->context() : 0; +} + +ImageBuffer* CanvasSurface::buffer() const +{ + if (!m_hasCreatedImageBuffer) + createImageBuffer(); + return m_imageBuffer.get(); +} + +AffineTransform CanvasSurface::baseTransform() const +{ + ASSERT(m_hasCreatedImageBuffer); + FloatSize unscaledSize(width(), height()); + IntSize size = convertLogicalToDevice(unscaledSize); + AffineTransform transform; + if (size.width() && size.height()) + transform.scaleNonUniform(size.width() / unscaledSize.width(), size.height() / unscaledSize.height()); + transform.multiply(m_imageBuffer->baseTransform()); + return transform; +} + +// FIXME: Everything below here relies on CanvasSurface really being +// a HTMLCanvasElement. +const SecurityOrigin& CanvasSurface::securityOrigin() const +{ + return *(static_cast<const HTMLCanvasElement*>(this)->document()->securityOrigin()); +} + +RenderBox* CanvasSurface::renderBox() const +{ + return static_cast<const HTMLCanvasElement*>(this)->renderBox(); +} + +RenderStyle* CanvasSurface::computedStyle() +{ + return static_cast<HTMLCanvasElement*>(this)->computedStyle(); +} + +CSSStyleSelector* CanvasSurface::styleSelector() +{ + return static_cast<HTMLCanvasElement*>(this)->document()->styleSelector(); +} + +} // namespace WebCore |