• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007, 2009 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 "HTMLVideoElement.h"
32 #include "ImageData.h"
33 #include "JSCanvasGradient.h"
34 #include "JSCanvasPattern.h"
35 #include "JSHTMLCanvasElement.h"
36 #include "JSHTMLImageElement.h"
37 #include "JSHTMLVideoElement.h"
38 #include "JSImageData.h"
39 #include <runtime/Error.h>
40 
41 using namespace JSC;
42 
43 namespace WebCore {
44 
toJS(ExecState * exec,CanvasStyle * style)45 static JSValue toJS(ExecState* exec, CanvasStyle* style)
46 {
47     if (style->canvasGradient())
48         return toJS(exec, style->canvasGradient());
49     if (style->canvasPattern())
50         return toJS(exec, style->canvasPattern());
51     return jsString(exec, style->color());
52 }
53 
toHTMLCanvasStyle(ExecState *,JSValue value)54 static PassRefPtr<CanvasStyle> toHTMLCanvasStyle(ExecState*, JSValue value)
55 {
56     if (value.isString())
57         return CanvasStyle::create(asString(value)->value());
58     if (!value.isObject())
59         return 0;
60     JSObject* object = asObject(value);
61     if (object->inherits(&JSCanvasGradient::s_info))
62         return CanvasStyle::create(static_cast<JSCanvasGradient*>(object)->impl());
63     if (object->inherits(&JSCanvasPattern::s_info))
64         return CanvasStyle::create(static_cast<JSCanvasPattern*>(object)->impl());
65     return 0;
66 }
67 
strokeStyle(ExecState * exec) const68 JSValue JSCanvasRenderingContext2D::strokeStyle(ExecState* exec) const
69 {
70     return toJS(exec, impl()->strokeStyle());
71 }
72 
setStrokeStyle(ExecState * exec,JSValue value)73 void JSCanvasRenderingContext2D::setStrokeStyle(ExecState* exec, JSValue value)
74 {
75     impl()->setStrokeStyle(toHTMLCanvasStyle(exec, value));
76 }
77 
fillStyle(ExecState * exec) const78 JSValue JSCanvasRenderingContext2D::fillStyle(ExecState* exec) const
79 {
80     return toJS(exec, impl()->fillStyle());
81 }
82 
setFillStyle(ExecState * exec,JSValue value)83 void JSCanvasRenderingContext2D::setFillStyle(ExecState* exec, JSValue value)
84 {
85     impl()->setFillStyle(toHTMLCanvasStyle(exec, value));
86 }
87 
setFillColor(ExecState * exec,const ArgList & args)88 JSValue JSCanvasRenderingContext2D::setFillColor(ExecState* exec, const ArgList& args)
89 {
90     CanvasRenderingContext2D* context = impl();
91 
92     // string arg = named color
93     // number arg = gray color
94     // string arg, number arg = named color, alpha
95     // number arg, number arg = gray color, alpha
96     // 4 args = r, g, b, a
97     // 5 args = c, m, y, k, a
98     switch (args.size()) {
99         case 1:
100             if (args.at(0).isString())
101                 context->setFillColor(asString(args.at(0))->value());
102             else
103                 context->setFillColor(args.at(0).toFloat(exec));
104             break;
105         case 2:
106             if (args.at(0).isString())
107                 context->setFillColor(asString(args.at(0))->value(), args.at(1).toFloat(exec));
108             else
109                 context->setFillColor(args.at(0).toFloat(exec), args.at(1).toFloat(exec));
110             break;
111         case 4:
112             context->setFillColor(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
113                                   args.at(2).toFloat(exec), args.at(3).toFloat(exec));
114             break;
115         case 5:
116             context->setFillColor(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
117                                   args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec));
118             break;
119         default:
120             return throwError(exec, SyntaxError);
121     }
122     return jsUndefined();
123 }
124 
setStrokeColor(ExecState * exec,const ArgList & args)125 JSValue JSCanvasRenderingContext2D::setStrokeColor(ExecState* exec, const ArgList& args)
126 {
127     CanvasRenderingContext2D* context = impl();
128 
129     // string arg = named color
130     // number arg = gray color
131     // string arg, number arg = named color, alpha
132     // number arg, number arg = gray color, alpha
133     // 4 args = r, g, b, a
134     // 5 args = c, m, y, k, a
135     switch (args.size()) {
136         case 1:
137             if (args.at(0).isString())
138                 context->setStrokeColor(asString(args.at(0))->value());
139             else
140                 context->setStrokeColor(args.at(0).toFloat(exec));
141             break;
142         case 2:
143             if (args.at(0).isString())
144                 context->setStrokeColor(asString(args.at(0))->value(), args.at(1).toFloat(exec));
145             else
146                 context->setStrokeColor(args.at(0).toFloat(exec), args.at(1).toFloat(exec));
147             break;
148         case 4:
149             context->setStrokeColor(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
150                                     args.at(2).toFloat(exec), args.at(3).toFloat(exec));
151             break;
152         case 5:
153             context->setStrokeColor(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
154                                     args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec));
155             break;
156         default:
157             return throwError(exec, SyntaxError);
158     }
159 
160     return jsUndefined();
161 }
162 
strokeRect(ExecState * exec,const ArgList & args)163 JSValue JSCanvasRenderingContext2D::strokeRect(ExecState* exec, const ArgList& args)
164 {
165     CanvasRenderingContext2D* context = impl();
166 
167     if (args.size() <= 4)
168         context->strokeRect(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
169                             args.at(2).toFloat(exec), args.at(3).toFloat(exec));
170     else
171         context->strokeRect(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
172                             args.at(2).toFloat(exec), args.at(3).toFloat(exec), args.at(4).toFloat(exec));
173 
174     return jsUndefined();
175 }
176 
drawImage(ExecState * exec,const ArgList & args)177 JSValue JSCanvasRenderingContext2D::drawImage(ExecState* exec, const ArgList& 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.at(0);
188     if (!value.isObject())
189         return throwError(exec, TypeError);
190     JSObject* o = asObject(value);
191 
192     ExceptionCode ec = 0;
193     if (o->inherits(&JSHTMLImageElement::s_info)) {
194         HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl());
195         switch (args.size()) {
196             case 3:
197                 context->drawImage(imgElt, args.at(1).toFloat(exec), args.at(2).toFloat(exec));
198                 break;
199             case 5:
200                 context->drawImage(imgElt, args.at(1).toFloat(exec), args.at(2).toFloat(exec),
201                                    args.at(3).toFloat(exec), args.at(4).toFloat(exec), ec);
202                 setDOMException(exec, ec);
203                 break;
204             case 9:
205                 context->drawImage(imgElt, FloatRect(args.at(1).toFloat(exec), args.at(2).toFloat(exec),
206                                    args.at(3).toFloat(exec), args.at(4).toFloat(exec)),
207                                    FloatRect(args.at(5).toFloat(exec), args.at(6).toFloat(exec),
208                                    args.at(7).toFloat(exec), args.at(8).toFloat(exec)), ec);
209                 setDOMException(exec, ec);
210                 break;
211             default:
212                 return throwError(exec, SyntaxError);
213         }
214     } else if (o->inherits(&JSHTMLCanvasElement::s_info)) {
215         HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl());
216         switch (args.size()) {
217             case 3:
218                 context->drawImage(canvas, args.at(1).toFloat(exec), args.at(2).toFloat(exec));
219                 break;
220             case 5:
221                 context->drawImage(canvas, args.at(1).toFloat(exec), args.at(2).toFloat(exec),
222                                    args.at(3).toFloat(exec), args.at(4).toFloat(exec), ec);
223                 setDOMException(exec, ec);
224                 break;
225             case 9:
226                 context->drawImage(canvas, FloatRect(args.at(1).toFloat(exec), args.at(2).toFloat(exec),
227                                    args.at(3).toFloat(exec), args.at(4).toFloat(exec)),
228                                    FloatRect(args.at(5).toFloat(exec), args.at(6).toFloat(exec),
229                                    args.at(7).toFloat(exec), args.at(8).toFloat(exec)), ec);
230                 setDOMException(exec, ec);
231                 break;
232             default:
233                 return throwError(exec, SyntaxError);
234         }
235 #if ENABLE(VIDEO)
236     } else if (o->inherits(&JSHTMLVideoElement::s_info)) {
237             HTMLVideoElement* video = static_cast<HTMLVideoElement*>(static_cast<JSHTMLElement*>(o)->impl());
238             switch (args.size()) {
239                 case 3:
240                     context->drawImage(video, args.at(1).toFloat(exec), args.at(2).toFloat(exec));
241                     break;
242                 case 5:
243                     context->drawImage(video, args.at(1).toFloat(exec), args.at(2).toFloat(exec),
244                                        args.at(3).toFloat(exec), args.at(4).toFloat(exec), ec);
245                     setDOMException(exec, ec);
246                     break;
247                 case 9:
248                     context->drawImage(video, FloatRect(args.at(1).toFloat(exec), args.at(2).toFloat(exec),
249                                        args.at(3).toFloat(exec), args.at(4).toFloat(exec)),
250                                        FloatRect(args.at(5).toFloat(exec), args.at(6).toFloat(exec),
251                                        args.at(7).toFloat(exec), args.at(8).toFloat(exec)), ec);
252                     setDOMException(exec, ec);
253                     break;
254                 default:
255                     return throwError(exec, SyntaxError);
256         }
257 #endif
258     } else {
259         setDOMException(exec, TYPE_MISMATCH_ERR);
260     }
261 
262     return jsUndefined();
263 }
264 
drawImageFromRect(ExecState * exec,const ArgList & args)265 JSValue JSCanvasRenderingContext2D::drawImageFromRect(ExecState* exec, const ArgList& args)
266 {
267     CanvasRenderingContext2D* context = impl();
268 
269     JSValue value = args.at(0);
270     if (!value.isObject())
271         return throwError(exec, TypeError);
272     JSObject* o = asObject(value);
273 
274     if (!o->inherits(&JSHTMLImageElement::s_info))
275         return throwError(exec, TypeError);
276     context->drawImageFromRect(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()),
277                                args.at(1).toFloat(exec), args.at(2).toFloat(exec),
278                                args.at(3).toFloat(exec), args.at(4).toFloat(exec),
279                                args.at(5).toFloat(exec), args.at(6).toFloat(exec),
280                                args.at(7).toFloat(exec), args.at(8).toFloat(exec),
281                                args.at(9).toString(exec));
282     return jsUndefined();
283 }
284 
setShadow(ExecState * exec,const ArgList & args)285 JSValue JSCanvasRenderingContext2D::setShadow(ExecState* exec, const ArgList& args)
286 {
287     CanvasRenderingContext2D* context = impl();
288 
289     switch (args.size()) {
290         case 3:
291             context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
292                                args.at(2).toFloat(exec));
293             break;
294         case 4:
295             if (args.at(3).isString())
296                 context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
297                                    args.at(2).toFloat(exec), asString(args.at(3))->value());
298             else
299                 context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
300                                    args.at(2).toFloat(exec), args.at(3).toFloat(exec));
301             break;
302         case 5:
303             if (args.at(3).isString())
304                 context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
305                                    args.at(2).toFloat(exec), asString(args.at(3))->value(),
306                                    args.at(4).toFloat(exec));
307             else
308                 context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
309                                    args.at(2).toFloat(exec), args.at(3).toFloat(exec),
310                                    args.at(4).toFloat(exec));
311             break;
312         case 7:
313             context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
314                                args.at(2).toFloat(exec), args.at(3).toFloat(exec),
315                                args.at(4).toFloat(exec), args.at(5).toFloat(exec),
316                                args.at(6).toFloat(exec));
317             break;
318         case 8:
319             context->setShadow(args.at(0).toFloat(exec), args.at(1).toFloat(exec),
320                                args.at(2).toFloat(exec), args.at(3).toFloat(exec),
321                                args.at(4).toFloat(exec), args.at(5).toFloat(exec),
322                                args.at(6).toFloat(exec), args.at(7).toFloat(exec));
323             break;
324         default:
325             return throwError(exec, SyntaxError);
326     }
327 
328     return jsUndefined();
329 }
330 
createPattern(ExecState * exec,const ArgList & args)331 JSValue JSCanvasRenderingContext2D::createPattern(ExecState* exec, const ArgList& args)
332 {
333     CanvasRenderingContext2D* context = impl();
334 
335     JSValue value = args.at(0);
336     if (!value.isObject())
337         return throwError(exec, TypeError);
338     JSObject* o = asObject(value);
339 
340     if (o->inherits(&JSHTMLImageElement::s_info)) {
341         ExceptionCode ec;
342         JSValue pattern = toJS(exec,
343             context->createPattern(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()),
344                                    valueToStringWithNullCheck(exec, args.at(1)), ec).get());
345         setDOMException(exec, ec);
346         return pattern;
347     }
348     if (o->inherits(&JSHTMLCanvasElement::s_info)) {
349         ExceptionCode ec;
350         JSValue pattern = toJS(exec,
351             context->createPattern(static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl()),
352                 valueToStringWithNullCheck(exec, args.at(1)), ec).get());
353         setDOMException(exec, ec);
354         return pattern;
355     }
356     setDOMException(exec, TYPE_MISMATCH_ERR);
357     return jsUndefined();
358 }
359 
putImageData(ExecState * exec,const ArgList & args)360 JSValue JSCanvasRenderingContext2D::putImageData(ExecState* exec, const ArgList& args)
361 {
362     // putImageData has two variants
363     // putImageData(ImageData, x, y)
364     // putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
365     CanvasRenderingContext2D* context = impl();
366 
367     ExceptionCode ec = 0;
368     if (args.size() >= 7)
369         context->putImageData(toImageData(args.at(0)), args.at(1).toFloat(exec), args.at(2).toFloat(exec),
370                               args.at(3).toFloat(exec), args.at(4).toFloat(exec), args.at(5).toFloat(exec), args.at(6).toFloat(exec), ec);
371     else
372         context->putImageData(toImageData(args.at(0)), args.at(1).toFloat(exec), args.at(2).toFloat(exec), ec);
373 
374     setDOMException(exec, ec);
375     return jsUndefined();
376 }
377 
fillText(ExecState * exec,const ArgList & args)378 JSValue JSCanvasRenderingContext2D::fillText(ExecState* exec, const ArgList& args)
379 {
380     CanvasRenderingContext2D* context = impl();
381 
382     // string arg = text to draw
383     // number arg = x
384     // number arg = y
385     // optional number arg = maxWidth
386     if (args.size() < 3 || args.size() > 4)
387         return throwError(exec, SyntaxError);
388 
389     if (args.size() == 4)
390         context->fillText(args.at(0).toString(exec), args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec));
391     else
392         context->fillText(args.at(0).toString(exec), args.at(1).toFloat(exec), args.at(2).toFloat(exec));
393     return jsUndefined();
394 }
395 
strokeText(ExecState * exec,const ArgList & args)396 JSValue JSCanvasRenderingContext2D::strokeText(ExecState* exec, const ArgList& args)
397 {
398     CanvasRenderingContext2D* context = impl();
399 
400     // string arg = text to draw
401     // number arg = x
402     // number arg = y
403     // optional number arg = maxWidth
404     if (args.size() < 3 || args.size() > 4)
405         return throwError(exec, SyntaxError);
406 
407     if (args.size() == 4)
408         context->strokeText(args.at(0).toString(exec), args.at(1).toFloat(exec), args.at(2).toFloat(exec), args.at(3).toFloat(exec));
409     else
410         context->strokeText(args.at(0).toString(exec), args.at(1).toFloat(exec), args.at(2).toFloat(exec));
411     return jsUndefined();
412 }
413 
414 } // namespace WebCore
415