Bug 16954: Support putImageData
[WebKit-https.git] / WebCore / bindings / js / JSCanvasRenderingContext2DCustom.cpp
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public License
15  * along with this library; see the file COPYING.LIB.  If not, write to
16  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19
20 #include "config.h"
21 #include "JSCanvasRenderingContext2D.h"
22
23 #include "CanvasGradient.h"
24 #include "CanvasPattern.h"
25 #include "CanvasRenderingContext2D.h"
26 #include "CanvasStyle.h"
27 #include "ExceptionCode.h"
28 #include "FloatRect.h"
29 #include "HTMLCanvasElement.h"
30 #include "HTMLImageElement.h"
31 #include "ImageData.h"
32 #include "JSCanvasGradient.h"
33 #include "JSCanvasPattern.h"
34 #include "JSHTMLCanvasElement.h"
35 #include "JSHTMLImageElement.h"
36 #include "JSImageData.h"
37 #include "kjs_html.h"
38
39 using namespace KJS;
40
41 namespace WebCore {
42
43 static JSValue* toJS(ExecState* exec, CanvasStyle* style)
44 {
45     if (style->gradient())
46         return toJS(exec, style->gradient());
47     if (style->pattern())
48         return toJS(exec, style->pattern());
49     return jsString(style->color());
50 }
51
52 static PassRefPtr<CanvasStyle> toHTMLCanvasStyle(ExecState* exec, JSValue* value)
53 {
54     if (value->isString())
55         return new CanvasStyle(value->toString(exec));
56     if (!value->isObject())
57         return 0;
58     JSObject* object = static_cast<JSObject*>(value);
59     if (object->inherits(&JSCanvasGradient::info))
60         return new CanvasStyle(static_cast<JSCanvasGradient*>(object)->impl());
61     if (object->inherits(&JSCanvasPattern::info))
62         return new CanvasStyle(static_cast<JSCanvasPattern*>(object)->impl());
63     return 0;
64 }
65
66 JSValue* JSCanvasRenderingContext2D::strokeStyle(ExecState* exec) const
67 {
68     return toJS(exec, impl()->strokeStyle());        
69 }
70
71 void JSCanvasRenderingContext2D::setStrokeStyle(ExecState* exec, JSValue* value)
72 {
73     impl()->setStrokeStyle(toHTMLCanvasStyle(exec, value));
74 }
75
76 JSValue* JSCanvasRenderingContext2D::fillStyle(ExecState* exec) const
77 {
78     return toJS(exec, impl()->fillStyle());
79 }
80
81 void JSCanvasRenderingContext2D::setFillStyle(ExecState* exec, JSValue* value)
82 {
83     impl()->setFillStyle(toHTMLCanvasStyle(exec, value));
84 }
85
86 JSValue* JSCanvasRenderingContext2D::setFillColor(ExecState* exec, const List& args)
87 {
88     CanvasRenderingContext2D* context = impl();
89
90     // string arg = named color
91     // number arg = gray color
92     // string arg, number arg = named color, alpha
93     // number arg, number arg = gray color, alpha
94     // 4 args = r, g, b, a
95     // 5 args = c, m, y, k, a
96     switch (args.size()) {
97         case 1:
98             if (args[0]->isString())
99                 context->setFillColor(args[0]->toString(exec));
100             else
101                 context->setFillColor(args[0]->toFloat(exec));
102             break;
103         case 2:
104             if (args[0]->isString())
105                 context->setFillColor(args[0]->toString(exec), args[1]->toFloat(exec));
106             else
107                 context->setFillColor(args[0]->toFloat(exec), args[1]->toFloat(exec));
108             break;
109         case 4:
110             context->setFillColor(args[0]->toFloat(exec), args[1]->toFloat(exec),
111                                   args[2]->toFloat(exec), args[3]->toFloat(exec));
112             break;
113         case 5:
114             context->setFillColor(args[0]->toFloat(exec), args[1]->toFloat(exec),
115                                   args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec));
116             break;
117         default:
118             return throwError(exec, SyntaxError);
119     }
120     return jsUndefined();
121 }    
122
123 JSValue* JSCanvasRenderingContext2D::setStrokeColor(ExecState* exec, const List& args)
124
125     CanvasRenderingContext2D* context = impl();
126
127     // string arg = named color
128     // number arg = gray color
129     // string arg, number arg = named color, alpha
130     // number arg, number arg = gray color, alpha
131     // 4 args = r, g, b, a
132     // 5 args = c, m, y, k, a
133     switch (args.size()) {
134         case 1:
135             if (args[0]->isString())
136                 context->setStrokeColor(args[0]->toString(exec));
137             else
138                 context->setStrokeColor(args[0]->toFloat(exec));
139             break;
140         case 2:
141             if (args[0]->isString())
142                 context->setStrokeColor(args[0]->toString(exec), args[1]->toFloat(exec));
143             else
144                 context->setStrokeColor(args[0]->toFloat(exec), args[1]->toFloat(exec));
145             break;
146         case 4:
147             context->setStrokeColor(args[0]->toFloat(exec), args[1]->toFloat(exec),
148                                     args[2]->toFloat(exec), args[3]->toFloat(exec));
149             break;
150         case 5:
151             context->setStrokeColor(args[0]->toFloat(exec), args[1]->toFloat(exec),
152                                     args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec));
153             break;
154         default:
155             return throwError(exec, SyntaxError);
156     }
157     
158     return jsUndefined();
159 }
160
161 JSValue* JSCanvasRenderingContext2D::strokeRect(ExecState* exec, const List& args)
162
163     CanvasRenderingContext2D* context = impl();    
164     ExceptionCode ec;
165     
166     if (args.size() <= 4)
167         context->strokeRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
168                             args[2]->toFloat(exec), args[3]->toFloat(exec), ec);
169     else
170         context->strokeRect(args[0]->toFloat(exec), args[1]->toFloat(exec),
171                             args[2]->toFloat(exec), args[3]->toFloat(exec), args[4]->toFloat(exec), ec);
172     setDOMException(exec, ec);
173     
174     return jsUndefined();    
175 }
176
177 JSValue* JSCanvasRenderingContext2D::drawImage(ExecState* exec, const List& args)
178
179     CanvasRenderingContext2D* context = impl();
180
181     // DrawImage has three variants:
182     //     drawImage(img, dx, dy)
183     //     drawImage(img, dx, dy, dw, dh)
184     //     drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
185     // Composite operation is specified with globalCompositeOperation.
186     // The img parameter can be a <img> or <canvas> element.
187     JSValue* value = args[0];
188     if (!value->isObject())
189         return throwError(exec, TypeError);
190     JSObject* o = static_cast<JSObject*>(value);
191     
192     ExceptionCode ec = 0;
193     if (o->inherits(&JSHTMLImageElement::info)) {
194         HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl());
195         switch (args.size()) {
196             case 3:
197                 context->drawImage(imgElt, args[1]->toFloat(exec), args[2]->toFloat(exec));
198                 break;
199             case 5:
200                 context->drawImage(imgElt, args[1]->toFloat(exec), args[2]->toFloat(exec),
201                                    args[3]->toFloat(exec), args[4]->toFloat(exec), ec);
202                 setDOMException(exec, ec);
203                 break;
204             case 9:
205                 context->drawImage(imgElt, FloatRect(args[1]->toFloat(exec), args[2]->toFloat(exec),
206                                    args[3]->toFloat(exec), args[4]->toFloat(exec)),
207                                    FloatRect(args[5]->toFloat(exec), args[6]->toFloat(exec),
208                                    args[7]->toFloat(exec), args[8]->toFloat(exec)), ec);
209                 setDOMException(exec, ec);
210                 break;
211             default:
212                 return throwError(exec, SyntaxError);
213         }
214     } else if (o->inherits(&JSHTMLCanvasElement::info)) {
215         HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(args[0])->impl());
216         switch (args.size()) {
217             case 3:
218                 context->drawImage(canvas, args[1]->toFloat(exec), args[2]->toFloat(exec));
219                 break;
220             case 5:
221                 context->drawImage(canvas, args[1]->toFloat(exec), args[2]->toFloat(exec),
222                                    args[3]->toFloat(exec), args[4]->toFloat(exec), ec);
223                 setDOMException(exec, ec);
224                 break;
225             case 9:
226                 context->drawImage(canvas, FloatRect(args[1]->toFloat(exec), args[2]->toFloat(exec),
227                                    args[3]->toFloat(exec), args[4]->toFloat(exec)),
228                                    FloatRect(args[5]->toFloat(exec), args[6]->toFloat(exec),
229                                    args[7]->toFloat(exec), args[8]->toFloat(exec)), ec);
230                 setDOMException(exec, ec);
231                 break;
232             default:
233                 return throwError(exec, SyntaxError);
234         }
235     } else {
236         setDOMException(exec, TYPE_MISMATCH_ERR);
237         return 0;
238     }
239     
240     return jsUndefined();    
241 }
242
243 JSValue* JSCanvasRenderingContext2D::drawImageFromRect(ExecState* exec, const List& args)
244
245     CanvasRenderingContext2D* context = impl();
246     
247     JSValue* value = args[0];
248     if (!value->isObject())
249         return throwError(exec, TypeError);
250     JSObject* o = static_cast<JSObject*>(value);
251     
252     if (!o->inherits(&JSHTMLImageElement::info))
253         return throwError(exec, TypeError);
254     context->drawImageFromRect(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl()),
255                                args[1]->toFloat(exec), args[2]->toFloat(exec),
256                                args[3]->toFloat(exec), args[4]->toFloat(exec),
257                                args[5]->toFloat(exec), args[6]->toFloat(exec),
258                                args[7]->toFloat(exec), args[8]->toFloat(exec),
259                                args[9]->toString(exec));    
260     return jsUndefined();    
261 }
262
263 JSValue* JSCanvasRenderingContext2D::setShadow(ExecState* exec, const List& args)
264
265     CanvasRenderingContext2D* context = impl();
266
267     switch (args.size()) {
268         case 3:
269             context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
270                                args[2]->toFloat(exec));
271             break;
272         case 4:
273             if (args[3]->isString())
274                 context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
275                                    args[2]->toFloat(exec), args[3]->toString(exec));
276             else
277                 context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
278                                    args[2]->toFloat(exec), args[3]->toFloat(exec));
279             break;
280         case 5:
281             if (args[3]->isString())
282                 context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
283                                    args[2]->toFloat(exec), args[3]->toString(exec),
284                                    args[4]->toFloat(exec));
285             else
286                 context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
287                                    args[2]->toFloat(exec), args[3]->toFloat(exec),
288                                    args[4]->toFloat(exec));
289             break;
290         case 7:
291             context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
292                                args[2]->toFloat(exec), args[3]->toFloat(exec),
293                                args[4]->toFloat(exec), args[5]->toFloat(exec),
294                                args[6]->toFloat(exec));
295             break;
296         case 8:
297             context->setShadow(args[0]->toFloat(exec), args[1]->toFloat(exec),
298                                args[2]->toFloat(exec), args[3]->toFloat(exec),
299                                args[4]->toFloat(exec), args[5]->toFloat(exec),
300                                args[6]->toFloat(exec), args[7]->toFloat(exec));
301             break;
302         default:
303             return throwError(exec, SyntaxError);
304     }
305     
306     return jsUndefined();    
307 }
308
309 JSValue* JSCanvasRenderingContext2D::createPattern(ExecState* exec, const List& args)
310
311     CanvasRenderingContext2D* context = impl();
312
313     JSValue* value = args[0];
314     if (!value->isObject())
315         return throwError(exec, TypeError);
316     JSObject* o = static_cast<JSObject*>(value);
317     
318     if (o->inherits(&JSHTMLImageElement::info)) {
319         ExceptionCode ec;
320         JSValue* pattern = toJS(exec,
321             context->createPattern(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl()),
322                 args[1]->toString(exec), ec).get());
323         setDOMException(exec, ec);
324         return pattern;
325     }
326     if (o->inherits(&JSHTMLCanvasElement::info)) {
327         ExceptionCode ec;
328         JSValue* pattern = toJS(exec,
329             context->createPattern(static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(args[0])->impl()),
330                 args[1]->toString(exec), ec).get());
331         setDOMException(exec, ec);
332         return pattern;
333     }
334     setDOMException(exec, TYPE_MISMATCH_ERR);
335     return 0;
336 }
337
338 JSValue* JSCanvasRenderingContext2D::putImageData(ExecState* exec, const List& args)
339 {
340     // putImageData has two variants
341     // putImageData(ImageData, x, y)
342     // putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
343     CanvasRenderingContext2D* context = impl();
344
345     ExceptionCode ec = 0;
346     if (args.size() >= 7)
347         context->putImageData(toImageData(args[0]), args[1]->toFloat(exec), args[2]->toFloat(exec), 
348                               args[3]->toFloat(exec), args[4]->toFloat(exec), args[5]->toFloat(exec), args[6]->toFloat(exec), ec);
349     else
350         context->putImageData(toImageData(args[0]), args[1]->toFloat(exec), args[2]->toFloat(exec), ec);
351
352     setDOMException(exec, ec);
353     return jsUndefined();
354 }
355
356 } // namespace WebCore