LayoutTests:
[WebKit-https.git] / WebCore / bindings / js / JSCanvasRenderingContext2DBase.cpp
1 /*
2  * Copyright (C) 2006 Apple Computer, Inc.
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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 #include "config.h"
21 #include "JSCanvasRenderingContext2DBase.h"
22
23 #include "CanvasGradient.h"
24 #include "CanvasPattern.h"
25 #include "CanvasRenderingContext2D.h"
26 #include "CanvasStyle.h"
27 #include "HTMLCanvasElement.h"
28 #include "JSCanvasGradient.h"
29 #include "JSCanvasPattern.h"
30 #include "html_imageimpl.h"
31 #include "kjs_html.h"
32
33 #include "JSCanvasRenderingContext2DBaseTable.cpp"
34
35 using namespace KJS;
36
37 namespace WebCore {
38
39 /*
40 @begin JSCanvasRenderingContext2DBaseProtoTable 7
41   setStrokeColor           WebCore::JSCanvasRenderingContext2DBase::SetStrokeColor              DontDelete|Function 1
42   setFillColor             WebCore::JSCanvasRenderingContext2DBase::SetFillColor                DontDelete|Function 1
43   strokeRect               WebCore::JSCanvasRenderingContext2DBase::StrokeRect                  DontDelete|Function 4
44   drawImage                WebCore::JSCanvasRenderingContext2DBase::DrawImage                   DontDelete|Function 3
45   drawImageFromRect        WebCore::JSCanvasRenderingContext2DBase::DrawImageFromRect           DontDelete|Function 10
46   setShadow                WebCore::JSCanvasRenderingContext2DBase::SetShadow                   DontDelete|Function 3
47   createPattern            WebCore::JSCanvasRenderingContext2DBase::CreatePattern               DontDelete|Function 2
48 @end
49 @begin JSCanvasRenderingContext2DBaseTable 2
50   strokeStyle              WebCore::JSCanvasRenderingContext2DBase::StrokeStyle                 DontDelete
51   fillStyle                WebCore::JSCanvasRenderingContext2DBase::FillStyle                   DontDelete
52 @end
53 */
54
55 KJS_IMPLEMENT_PROTOFUNC(JSCanvasRenderingContext2DBaseProtoFunc)
56 KJS_IMPLEMENT_PROTOTYPE("CanvasRenderingContext2DBase", JSCanvasRenderingContext2DBaseProto, JSCanvasRenderingContext2DBaseProtoFunc)
57
58 JSValue* JSCanvasRenderingContext2DBaseProtoFunc::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
59 {
60     if (!thisObj->inherits(&JSCanvasRenderingContext2DBase::info))
61         return throwError(exec, TypeError);
62
63     CanvasRenderingContext2D* context = static_cast<JSCanvasRenderingContext2DBase*>(thisObj)->impl();
64     
65     switch (id) {
66         case JSCanvasRenderingContext2DBase::SetStrokeColor:
67             // string arg = named color
68             // number arg = gray color
69             // string arg, number arg = named color, alpha
70             // number arg, number arg = gray color, alpha
71             // 4 args = r, g, b, a
72             // 5 args = c, m, y, k, a
73             switch (args.size()) {
74                 case 1:
75                     if (args[0]->isString())
76                         context->setStrokeColor(args[0]->toString(exec));
77                     else
78                         context->setStrokeColor(args[0]->toNumber(exec));
79                     break;
80                 case 2:
81                     if (args[0]->isString())
82                         context->setStrokeColor(args[0]->toString(exec), args[1]->toNumber(exec));
83                     else
84                         context->setStrokeColor(args[0]->toNumber(exec), args[1]->toNumber(exec));
85                     break;
86                 case 4:
87                     context->setStrokeColor(args[0]->toNumber(exec), args[1]->toNumber(exec),
88                         args[2]->toNumber(exec), args[3]->toNumber(exec));
89                     break;
90                 case 5:
91                     context->setStrokeColor(args[0]->toNumber(exec), args[1]->toNumber(exec),
92                         args[2]->toNumber(exec), args[3]->toNumber(exec), args[4]->toNumber(exec));
93                     break;
94                 default:
95                     return throwError(exec, SyntaxError);
96             }
97             break;
98         case JSCanvasRenderingContext2DBase::SetFillColor:
99             // string arg = named color
100             // number arg = gray color
101             // string arg, number arg = named color, alpha
102             // number arg, number arg = gray color, alpha
103             // 4 args = r, g, b, a
104             // 5 args = c, m, y, k, a
105             switch (args.size()) {
106                 case 1:
107                     if (args[0]->isString())
108                         context->setFillColor(args[0]->toString(exec));
109                     else
110                         context->setFillColor(args[0]->toNumber(exec));
111                     break;
112                 case 2:
113                     if (args[0]->isString())
114                         context->setFillColor(args[0]->toString(exec), args[1]->toNumber(exec));
115                     else
116                         context->setFillColor(args[0]->toNumber(exec), args[1]->toNumber(exec));
117                     break;
118                 case 4:
119                     context->setFillColor(args[0]->toNumber(exec), args[1]->toNumber(exec),
120                         args[2]->toNumber(exec), args[3]->toNumber(exec));
121                     break;
122                 case 5:
123                     context->setFillColor(args[0]->toNumber(exec), args[1]->toNumber(exec),
124                         args[2]->toNumber(exec), args[3]->toNumber(exec), args[4]->toNumber(exec));
125                     break;
126                 default:
127                     return throwError(exec, SyntaxError);
128             }
129             break;
130         case JSCanvasRenderingContext2DBase::StrokeRect:
131             if (args.size() <= 4)
132                 context->strokeRect(args[0]->toNumber(exec), args[1]->toNumber(exec),
133                     args[2]->toNumber(exec), args[3]->toNumber(exec));
134             else
135                 context->strokeRect(args[0]->toNumber(exec), args[1]->toNumber(exec),
136                     args[2]->toNumber(exec), args[3]->toNumber(exec), args[4]->toNumber(exec));
137             break;
138         case JSCanvasRenderingContext2DBase::SetShadow:
139             switch (args.size()) {
140                 case 3:
141                     context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
142                         args[2]->toNumber(exec));
143                     break;
144                 case 4:
145                     if (args[3]->isString())
146                         context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
147                             args[2]->toNumber(exec), args[3]->toString(exec));
148                     else
149                         context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
150                             args[2]->toNumber(exec), args[3]->toNumber(exec));
151                     break;
152                 case 5:
153                     if (args[3]->isString())
154                         context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
155                             args[2]->toNumber(exec), args[3]->toString(exec),
156                             args[4]->toNumber(exec));
157                     else
158                         context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
159                             args[2]->toNumber(exec), args[3]->toNumber(exec),
160                             args[4]->toNumber(exec));
161                     break;
162                 case 7:
163                     context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
164                         args[2]->toNumber(exec), args[3]->toNumber(exec),
165                         args[4]->toNumber(exec), args[5]->toNumber(exec),
166                         args[6]->toNumber(exec));
167                     break;
168                 case 8:
169                     context->setShadow(args[0]->toNumber(exec), args[1]->toNumber(exec),
170                         args[2]->toNumber(exec), args[3]->toNumber(exec),
171                         args[4]->toNumber(exec), args[5]->toNumber(exec),
172                         args[6]->toNumber(exec), args[7]->toNumber(exec));
173                     break;
174                 default:
175                     return throwError(exec, SyntaxError);
176             }
177             break;
178         case JSCanvasRenderingContext2DBase::DrawImage: {
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             JSObject* o = static_cast<JSObject*>(args[0]);
186             if (!o->isObject())
187                 return throwError(exec, TypeError);
188             if (o->inherits(&JSHTMLElement::img_info)) {
189                 HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl());
190                 switch (args.size()) {
191                     case 3:
192                         context->drawImage(imgElt, args[1]->toNumber(exec), args[2]->toNumber(exec));
193                         break;
194                     case 5:
195                         context->drawImage(imgElt, args[1]->toNumber(exec), args[2]->toNumber(exec),
196                             args[3]->toNumber(exec), args[4]->toNumber(exec));
197                         break;
198                     case 9:
199                         context->drawImage(imgElt, args[1]->toNumber(exec), args[2]->toNumber(exec),
200                             args[3]->toNumber(exec), args[4]->toNumber(exec),
201                             args[5]->toNumber(exec), args[6]->toNumber(exec),
202                             args[7]->toNumber(exec), args[8]->toNumber(exec));
203                         break;
204                     default:
205                         return throwError(exec, SyntaxError);
206                 }
207                 break;
208             }
209             if (o->inherits(&JSHTMLElement::canvas_info)) {
210                 HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(args[0])->impl());
211                 switch (args.size()) {
212                     case 3:
213                         context->drawImage(canvas, args[1]->toNumber(exec), args[2]->toNumber(exec));
214                         break;
215                     case 5:
216                         context->drawImage(canvas, args[1]->toNumber(exec), args[2]->toNumber(exec),
217                             args[3]->toNumber(exec), args[4]->toNumber(exec));
218                         break;
219                     case 9:
220                         context->drawImage(canvas, args[1]->toNumber(exec), args[2]->toNumber(exec),
221                             args[3]->toNumber(exec), args[4]->toNumber(exec),
222                             args[5]->toNumber(exec), args[6]->toNumber(exec),
223                             args[7]->toNumber(exec), args[8]->toNumber(exec));
224                         break;
225                     default:
226                         return throwError(exec, SyntaxError);
227                 }
228                 break;
229             }
230             return throwError(exec, TypeError);
231         }
232         case JSCanvasRenderingContext2DBase::DrawImageFromRect: {
233             JSObject* o = static_cast<JSObject*>(args[0]);
234             if (!o->isObject())
235                 return throwError(exec, TypeError);
236             if (!o->inherits(&JSHTMLElement::img_info))
237                 return throwError(exec, TypeError);
238             context->drawImageFromRect(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl()),
239                 args[1]->toNumber(exec), args[2]->toNumber(exec),
240                 args[3]->toNumber(exec), args[4]->toNumber(exec),
241                 args[5]->toNumber(exec), args[6]->toNumber(exec),
242                 args[7]->toNumber(exec), args[8]->toNumber(exec),
243                 args[9]->toString(exec));
244             break;
245         }
246         case JSCanvasRenderingContext2DBase::CreatePattern:
247             JSObject* o = static_cast<JSObject*>(args[0]);
248             if (!o->isObject())
249                 return throwError(exec, TypeError);
250             if (!o->inherits(&JSHTMLElement::img_info))
251                 return throwError(exec, TypeError);
252             return toJS(exec,
253                 context->createPattern(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(args[0])->impl()),
254                 args[1]->toString(exec)).get());
255     }
256
257     return jsUndefined();
258 }
259
260 const ClassInfo JSCanvasRenderingContext2DBase::info = { "CanvasRenderingContext2DBase", 0, &JSCanvasRenderingContext2DBaseTable, 0 };
261
262 bool JSCanvasRenderingContext2DBase::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
263 {
264     return getStaticValueSlot<JSCanvasRenderingContext2DBase, DOMObject>
265         (exec, &JSCanvasRenderingContext2DBaseTable, this, propertyName, slot);
266 }
267
268 static JSValue* toJS(ExecState* exec, CanvasStyle* style)
269 {
270     if (style->gradient())
271         return toJS(exec, style->gradient());
272     if (style->pattern())
273         return toJS(exec, style->pattern());
274     return jsString(style->color());
275 }
276
277 static PassRefPtr<CanvasStyle> toHTMLCanvasStyle(ExecState* exec, JSValue* value)
278 {
279     if (value->isString())
280         return new CanvasStyle(value->toString(exec));
281     if (!value->isObject())
282         return 0;
283     JSObject* object = static_cast<JSObject*>(value);
284     if (object->inherits(&JSCanvasGradient::info))
285         return new CanvasStyle(static_cast<JSCanvasGradient*>(object)->impl());
286     if (object->inherits(&JSCanvasPattern::info))
287         return new CanvasStyle(static_cast<JSCanvasPattern*>(object)->impl());
288     return 0;
289 }
290
291 JSValue* JSCanvasRenderingContext2DBase::getValueProperty(ExecState* exec, int token) const
292 {
293     switch (token) {
294         case StrokeStyle:
295             return toJS(exec, m_impl->strokeStyle());        
296         case FillStyle:
297             return toJS(exec, m_impl->fillStyle());        
298     }
299     return 0;
300 }
301
302 void JSCanvasRenderingContext2DBase::put(ExecState* exec, const Identifier& propertyName, JSValue* value, int attr)
303 {
304     lookupPut<JSCanvasRenderingContext2DBase, DOMObject>(exec, propertyName, value, attr, &JSCanvasRenderingContext2DBaseTable, this);
305 }
306
307 void JSCanvasRenderingContext2DBase::putValueProperty(ExecState* exec, int token, JSValue* value, int /*attr*/)
308 {
309     switch (token) {
310         case StrokeStyle:
311             impl()->setStrokeStyle(toHTMLCanvasStyle(exec, value));
312             break;
313         case FillStyle:
314             impl()->setFillStyle(toHTMLCanvasStyle(exec, value));
315             break;
316     }
317 }
318
319 JSCanvasRenderingContext2DBase::JSCanvasRenderingContext2DBase(ExecState*, PassRefPtr<WebCore::CanvasRenderingContext2D> impl)
320     : m_impl(impl)
321 {
322 }
323
324 JSCanvasRenderingContext2DBase::~JSCanvasRenderingContext2DBase()
325 {
326     ScriptInterpreter::forgetDOMObject(m_impl.get());
327 }
328
329 }