• 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.isObject())
57         return 0;
58     JSObject* object = asObject(value);
59     if (object->inherits(&JSCanvasGradient::s_info))
60         return CanvasStyle::createFromGradient(static_cast<JSCanvasGradient*>(object)->impl());
61     if (object->inherits(&JSCanvasPattern::s_info))
62         return CanvasStyle::createFromPattern(static_cast<JSCanvasPattern*>(object)->impl());
63     return 0;
64 }
65 
strokeStyle(ExecState * exec) const66 JSValue JSCanvasRenderingContext2D::strokeStyle(ExecState* exec) const
67 {
68     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
69     return toJS(exec, context->strokeStyle());
70 }
71 
setStrokeStyle(ExecState * exec,JSValue value)72 void JSCanvasRenderingContext2D::setStrokeStyle(ExecState* exec, JSValue value)
73 {
74     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
75     if (value.isString()) {
76         context->setStrokeColor(ustringToString(asString(value)->value(exec)));
77         return;
78     }
79     context->setStrokeStyle(toHTMLCanvasStyle(exec, value));
80 }
81 
fillStyle(ExecState * exec) const82 JSValue JSCanvasRenderingContext2D::fillStyle(ExecState* exec) const
83 {
84     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
85     return toJS(exec, context->fillStyle());
86 }
87 
setFillStyle(ExecState * exec,JSValue value)88 void JSCanvasRenderingContext2D::setFillStyle(ExecState* exec, JSValue value)
89 {
90     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
91     if (value.isString()) {
92         context->setFillColor(ustringToString(asString(value)->value(exec)));
93         return;
94     }
95     context->setFillStyle(toHTMLCanvasStyle(exec, value));
96 }
97 
setFillColor(ExecState * exec)98 JSValue JSCanvasRenderingContext2D::setFillColor(ExecState* exec)
99 {
100     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
101 
102     // string arg = named color
103     // number arg = gray color
104     // string arg, number arg = named color, alpha
105     // number arg, number arg = gray color, alpha
106     // 4 args = r, g, b, a
107     // 5 args = c, m, y, k, a
108     switch (exec->argumentCount()) {
109         case 1:
110             if (exec->argument(0).isString())
111                 context->setFillColor(ustringToString(asString(exec->argument(0))->value(exec)));
112             else
113                 context->setFillColor(exec->argument(0).toFloat(exec));
114             break;
115         case 2:
116             if (exec->argument(0).isString())
117                 context->setFillColor(ustringToString(asString(exec->argument(0))->value(exec)), exec->argument(1).toFloat(exec));
118             else
119                 context->setFillColor(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec));
120             break;
121         case 4:
122             context->setFillColor(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
123                                   exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec));
124             break;
125         case 5:
126             context->setFillColor(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
127                                   exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec));
128             break;
129         default:
130             return throwSyntaxError(exec);
131     }
132     return jsUndefined();
133 }
134 
setStrokeColor(ExecState * exec)135 JSValue JSCanvasRenderingContext2D::setStrokeColor(ExecState* exec)
136 {
137     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
138 
139     // string arg = named color
140     // number arg = gray color
141     // string arg, number arg = named color, alpha
142     // number arg, number arg = gray color, alpha
143     // 4 args = r, g, b, a
144     // 5 args = c, m, y, k, a
145     switch (exec->argumentCount()) {
146         case 1:
147             if (exec->argument(0).isString())
148                 context->setStrokeColor(ustringToString(asString(exec->argument(0))->value(exec)));
149             else
150                 context->setStrokeColor(exec->argument(0).toFloat(exec));
151             break;
152         case 2:
153             if (exec->argument(0).isString())
154                 context->setStrokeColor(ustringToString(asString(exec->argument(0))->value(exec)), exec->argument(1).toFloat(exec));
155             else
156                 context->setStrokeColor(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec));
157             break;
158         case 4:
159             context->setStrokeColor(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
160                                     exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec));
161             break;
162         case 5:
163             context->setStrokeColor(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
164                                     exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec));
165             break;
166         default:
167             return throwSyntaxError(exec);
168     }
169 
170     return jsUndefined();
171 }
172 
strokeRect(ExecState * exec)173 JSValue JSCanvasRenderingContext2D::strokeRect(ExecState* exec)
174 {
175     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
176 
177     if (exec->argumentCount() <= 4)
178         context->strokeRect(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
179                             exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec));
180     else
181         context->strokeRect(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
182                             exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec));
183 
184     return jsUndefined();
185 }
186 
drawImage(ExecState * exec)187 JSValue JSCanvasRenderingContext2D::drawImage(ExecState* exec)
188 {
189     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
190 
191     // DrawImage has three variants:
192     //     drawImage(img, dx, dy)
193     //     drawImage(img, dx, dy, dw, dh)
194     //     drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
195     // Composite operation is specified with globalCompositeOperation.
196     // The img parameter can be a <img> or <canvas> element.
197     JSValue value = exec->argument(0);
198     if (value.isNull()) {
199         setDOMException(exec, TYPE_MISMATCH_ERR);
200         return jsUndefined();
201     }
202     if (!value.isObject())
203         return throwTypeError(exec);
204 
205     JSObject* o = asObject(value);
206     ExceptionCode ec = 0;
207     if (o->inherits(&JSHTMLImageElement::s_info)) {
208         HTMLImageElement* imgElt = static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl());
209         switch (exec->argumentCount()) {
210             case 3:
211                 context->drawImage(imgElt, exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec), ec);
212                 break;
213             case 5:
214                 context->drawImage(imgElt, exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
215                                    exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec), ec);
216                 setDOMException(exec, ec);
217                 break;
218             case 9:
219                 context->drawImage(imgElt, FloatRect(exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
220                                    exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec)),
221                                    FloatRect(exec->argument(5).toFloat(exec), exec->argument(6).toFloat(exec),
222                                    exec->argument(7).toFloat(exec), exec->argument(8).toFloat(exec)), ec);
223                 setDOMException(exec, ec);
224                 break;
225             default:
226                 return throwSyntaxError(exec);
227         }
228     } else if (o->inherits(&JSHTMLCanvasElement::s_info)) {
229         HTMLCanvasElement* canvas = static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl());
230         switch (exec->argumentCount()) {
231             case 3:
232                 context->drawImage(canvas, exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec), ec);
233                 setDOMException(exec, ec);
234                 break;
235             case 5:
236                 context->drawImage(canvas, exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
237                                    exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec), ec);
238                 setDOMException(exec, ec);
239                 break;
240             case 9:
241                 context->drawImage(canvas, FloatRect(exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
242                                    exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec)),
243                                    FloatRect(exec->argument(5).toFloat(exec), exec->argument(6).toFloat(exec),
244                                    exec->argument(7).toFloat(exec), exec->argument(8).toFloat(exec)), ec);
245                 setDOMException(exec, ec);
246                 break;
247             default:
248                 return throwSyntaxError(exec);
249         }
250 #if ENABLE(VIDEO)
251     } else if (o->inherits(&JSHTMLVideoElement::s_info)) {
252             HTMLVideoElement* video = static_cast<HTMLVideoElement*>(static_cast<JSHTMLElement*>(o)->impl());
253             switch (exec->argumentCount()) {
254                 case 3:
255                     context->drawImage(video, exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec), ec);
256                     break;
257                 case 5:
258                     context->drawImage(video, exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
259                                        exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec), ec);
260                     setDOMException(exec, ec);
261                     break;
262                 case 9:
263                     context->drawImage(video, FloatRect(exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
264                                        exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec)),
265                                        FloatRect(exec->argument(5).toFloat(exec), exec->argument(6).toFloat(exec),
266                                        exec->argument(7).toFloat(exec), exec->argument(8).toFloat(exec)), ec);
267                     setDOMException(exec, ec);
268                     break;
269                 default:
270                     return throwSyntaxError(exec);
271         }
272 #endif
273     } else
274         return throwTypeError(exec);
275 
276     return jsUndefined();
277 }
278 
drawImageFromRect(ExecState * exec)279 JSValue JSCanvasRenderingContext2D::drawImageFromRect(ExecState* exec)
280 {
281     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
282 
283     JSValue value = exec->argument(0);
284     if (!value.isObject())
285         return throwTypeError(exec);
286     JSObject* o = asObject(value);
287 
288     if (!o->inherits(&JSHTMLImageElement::s_info))
289         return throwTypeError(exec);
290     context->drawImageFromRect(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()),
291                                exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
292                                exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec),
293                                exec->argument(5).toFloat(exec), exec->argument(6).toFloat(exec),
294                                exec->argument(7).toFloat(exec), exec->argument(8).toFloat(exec),
295                                ustringToString(exec->argument(9).toString(exec)));
296     return jsUndefined();
297 }
298 
setShadow(ExecState * exec)299 JSValue JSCanvasRenderingContext2D::setShadow(ExecState* exec)
300 {
301     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
302 
303     switch (exec->argumentCount()) {
304         case 3:
305             context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
306                                exec->argument(2).toFloat(exec));
307             break;
308         case 4:
309             if (exec->argument(3).isString())
310                 context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
311                                    exec->argument(2).toFloat(exec), ustringToString(asString(exec->argument(3))->value(exec)));
312             else
313                 context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
314                                    exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec));
315             break;
316         case 5:
317             if (exec->argument(3).isString())
318                 context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
319                                    exec->argument(2).toFloat(exec), ustringToString(asString(exec->argument(3))->value(exec)),
320                                    exec->argument(4).toFloat(exec));
321             else
322                 context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
323                                    exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec),
324                                    exec->argument(4).toFloat(exec));
325             break;
326         case 7:
327             context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
328                                exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec),
329                                exec->argument(4).toFloat(exec), exec->argument(5).toFloat(exec),
330                                exec->argument(6).toFloat(exec));
331             break;
332         case 8:
333             context->setShadow(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec),
334                                exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec),
335                                exec->argument(4).toFloat(exec), exec->argument(5).toFloat(exec),
336                                exec->argument(6).toFloat(exec), exec->argument(7).toFloat(exec));
337             break;
338         default:
339             return throwSyntaxError(exec);
340     }
341 
342     return jsUndefined();
343 }
344 
createPattern(ExecState * exec)345 JSValue JSCanvasRenderingContext2D::createPattern(ExecState* exec)
346 {
347     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
348 
349     JSValue value = exec->argument(0);
350     if (!value.isObject()) {
351         setDOMException(exec, TYPE_MISMATCH_ERR);
352         return jsUndefined();
353     }
354     JSObject* o = asObject(value);
355 
356     if (o->inherits(&JSHTMLImageElement::s_info)) {
357         ExceptionCode ec;
358         JSValue pattern = toJS(exec,
359             context->createPattern(static_cast<HTMLImageElement*>(static_cast<JSHTMLElement*>(o)->impl()),
360                                    valueToStringWithNullCheck(exec, exec->argument(1)), ec).get());
361         setDOMException(exec, ec);
362         return pattern;
363     }
364     if (o->inherits(&JSHTMLCanvasElement::s_info)) {
365         ExceptionCode ec;
366         JSValue pattern = toJS(exec,
367             context->createPattern(static_cast<HTMLCanvasElement*>(static_cast<JSHTMLElement*>(o)->impl()),
368                 valueToStringWithNullCheck(exec, exec->argument(1)), ec).get());
369         setDOMException(exec, ec);
370         return pattern;
371     }
372     setDOMException(exec, TYPE_MISMATCH_ERR);
373     return jsUndefined();
374 }
375 
createImageData(ExecState * exec)376 JSValue JSCanvasRenderingContext2D::createImageData(ExecState* exec)
377 {
378     // createImageData has two variants
379     // createImageData(ImageData)
380     // createImageData(width, height)
381     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
382     RefPtr<ImageData> imageData = 0;
383 
384     ExceptionCode ec = 0;
385     if (exec->argumentCount() == 1)
386         imageData = context->createImageData(toImageData(exec->argument(0)), ec);
387     else if (exec->argumentCount() == 2)
388         imageData = context->createImageData(exec->argument(0).toFloat(exec), exec->argument(1).toFloat(exec), ec);
389 
390     setDOMException(exec, ec);
391     return toJS(exec, globalObject(), WTF::getPtr(imageData));
392 }
393 
putImageData(ExecState * exec)394 JSValue JSCanvasRenderingContext2D::putImageData(ExecState* exec)
395 {
396     // putImageData has two variants
397     // putImageData(ImageData, x, y)
398     // putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
399     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
400 
401     ExceptionCode ec = 0;
402     if (exec->argumentCount() >= 7)
403         context->putImageData(toImageData(exec->argument(0)), exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec),
404                               exec->argument(3).toFloat(exec), exec->argument(4).toFloat(exec), exec->argument(5).toFloat(exec), exec->argument(6).toFloat(exec), ec);
405     else
406         context->putImageData(toImageData(exec->argument(0)), exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec), ec);
407 
408     setDOMException(exec, ec);
409     return jsUndefined();
410 }
411 
fillText(ExecState * exec)412 JSValue JSCanvasRenderingContext2D::fillText(ExecState* exec)
413 {
414     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
415 
416     // string arg = text to draw
417     // number arg = x
418     // number arg = y
419     // optional number arg = maxWidth
420     if (exec->argumentCount() < 3 || exec->argumentCount() > 4)
421         return throwSyntaxError(exec);
422 
423     if (exec->argumentCount() == 4)
424         context->fillText(ustringToString(exec->argument(0).toString(exec)), exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec));
425     else
426         context->fillText(ustringToString(exec->argument(0).toString(exec)), exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec));
427     return jsUndefined();
428 }
429 
strokeText(ExecState * exec)430 JSValue JSCanvasRenderingContext2D::strokeText(ExecState* exec)
431 {
432     CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl());
433 
434     // string arg = text to draw
435     // number arg = x
436     // number arg = y
437     // optional number arg = maxWidth
438     if (exec->argumentCount() < 3 || exec->argumentCount() > 4)
439         return throwSyntaxError(exec);
440 
441     if (exec->argumentCount() == 4)
442         context->strokeText(ustringToString(exec->argument(0).toString(exec)), exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec), exec->argument(3).toFloat(exec));
443     else
444         context->strokeText(ustringToString(exec->argument(0).toString(exec)), exec->argument(1).toFloat(exec), exec->argument(2).toFloat(exec));
445     return jsUndefined();
446 }
447 
448 } // namespace WebCore
449