18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2004, 2006, 2007 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2007 Alp Toker <alp@atoker.com>
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLCanvasElement.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
30d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "CanvasContextAttributes.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CanvasGradient.h"
328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CanvasPattern.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CanvasRenderingContext2D.h"
34231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(3D_CANVAS)
35d0825bca7fe65beaee391d30da42e937db621564Steve Block#include "WebGLContextAttributes.h"
36643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#include "WebGLRenderingContext.h"
37231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "CanvasStyle.h"
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Chrome.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Document.h"
418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ExceptionCode.h"
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Frame.h"
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "GraphicsContext.h"
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLNames.h"
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "ImageBuffer.h"
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "MIMETypeRegistry.h"
475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "MappedAttribute.h"
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Page.h"
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderHTMLCanvas.h"
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Settings.h"
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <math.h>
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <stdio.h>
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames;
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// These values come from the WhatWG spec.
598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic const int defaultWidth = 300;
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic const int defaultHeight = 150;
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Firefox limits width/height to 32767 pixels, but slows down dramatically before it
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// reaches that limit. We limit by area instead, giving us larger maximum dimensions,
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// in exchange for a smaller maximum canvas size.
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectconst float HTMLCanvasElement::MaxCanvasArea = 32768 * 8192; // Maximum canvas area in CSS pixels
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
67635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectHTMLCanvasElement::HTMLCanvasElement(const QualifiedName& tagName, Document* doc)
68635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    : HTMLElement(tagName, doc)
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_size(defaultWidth, defaultHeight)
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_observer(0)
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_originClean(true)
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_ignoreReset(false)
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    , m_createdImageBuffer(false)
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
75635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(hasTagName(canvasTag));
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHTMLCanvasElement::~HTMLCanvasElement()
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (m_observer)
815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        m_observer->canvasDestroyed(this);
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if ENABLE(DASHBOARD_SUPPORT)
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectHTMLTagStatus HTMLCanvasElement::endTagRequirement() const
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Settings* settings = document()->settings();
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (settings && settings->usesDashboardBackwardCompatibilityMode())
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return TagStatusForbidden;
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return HTMLElement::endTagRequirement();
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectint HTMLCanvasElement::tagPriority() const
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Settings* settings = document()->settings();
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (settings && settings->usesDashboardBackwardCompatibilityMode())
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return HTMLElement::tagPriority();
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::parseMappedAttribute(MappedAttribute* attr)
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const QualifiedName& attrName = attr->name();
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (attrName == widthAttr || attrName == heightAttr)
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        reset();
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HTMLElement::parseMappedAttribute(attr);
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectRenderObject* HTMLCanvasElement::createRenderer(RenderArena* arena, RenderStyle* style)
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Settings* settings = document()->settings();
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (settings && settings->isJavaScriptEnabled()) {
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_rendererIsCanvas = true;
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return new (arena) RenderHTMLCanvas(this);
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_rendererIsCanvas = false;
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return HTMLElement::createRenderer(arena, style);
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::setHeight(int value)
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    setAttribute(heightAttr, String::number(value));
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::setWidth(int value)
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    setAttribute(widthAttr, String::number(value));
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString HTMLCanvasElement::toDataURL(const String& mimeType, ExceptionCode& ec)
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_originClean) {
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ec = SECURITY_ERR;
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
143cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block    if (m_size.isEmpty() || !buffer())
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String("data:,");
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (mimeType.isNull() || !MIMETypeRegistry::isSupportedImageMIMETypeForEncoding(mimeType))
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return buffer()->toDataURL("image/png");
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return buffer()->toDataURL(mimeType);
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
152d0825bca7fe65beaee391d30da42e937db621564Steve BlockCanvasRenderingContext* HTMLCanvasElement::getContext(const String& type, CanvasContextAttributes* attrs)
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
154643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // A Canvas can either be "2D" or "webgl" but never both. If you request a 2D canvas and the existing
155643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // context is already 2D, just return that. If the existing context is WebGL, then destroy it
156643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // before creating a new 2D context. Vice versa when requesting a WebGL canvas. Requesting a
157231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // context with any other type string will destroy any existing context.
158231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
159231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // FIXME - The code depends on the context not going away once created, to prevent JS from
160231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // seeing a dangling pointer. So for now we will disallow the context from being changed
161231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    // once it is created.
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (type == "2d") {
163231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (m_context && !m_context->is2d())
164231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return 0;
165231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if (!m_context)
166231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            m_context = new CanvasRenderingContext2D(this);
167231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return m_context.get();
168231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
169231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(3D_CANVAS)
170231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    Settings* settings = document()->settings();
171231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (settings && settings->webGLEnabled()) {
172643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // Accept the legacy "webkit-3d" name as well as the provisional "experimental-webgl" name.
173643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        // Once ratified, we will also accept "webgl" as the context name.
174231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        if ((type == "webkit-3d") ||
175643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            (type == "experimental-webgl")) {
176231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (m_context && !m_context->is3d())
177231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block                return 0;
178231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            if (!m_context) {
179d0825bca7fe65beaee391d30da42e937db621564Steve Block                m_context = WebGLRenderingContext::create(this, static_cast<WebGLContextAttributes*>(attrs));
180cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                if (m_context) {
181cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                    // Need to make sure a RenderLayer and compositing layer get created for the Canvas
182cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                    setNeedsStyleRecalc(SyntheticStyleChange);
183cac0f67c402d107cdb10971b95719e2ff9c7c76bSteve Block                }
184231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            }
185231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block            return m_context.get();
186231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        }
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
188d0825bca7fe65beaee391d30da42e937db621564Steve Block#else
189d0825bca7fe65beaee391d30da42e937db621564Steve Block    UNUSED_PARAM(attrs);
190231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::willDraw(const FloatRect& rect)
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
196231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (m_imageBuffer)
197231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        m_imageBuffer->clearImage();
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
199635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (RenderBox* ro = renderBox()) {
200635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        FloatRect destRect = ro->contentBoxRect();
201635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        FloatRect r = mapRect(rect, FloatRect(0, 0, m_size.width(), m_size.height()), destRect);
202635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        r.intersect(destRect);
203635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        if (m_dirtyRect.contains(r))
204635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            return;
205635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
206635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        m_dirtyRect.unite(r);
207635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ro->repaintRectangle(enclosingIntRect(m_dirtyRect));
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_observer)
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_observer->canvasChanged(this, rect);
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::reset()
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_ignoreReset)
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool ok;
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int w = getAttribute(widthAttr).toInt(&ok);
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!ok)
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        w = defaultWidth;
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int h = getAttribute(heightAttr).toInt(&ok);
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!ok)
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        h = defaultHeight;
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IntSize oldSize = m_size;
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_size = IntSize(w, h);
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
230d0825bca7fe65beaee391d30da42e937db621564Steve Block#if ENABLE(3D_CANVAS)
231d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (m_context && m_context->is3d())
232d0825bca7fe65beaee391d30da42e937db621564Steve Block        static_cast<WebGLRenderingContext*>(m_context.get())->reshape(width(), height());
233d0825bca7fe65beaee391d30da42e937db621564Steve Block#endif
234d0825bca7fe65beaee391d30da42e937db621564Steve Block
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool hadImageBuffer = m_createdImageBuffer;
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_createdImageBuffer = false;
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_imageBuffer.clear();
238231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (m_context && m_context->is2d())
239231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        static_cast<CanvasRenderingContext2D*>(m_context.get())->reset();
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2410bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (RenderObject* renderer = this->renderer()) {
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_rendererIsCanvas) {
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (oldSize != m_size)
2440bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                toRenderHTMLCanvas(renderer)->canvasSizeChanged();
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (hadImageBuffer)
2460bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch                renderer->repaint();
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2480bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    }
2490bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_observer)
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_observer->canvasResized(this);
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::paint(GraphicsContext* context, const IntRect& r)
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Clear the dirty rect
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_dirtyRect = FloatRect();
258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (context->paintingDisabled())
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
262231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(3D_CANVAS)
263d0825bca7fe65beaee391d30da42e937db621564Steve Block    WebGLRenderingContext* context3D = 0;
264231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    if (m_context && m_context->is3d()) {
265643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        context3D = static_cast<WebGLRenderingContext*>(m_context.get());
266231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context3D->beginPaint();
267231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    }
268231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
269231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_imageBuffer) {
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Image* image = m_imageBuffer->image();
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (image)
273643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            context->drawImage(image, DeviceColorSpace, r);
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
275231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
276231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(3D_CANVAS)
277d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (context3D)
278231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        context3D->endPaint();
279231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectIntRect HTMLCanvasElement::convertLogicalToDevice(const FloatRect& logicalRect) const
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return IntRect(convertLogicalToDevice(logicalRect.location()), convertLogicalToDevice(logicalRect.size()));
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectIntSize HTMLCanvasElement::convertLogicalToDevice(const FloatSize& logicalSize) const
2888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2899652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba#if PLATFORM(ANDROID)
2909652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba    /*  In Android we capture the drawing into a displayList, and then
2919652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        replay that list at various scale factors (sometimes zoomed out, other
2929652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        times zoomed in for "normal" reading, yet other times at arbitrary
2939652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        zoom values based on the user's choice). In all of these cases, we do
2949652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        not re-record the displayList, hence it is usually harmful to perform
2959652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        any pre-rounding, since we just don't know the actual drawing resolution
2969652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        at record time.
2979652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba     */
2989652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba    float pageScaleFactor = 1.0f;
2999652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba#else
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float pageScaleFactor = document()->frame() ? document()->frame()->page()->chrome()->scaleFactor() : 1.0f;
3019652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba#endif
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float wf = ceilf(logicalSize.width() * pageScaleFactor);
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float hf = ceilf(logicalSize.height() * pageScaleFactor);
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!(wf >= 1 && hf >= 1 && wf * hf <= MaxCanvasArea))
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return IntSize();
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return IntSize(static_cast<unsigned>(wf), static_cast<unsigned>(hf));
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectIntPoint HTMLCanvasElement::convertLogicalToDevice(const FloatPoint& logicalPos) const
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3139652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba#if PLATFORM(ANDROID)
3149652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba    /*  In Android we capture the drawing into a displayList, and then
3159652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        replay that list at various scale factors (sometimes zoomed out, other
3169652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        times zoomed in for "normal" reading, yet other times at arbitrary
3179652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        zoom values based on the user's choice). In all of these cases, we do
3189652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        not re-record the displayList, hence it is usually harmful to perform
3199652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        any pre-rounding, since we just don't know the actual drawing resolution
3209652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba        at record time.
3219652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba     */
3229652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba    float pageScaleFactor = 1.0f;
3239652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba#else
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float pageScaleFactor = document()->frame() ? document()->frame()->page()->chrome()->scaleFactor() : 1.0f;
3259652d6b88e01f27d69c804ac6bc56b527b33c219Grace Kloba#endif
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float xf = logicalPos.x() * pageScaleFactor;
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    float yf = logicalPos.y() * pageScaleFactor;
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return IntPoint(static_cast<unsigned>(xf), static_cast<unsigned>(yf));
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid HTMLCanvasElement::createImageBuffer() const
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(!m_imageBuffer);
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_createdImageBuffer = true;
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    FloatSize unscaledSize(width(), height());
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IntSize size = convertLogicalToDevice(unscaledSize);
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!size.width() || !size.height())
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
342635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
3430bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    m_imageBuffer = ImageBuffer::create(size);
3445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // The convertLogicalToDevice MaxCanvasArea check should prevent common cases
3455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // where ImageBuffer::create() returns NULL, however we could still be low on memory.
3465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!m_imageBuffer)
3475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
348635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_imageBuffer->context()->scale(FloatSize(size.width() / unscaledSize.width(), size.height() / unscaledSize.height()));
349635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    m_imageBuffer->context()->setShadowsIgnoreTransforms(true);
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectGraphicsContext* HTMLCanvasElement::drawingContext() const
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return buffer() ? m_imageBuffer->context() : 0;
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectImageBuffer* HTMLCanvasElement::buffer() const
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_createdImageBuffer)
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        createImageBuffer();
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_imageBuffer.get();
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
363635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
3648a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve BlockAffineTransform HTMLCanvasElement::baseTransform() const
365635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
366635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(m_createdImageBuffer);
367635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    FloatSize unscaledSize(width(), height());
368635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    IntSize size = convertLogicalToDevice(unscaledSize);
3698a0914b749bbe7da7768e07a7db5c6d4bb09472bSteve Block    AffineTransform transform;
370635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (size.width() && size.height())
3718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        transform.scaleNonUniform(size.width() / unscaledSize.width(), size.height() / unscaledSize.height());
372635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    transform.multiply(m_imageBuffer->baseTransform());
373635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return transform;
374635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
376231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#if ENABLE(3D_CANVAS)
377231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Blockbool HTMLCanvasElement::is3D() const
378231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block{
379231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    return m_context && m_context->is3d();
380231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block}
381231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block#endif
382231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
384