JavaScriptCore:
[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/Error.h>
38
39 using namespace KJS;
40
41 namespace WebCore {
42
43 static JSValue* toJS(ExecState* exec, CanvasStyle* style)
44 {
45     if (style->canvasGradient())
46         return toJS(exec, style->canvasGradient());
47     if (style->pattern())
48         return toJS(exec, style->pattern());
49     return jsString(exec, style->color());
50 }
51
52 static PassRefPtr<CanvasStyle> toHTMLCanvasStyle(ExecState* exec, JSValue* value)
53 {
54     if (value->isString())
55         return CanvasStyle::create(static_cast<JSString*>(value)->value());
56     if (!value->isObject())
57         return 0;
58     JSObject* object = static_cast<JSObject*>(value);
59     if (object->inherits(&JSCanvasGradient::s_info))
60         return CanvasStyle::create(static_cast<JSCanvasGradient*>(object)->impl());
61     if (object->inherits(&JSCanvasPattern::s_info))
62         return CanvasStyle::create(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 ArgList& 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.at(exec, 0)->isString())
99                 context->setFillColor(static_cast<JSString*>(args.at(exec, 0))->value());
100             else
101                 context->setFillColor(args.at(exec, 0)->toFloat(exec));
102             break;
103         case 2:
104             if (args.at(exec, 0)->isString())
105                 context->setFillColor(static_cast<JSString*>(args.at(exec, 0))->value(), args.at(exec, 1)->toFloat(exec));
106             else
107                 context->setFillColor(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec));
108             break;
109         case 4:
110             context->setFillColor(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
111                                   args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec));
112             break;
113         case 5:
114             context->setFillColor(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
115                                   args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec), args.at(exec, 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 ArgList& 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.at(exec, 0)->isString())
136                 context->setStrokeColor(static_cast<JSString*>(args.at(exec, 0))->value());
137             else
138                 context->setStrokeColor(args.at(exec, 0)->toFloat(exec));
139             break;
140         case 2:
141             if (args.at(exec, 0)->isString())
142                 context->setStrokeColor(static_cast<JSString*>(args.at(exec, 0))->value(), args.at(exec, 1)->toFloat(exec));
143             else
144                 context->setStrokeColor(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec));
145             break;
146         case 4:
147             context->setStrokeColor(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
148                                     args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec));
149             break;
150         case 5:
151             context->setStrokeColor(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
152                                     args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec), args.at(exec, 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 ArgList& args)
162
163     CanvasRenderingContext2D* context = impl();
164     
165     if (args.size() <= 4)
166         context->strokeRect(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
167                             args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec));
168     else
169         context->strokeRect(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
170                             args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec));
171
172     return jsUndefined();    
173 }
174
175 JSValue* JSCanvasRenderingContext2D::drawImage(ExecState* exec, const ArgList& args)
176
177     CanvasRenderingContext2D* context = impl();
178
179     // DrawImage has three variants:
180     //     drawImage(img, dx, dy)
181     //     drawImage(img, dx, dy, dw, dh)
182     //     drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
183     // Composite operation is specified with globalCompositeOperation.
184     // The img parameter can be a <img> or <canvas> element.
185     JSValue* value = args.at(exec, 0);
186     if (!value->isObject())
187         return throwError(exec, TypeError);
188     JSObject* o = static_cast<JSObject*>(value);
189     
190     ExceptionCode ec = 0;
191     if (o->inherits(&JSHTMLImageElement::s_info)) {
192         HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args.at(exec, 0))->impl());
193         switch (args.size()) {
194             case 3:
195                 context->drawImage(imgElt, args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec));
196                 break;
197             case 5:
198                 context->drawImage(imgElt, args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec),
199                                    args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec), ec);
200                 setDOMException(exec, ec);
201                 break;
202             case 9:
203                 context->drawImage(imgElt, FloatRect(args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec),
204                                    args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec)),
205                                    FloatRect(args.at(exec, 5)->toFloat(exec), args.at(exec, 6)->toFloat(exec),
206                                    args.at(exec, 7)->toFloat(exec), args.at(exec, 8)->toFloat(exec)), ec);
207                 setDOMException(exec, ec);
208                 break;
209             default:
210                 return throwError(exec, SyntaxError);
211         }
212     } else if (o->inherits(&JSHTMLCanvasElement::s_info)) {
213         HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(args.at(exec, 0))->impl());
214         switch (args.size()) {
215             case 3:
216                 context->drawImage(canvas, args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec));
217                 break;
218             case 5:
219                 context->drawImage(canvas, args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec),
220                                    args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec), ec);
221                 setDOMException(exec, ec);
222                 break;
223             case 9:
224                 context->drawImage(canvas, FloatRect(args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec),
225                                    args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec)),
226                                    FloatRect(args.at(exec, 5)->toFloat(exec), args.at(exec, 6)->toFloat(exec),
227                                    args.at(exec, 7)->toFloat(exec), args.at(exec, 8)->toFloat(exec)), ec);
228                 setDOMException(exec, ec);
229                 break;
230             default:
231                 return throwError(exec, SyntaxError);
232         }
233     } else {
234         setDOMException(exec, TYPE_MISMATCH_ERR);
235         return 0;
236     }
237     
238     return jsUndefined();    
239 }
240
241 JSValue* JSCanvasRenderingContext2D::drawImageFromRect(ExecState* exec, const ArgList& args)
242
243     CanvasRenderingContext2D* context = impl();
244     
245     JSValue* value = args.at(exec, 0);
246     if (!value->isObject())
247         return throwError(exec, TypeError);
248     JSObject* o = static_cast<JSObject*>(value);
249     
250     if (!o->inherits(&JSHTMLImageElement::s_info))
251         return throwError(exec, TypeError);
252     context->drawImageFromRect(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args.at(exec, 0))->impl()),
253                                args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec),
254                                args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec),
255                                args.at(exec, 5)->toFloat(exec), args.at(exec, 6)->toFloat(exec),
256                                args.at(exec, 7)->toFloat(exec), args.at(exec, 8)->toFloat(exec),
257                                args.at(exec, 9)->toString(exec));    
258     return jsUndefined();    
259 }
260
261 JSValue* JSCanvasRenderingContext2D::setShadow(ExecState* exec, const ArgList& args)
262
263     CanvasRenderingContext2D* context = impl();
264
265     switch (args.size()) {
266         case 3:
267             context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
268                                args.at(exec, 2)->toFloat(exec));
269             break;
270         case 4:
271             if (args.at(exec, 3)->isString())
272                 context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
273                                    args.at(exec, 2)->toFloat(exec), static_cast<JSString*>(args.at(exec, 3))->value());
274             else
275                 context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
276                                    args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec));
277             break;
278         case 5:
279             if (args.at(exec, 3)->isString())
280                 context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
281                                    args.at(exec, 2)->toFloat(exec), static_cast<JSString*>(args.at(exec, 3))->value(),
282                                    args.at(exec, 4)->toFloat(exec));
283             else
284                 context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
285                                    args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec),
286                                    args.at(exec, 4)->toFloat(exec));
287             break;
288         case 7:
289             context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
290                                args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec),
291                                args.at(exec, 4)->toFloat(exec), args.at(exec, 5)->toFloat(exec),
292                                args.at(exec, 6)->toFloat(exec));
293             break;
294         case 8:
295             context->setShadow(args.at(exec, 0)->toFloat(exec), args.at(exec, 1)->toFloat(exec),
296                                args.at(exec, 2)->toFloat(exec), args.at(exec, 3)->toFloat(exec),
297                                args.at(exec, 4)->toFloat(exec), args.at(exec, 5)->toFloat(exec),
298                                args.at(exec, 6)->toFloat(exec), args.at(exec, 7)->toFloat(exec));
299             break;
300         default:
301             return throwError(exec, SyntaxError);
302     }
303     
304     return jsUndefined();    
305 }
306
307 JSValue* JSCanvasRenderingContext2D::createPattern(ExecState* exec, const ArgList& args)
308
309     CanvasRenderingContext2D* context = impl();
310
311     JSValue* value = args.at(exec, 0);
312     if (!value->isObject())
313         return throwError(exec, TypeError);
314     JSObject* o = static_cast<JSObject*>(value);
315
316     if (o->inherits(&JSHTMLImageElement::s_info)) {
317         ExceptionCode ec;
318         JSValue* pattern = toJS(exec,
319             context->createPattern(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args.at(exec, 0))->impl()),
320                                    valueToStringWithNullCheck(exec, args.at(exec, 1)), ec).get());
321         setDOMException(exec, ec);
322         return pattern;
323     }
324     if (o->inherits(&JSHTMLCanvasElement::s_info)) {
325         ExceptionCode ec;
326         JSValue* pattern = toJS(exec,
327             context->createPattern(static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(args.at(exec, 0))->impl()),
328                 valueToStringWithNullCheck(exec, args.at(exec, 1)), ec).get());
329         setDOMException(exec, ec);
330         return pattern;
331     }
332     setDOMException(exec, TYPE_MISMATCH_ERR);
333     return 0;
334 }
335
336 JSValue* JSCanvasRenderingContext2D::putImageData(ExecState* exec, const ArgList& args)
337 {
338     // putImageData has two variants
339     // putImageData(ImageData, x, y)
340     // putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
341     CanvasRenderingContext2D* context = impl();
342
343     ExceptionCode ec = 0;
344     if (args.size() >= 7)
345         context->putImageData(toImageData(args.at(exec, 0)), args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec), 
346                               args.at(exec, 3)->toFloat(exec), args.at(exec, 4)->toFloat(exec), args.at(exec, 5)->toFloat(exec), args.at(exec, 6)->toFloat(exec), ec);
347     else
348         context->putImageData(toImageData(args.at(exec, 0)), args.at(exec, 1)->toFloat(exec), args.at(exec, 2)->toFloat(exec), ec);
349
350     setDOMException(exec, ec);
351     return jsUndefined();
352 }
353
354 } // namespace WebCore