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