LayoutTests:
[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), m_size(defaultWidth, defaultHeight)
47     , m_createdDrawingContext(false), m_data(0)
48 #if __APPLE__
49     , m_drawingContext(0)
50 #endif
51 {
52 }
53
54 HTMLCanvasElement::~HTMLCanvasElement()
55 {
56     if (m_2DContext)
57         m_2DContext->detachCanvas();
58     fastFree(m_data);
59 #if __APPLE__
60     CGContextRelease(m_drawingContext);
61 #endif
62 }
63
64 void HTMLCanvasElement::parseMappedAttribute(MappedAttribute* attr)
65 {
66     const QualifiedName& attrName = attr->name();
67     if (attrName == widthAttr || attrName == heightAttr)
68         reset();
69     HTMLElement::parseMappedAttribute(attr);
70 }
71
72 RenderObject* HTMLCanvasElement::createRenderer(RenderArena *arena, RenderStyle *style)
73 {
74     RenderHTMLCanvas* r = new (arena) RenderHTMLCanvas(this);
75     r->setIntrinsicWidth(width());
76     r->setIntrinsicHeight(height());
77     return r;
78 }
79
80 void HTMLCanvasElement::setHeight(int value)
81 {
82     setAttribute(heightAttr, String::number(value));
83 }
84
85 void HTMLCanvasElement::setWidth(int value)
86 {
87     setAttribute(widthAttr, String::number(value));
88 }
89
90 CanvasRenderingContext* HTMLCanvasElement::getContext(const String& type)
91 {
92     // FIXME: Web Applications 1.0 says "2d" only, but the code here matches historical behavior of WebKit.
93     if (type.isNull() || type == "2d" || type == "2D") {
94         if (!m_2DContext)
95             m_2DContext = new CanvasRenderingContext2D(this);
96         return m_2DContext.get();
97     }
98     return 0;
99 }
100
101 void HTMLCanvasElement::willDraw(const FloatRect&)
102 {
103     // FIXME: Change to repaint just the dirty rect for speed.
104     // Until we start doing this, we won't know if the rects passed in are
105     // accurate. Also don't forget to take into account the transform
106     // on the context when determining what needs to be repainted.
107     if (renderer())
108         renderer()->repaint();
109 }
110
111 void HTMLCanvasElement::reset()
112 {
113     bool ok;
114     int w = getAttribute(widthAttr).toInt(&ok);
115     if (!ok)
116         w = defaultWidth;
117     int h = getAttribute(heightAttr).toInt(&ok);
118     if (!ok)
119         h = defaultHeight;
120     m_size = IntSize(w, h);
121
122     RenderHTMLCanvas* r = static_cast<RenderHTMLCanvas*>(renderer());
123     if (r) {
124         r->setIntrinsicWidth(w);
125         r->setIntrinsicHeight(h);
126         r->repaint();
127     }
128
129     m_createdDrawingContext = false;
130     CGContextRelease(m_drawingContext);
131     m_drawingContext = 0;
132     fastFree(m_data);
133     m_data = 0;
134 }
135
136 void HTMLCanvasElement::paint(GraphicsContext* p, const IntRect& r)
137 {
138     if (p->paintingDisabled())
139         return;
140 #if __APPLE__
141     if (CGImageRef image = createPlatformImage()) {
142         CGContextDrawImage(p->currentCGContext(), r, image);
143         CGImageRelease(image);
144     }
145 #endif
146 }
147
148 void HTMLCanvasElement::createDrawingContext() const
149 {
150     ASSERT(!m_createdDrawingContext);
151     ASSERT(!m_data);
152
153     m_createdDrawingContext = true;
154
155     if (width() <= 0 || height() <= 0)
156         return;
157     unsigned w = width();
158     size_t bytesPerRow = w * 4;
159     if (bytesPerRow / 4 != w) // check for overflow
160         return;
161     m_data = fastCalloc(height(), bytesPerRow);
162     if (!m_data)
163         return;
164 #if __APPLE__
165     CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
166     m_drawingContext = CGBitmapContextCreate(m_data, w, height(), 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
167     CGColorSpaceRelease(colorSpace);
168 #endif
169 }
170
171 #if __APPLE__
172
173 CGContextRef HTMLCanvasElement::drawingContext() const
174 {
175     if (!m_createdDrawingContext)
176         createDrawingContext();
177     return m_drawingContext;
178 }
179
180 CGImageRef HTMLCanvasElement::createPlatformImage() const
181 {
182     CGContextRef context = drawingContext();
183     if (!context)
184         return 0;
185     CGContextFlush(context);
186     return CGBitmapContextCreateImage(context);
187 }
188
189 #endif
190
191 }