Reviewed by Hyatt.
[WebKit-https.git] / WebCore / html / HTMLCanvasElement.cpp
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #include "config.h"
27 #include "HTMLCanvasElement.h"
28
29 #include "CanvasGradient.h"
30 #include "CanvasPattern.h"
31 #include "CanvasRenderingContext2D.h"
32 #include "CanvasStyle.h"
33 #include "GraphicsContext.h"
34 #include "HTMLNames.h"
35 #include "RenderHTMLCanvas.h"
36
37 namespace WebCore {
38
39 using namespace HTMLNames;
40
41 // These value come from the specification.
42 const int defaultWidth = 300;
43 const int defaultHeight = 150;
44
45 HTMLCanvasElement::HTMLCanvasElement(Document* doc)
46     : HTMLElement(canvasTag, doc)
47     , m_size(defaultWidth, defaultHeight)
48     , m_createdDrawingContext(false)
49     , m_data(0)
50     , m_drawingContext(0)
51 {
52 }
53
54 HTMLCanvasElement::~HTMLCanvasElement()
55 {
56     if (m_2DContext)
57         m_2DContext->detachCanvas();
58     fastFree(m_data);
59     delete m_drawingContext;
60 }
61
62 void HTMLCanvasElement::parseMappedAttribute(MappedAttribute* attr)
63 {
64     const QualifiedName& attrName = attr->name();
65     if (attrName == widthAttr || attrName == heightAttr)
66         reset();
67     HTMLElement::parseMappedAttribute(attr);
68 }
69
70 RenderObject* HTMLCanvasElement::createRenderer(RenderArena *arena, RenderStyle *style)
71 {
72     RenderHTMLCanvas* r = new (arena) RenderHTMLCanvas(this);
73     r->setIntrinsicWidth(width());
74     r->setIntrinsicHeight(height());
75     return r;
76 }
77
78 void HTMLCanvasElement::setHeight(int value)
79 {
80     setAttribute(heightAttr, String::number(value));
81 }
82
83 void HTMLCanvasElement::setWidth(int value)
84 {
85     setAttribute(widthAttr, String::number(value));
86 }
87
88 CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type)
89 {
90     if (type == "2d") {
91         if (!m_2DContext)
92             m_2DContext = new CanvasRenderingContext2D(this);
93         return m_2DContext.get();
94     }
95     return 0;
96 }
97
98 void HTMLCanvasElement::willDraw(const FloatRect&)
99 {
100     // FIXME: Change to repaint just the dirty rect for speed.
101     // Until we start doing this, we won't know if the rects passed in are
102     // accurate. Also don't forget to take into account the transform
103     // on the context when determining what needs to be repainted.
104     if (renderer())
105         renderer()->repaint();
106 }
107
108 void HTMLCanvasElement::reset()
109 {
110     bool ok;
111     int w = getAttribute(widthAttr).toInt(&ok);
112     if (!ok)
113         w = defaultWidth;
114     int h = getAttribute(heightAttr).toInt(&ok);
115     if (!ok)
116         h = defaultHeight;
117     m_size = IntSize(w, h);
118
119     RenderHTMLCanvas* r = static_cast<RenderHTMLCanvas*>(renderer());
120     if (r) {
121         r->setIntrinsicWidth(w);
122         r->setIntrinsicHeight(h);
123         r->repaint();
124     }
125
126     m_createdDrawingContext = false;
127     fastFree(m_data);
128     m_data = 0;
129     delete m_drawingContext;
130     m_drawingContext = 0;
131 }
132
133 void HTMLCanvasElement::paint(GraphicsContext* p, const IntRect& r)
134 {
135     if (p->paintingDisabled())
136         return;
137 #if __APPLE__
138     if (CGImageRef image = createPlatformImage()) {
139         CGContextDrawImage(p->platformContext(), r, image);
140         CGImageRelease(image);
141     }
142 #endif
143 }
144
145 void HTMLCanvasElement::createDrawingContext() const
146 {
147     ASSERT(!m_createdDrawingContext);
148     ASSERT(!m_data);
149
150     m_createdDrawingContext = true;
151
152     if (width() <= 0 || height() <= 0)
153         return;
154     unsigned w = width();
155     size_t bytesPerRow = w * 4;
156     if (bytesPerRow / 4 != w) // check for overflow
157         return;
158     m_data = fastCalloc(height(), bytesPerRow);
159     if (!m_data)
160         return;
161 #if __APPLE__
162     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
163     CGContextRef bitmapContext = CGBitmapContextCreate(m_data, w, height(), 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
164     CGColorSpaceRelease(colorSpace);
165     m_drawingContext = new GraphicsContext(bitmapContext, false, false);
166     CGContextRelease(bitmapContext);
167 #endif
168 }
169
170 GraphicsContext* HTMLCanvasElement::drawingContext() const
171 {
172     if (!m_createdDrawingContext)
173         createDrawingContext();
174     return m_drawingContext;
175 }
176
177 #if __APPLE__
178
179 CGImageRef HTMLCanvasElement::createPlatformImage() const
180 {
181     GraphicsContext* context = drawingContext();
182     if (!context)
183         return 0;
184     CGContextFlush(context->platformContext());
185     return CGBitmapContextCreateImage(context->platformContext());
186 }
187
188 #endif
189
190 }