• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "config.h"
32 #include "CanvasRenderingContext2D.h"
33 
34 #include "CanvasGradient.h"
35 #include "CanvasPattern.h"
36 #include "CanvasStyle.h"
37 #include "ExceptionCode.h"
38 #include "FloatRect.h"
39 
40 #include "V8Binding.h"
41 #include "V8CanvasGradient.h"
42 #include "V8CanvasPattern.h"
43 #include "V8CustomBinding.h"
44 #include "V8HTMLCanvasElement.h"
45 #include "V8HTMLImageElement.h"
46 #include "V8HTMLVideoElement.h"
47 #include "V8Proxy.h"
48 
49 namespace WebCore {
50 
toV8(CanvasStyle * style)51 static v8::Handle<v8::Value> toV8(CanvasStyle* style)
52 {
53     if (style->canvasGradient())
54         return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASGRADIENT, style->canvasGradient());
55 
56     if (style->canvasPattern())
57         return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASPATTERN, style->canvasPattern());
58 
59     return v8String(style->color());
60 }
61 
toCanvasStyle(v8::Handle<v8::Value> value)62 static PassRefPtr<CanvasStyle> toCanvasStyle(v8::Handle<v8::Value> value)
63 {
64     if (value->IsString())
65         return CanvasStyle::create(toWebCoreString(value));
66 
67     if (V8CanvasGradient::HasInstance(value))
68         return CanvasStyle::create(V8DOMWrapper::convertDOMWrapperToNative<CanvasGradient>(v8::Handle<v8::Object>::Cast(value)));
69 
70     if (V8CanvasPattern::HasInstance(value))
71         return CanvasStyle::create(V8DOMWrapper::convertDOMWrapperToNative<CanvasPattern>(v8::Handle<v8::Object>::Cast(value)));
72 
73     return 0;
74 }
75 
ACCESSOR_GETTER(CanvasRenderingContext2DStrokeStyle)76 ACCESSOR_GETTER(CanvasRenderingContext2DStrokeStyle)
77 {
78     CanvasRenderingContext2D* impl = V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
79     return toV8(impl->strokeStyle());
80 }
81 
ACCESSOR_SETTER(CanvasRenderingContext2DStrokeStyle)82 ACCESSOR_SETTER(CanvasRenderingContext2DStrokeStyle)
83 {
84     CanvasRenderingContext2D* impl = V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
85     impl->setStrokeStyle(toCanvasStyle(value));
86 }
87 
ACCESSOR_GETTER(CanvasRenderingContext2DFillStyle)88 ACCESSOR_GETTER(CanvasRenderingContext2DFillStyle)
89 {
90     CanvasRenderingContext2D* impl = V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
91     return toV8(impl->fillStyle());
92 }
93 
ACCESSOR_SETTER(CanvasRenderingContext2DFillStyle)94 ACCESSOR_SETTER(CanvasRenderingContext2DFillStyle)
95 {
96     CanvasRenderingContext2D* impl = V8DOMWrapper::convertDOMWrapperToNative<CanvasRenderingContext2D>(info.Holder());
97     impl->setFillStyle(toCanvasStyle(value));
98 }
99 
100 // TODO: SetStrokeColor and SetFillColor are similar except function names,
101 // consolidate them into one.
CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetStrokeColor)102 CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetStrokeColor)
103 {
104     INC_STATS("DOM.CanvasRenderingContext2D.setStrokeColor()");
105     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
106     switch (args.Length()) {
107     case 1:
108         if (args[0]->IsString())
109             context->setStrokeColor(toWebCoreString(args[0]));
110         else
111             context->setStrokeColor(toFloat(args[0]));
112         break;
113     case 2:
114         if (args[0]->IsString())
115             context->setStrokeColor(toWebCoreString(args[0]), toFloat(args[1]));
116         else
117             context->setStrokeColor(toFloat(args[0]), toFloat(args[1]));
118         break;
119     case 4:
120         context->setStrokeColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
121         break;
122     case 5:
123         context->setStrokeColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
124         break;
125     default:
126         V8Proxy::throwError(V8Proxy::SyntaxError, "setStrokeColor: Invalid number of arguments");
127         break;
128     }
129     return v8::Undefined();
130 }
131 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor)132 CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetFillColor)
133 {
134     INC_STATS("DOM.CanvasRenderingContext2D.setFillColor()");
135     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
136     switch (args.Length()) {
137     case 1:
138         if (args[0]->IsString())
139             context->setFillColor(toWebCoreString(args[0]));
140         else
141             context->setFillColor(toFloat(args[0]));
142         break;
143     case 2:
144         if (args[0]->IsString())
145             context->setFillColor(toWebCoreString(args[0]), toFloat(args[1]));
146         else
147             context->setFillColor(toFloat(args[0]), toFloat(args[1]));
148         break;
149     case 4:
150         context->setFillColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
151         break;
152     case 5:
153         context->setFillColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
154         break;
155     default:
156         V8Proxy::throwError(V8Proxy::SyntaxError, "setFillColor: Invalid number of arguments");
157         break;
158     }
159     return v8::Undefined();
160 }
161 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeRect)162 CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeRect)
163 {
164     INC_STATS("DOM.CanvasRenderingContext2D.strokeRect()");
165     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
166     if (args.Length() == 5)
167         context->strokeRect(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
168     else if (args.Length() == 4)
169         context->strokeRect(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
170     else {
171         V8Proxy::setDOMException(INDEX_SIZE_ERR);
172         return notHandledByInterceptor();
173     }
174     return v8::Undefined();
175 }
176 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow)177 CALLBACK_FUNC_DECL(CanvasRenderingContext2DSetShadow)
178 {
179     INC_STATS("DOM.CanvasRenderingContext2D.setShadow()");
180     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
181 
182     switch (args.Length()) {
183     case 3:
184         context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]));
185         break;
186     case 4:
187         if (args[3]->IsString())
188             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toWebCoreString(args[3]));
189         else
190             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
191         break;
192     case 5:
193         if (args[3]->IsString())
194             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toWebCoreString(args[3]), toFloat(args[4]));
195         else
196             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
197         break;
198     case 7:
199         context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), toFloat(args[5]), toFloat(args[6]));
200         break;
201     case 8:
202         context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), toFloat(args[5]), toFloat(args[6]), toFloat(args[7]));
203         break;
204     default:
205         V8Proxy::throwError(V8Proxy::SyntaxError, "setShadow: Invalid number of arguments");
206         break;
207     }
208 
209     return v8::Undefined();
210 }
211 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage)212 CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImage)
213 {
214     INC_STATS("DOM.CanvasRenderingContext2D.drawImage()");
215     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
216 
217     v8::Handle<v8::Value> arg = args[0];
218 
219     if (V8HTMLImageElement::HasInstance(arg)) {
220         ExceptionCode ec = 0;
221         HTMLImageElement* image_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLImageElement>(v8::Handle<v8::Object>::Cast(arg));
222         switch (args.Length()) {
223         case 3:
224             context->drawImage(image_element, toFloat(args[1]), toFloat(args[2]));
225             break;
226         case 5:
227             context->drawImage(image_element, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), ec);
228             if (ec != 0) {
229                 V8Proxy::setDOMException(ec);
230                 return notHandledByInterceptor();
231             }
232             break;
233         case 9:
234             context->drawImage(image_element,
235                 FloatRect(toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4])),
236                 FloatRect(toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8])),
237                 ec);
238             if (ec != 0) {
239                 V8Proxy::setDOMException(ec);
240                 return notHandledByInterceptor();
241             }
242             break;
243         default:
244             return throwError("drawImage: Invalid number of arguments", V8Proxy::SyntaxError);
245         }
246         return v8::Undefined();
247     }
248 
249     // HTMLCanvasElement
250     if (V8HTMLCanvasElement::HasInstance(arg)) {
251         ExceptionCode ec = 0;
252         HTMLCanvasElement* canvas_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLCanvasElement>(v8::Handle<v8::Object>::Cast(arg));
253         switch (args.Length()) {
254         case 3:
255             context->drawImage(canvas_element, toFloat(args[1]), toFloat(args[2]));
256             break;
257         case 5:
258             context->drawImage(canvas_element, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), ec);
259             if (ec != 0) {
260                 V8Proxy::setDOMException(ec);
261                 return notHandledByInterceptor();
262             }
263             break;
264         case 9:
265             context->drawImage(canvas_element,
266                 FloatRect(toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4])),
267                 FloatRect(toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8])),
268                 ec);
269             if (ec != 0) {
270                 V8Proxy::setDOMException(ec);
271                 return notHandledByInterceptor();
272             }
273             break;
274         default:
275             return throwError("drawImage: Invalid number of arguments", V8Proxy::SyntaxError);
276         }
277         return v8::Undefined();
278     }
279 
280 #if ENABLE(VIDEO)
281     // HTMLVideoElement
282     if (V8HTMLVideoElement::HasInstance(arg)) {
283         ExceptionCode ec = 0;
284         HTMLVideoElement* video_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLVideoElement>(v8::Handle<v8::Object>::Cast(arg));
285         switch (args.Length()) {
286         case 3:
287             context->drawImage(video_element, toFloat(args[1]), toFloat(args[2]));
288             break;
289         case 5:
290             context->drawImage(video_element, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), ec);
291             if (ec != 0) {
292                 V8Proxy::setDOMException(ec);
293                 return notHandledByInterceptor();
294             }
295             break;
296         case 9:
297             context->drawImage(video_element,
298                 FloatRect(toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4])),
299                 FloatRect(toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8])),
300                 ec);
301             if (ec != 0) {
302                 V8Proxy::setDOMException(ec);
303                 return notHandledByInterceptor();
304             }
305             break;
306         default:
307             return throwError("drawImage: Invalid number of arguments", V8Proxy::SyntaxError);
308         }
309         return v8::Undefined();
310     }
311 #endif
312 
313     V8Proxy::setDOMException(TYPE_MISMATCH_ERR);
314     return notHandledByInterceptor();
315 }
316 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImageFromRect)317 CALLBACK_FUNC_DECL(CanvasRenderingContext2DDrawImageFromRect)
318 {
319     INC_STATS("DOM.CanvasRenderingContext2D.drawImageFromRect()");
320     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
321 
322     v8::Handle<v8::Value> arg = args[0];
323 
324     if (V8HTMLImageElement::HasInstance(arg)) {
325         HTMLImageElement* image_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLImageElement>(v8::Handle<v8::Object>::Cast(arg));
326         context->drawImageFromRect(image_element,  toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8]), toWebCoreString(args[9]));
327     } else
328         V8Proxy::throwError(V8Proxy::TypeError, "drawImageFromRect: Invalid type of arguments");
329 
330     return v8::Undefined();
331 }
332 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DCreatePattern)333 CALLBACK_FUNC_DECL(CanvasRenderingContext2DCreatePattern)
334 {
335     INC_STATS("DOM.CanvasRenderingContext2D.createPattern()");
336     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
337 
338     v8::Handle<v8::Value> arg = args[0];
339 
340     if (V8HTMLImageElement::HasInstance(arg)) {
341         HTMLImageElement* image_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLImageElement>(v8::Handle<v8::Object>::Cast(arg));
342         ExceptionCode ec = 0;
343         RefPtr<CanvasPattern> pattern = context->createPattern(image_element, toWebCoreStringWithNullCheck(args[1]), ec);
344         if (ec != 0) {
345             V8Proxy::setDOMException(ec);
346             return notHandledByInterceptor();
347         }
348         return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASPATTERN, pattern.release());
349     }
350 
351     if (V8HTMLCanvasElement::HasInstance(arg)) {
352         HTMLCanvasElement* canvas_element = V8DOMWrapper::convertDOMWrapperToNode<HTMLCanvasElement>(v8::Handle<v8::Object>::Cast(arg));
353         ExceptionCode ec = 0;
354         RefPtr<CanvasPattern> pattern = context->createPattern(canvas_element, toWebCoreStringWithNullCheck(args[1]), ec);
355         if (ec != 0) {
356             V8Proxy::setDOMException(ec);
357             return notHandledByInterceptor();
358         }
359         return V8DOMWrapper::convertToV8Object(V8ClassIndex::CANVASPATTERN, pattern.release());
360     }
361 
362     V8Proxy::setDOMException(TYPE_MISMATCH_ERR);
363     return notHandledByInterceptor();
364 }
365 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DFillText)366 CALLBACK_FUNC_DECL(CanvasRenderingContext2DFillText)
367 {
368     INC_STATS("DOM.CanvasRenderingContext2D.fillText()");
369 
370     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
371 
372     // Two forms:
373     // * fillText(text, x, y)
374     // * fillText(text, x, y, maxWidth)
375     if (args.Length() < 3 || args.Length() > 4) {
376         V8Proxy::setDOMException(SYNTAX_ERR);
377         return notHandledByInterceptor();
378     }
379 
380     String text = toWebCoreString(args[0]);
381     float x = toFloat(args[1]);
382     float y = toFloat(args[2]);
383 
384     if (args.Length() == 4) {
385         float maxWidth = toFloat(args[3]);
386         context->fillText(text, x, y, maxWidth);
387     } else
388         context->fillText(text, x, y);
389 
390     return v8::Undefined();
391 }
392 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeText)393 CALLBACK_FUNC_DECL(CanvasRenderingContext2DStrokeText)
394 {
395     INC_STATS("DOM.CanvasRenderingContext2D.strokeText()");
396     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
397 
398     // Two forms:
399     // * strokeText(text, x, y)
400     // * strokeText(text, x, y, maxWidth)
401     if (args.Length() < 3 || args.Length() > 4) {
402         V8Proxy::setDOMException(SYNTAX_ERR);
403         return notHandledByInterceptor();
404     }
405 
406     String text = toWebCoreString(args[0]);
407     float x = toFloat(args[1]);
408     float y = toFloat(args[2]);
409 
410     if (args.Length() == 4) {
411         float maxWidth = toFloat(args[3]);
412         context->strokeText(text, x, y, maxWidth);
413     } else
414         context->strokeText(text, x, y);
415 
416     return v8::Undefined();
417 }
418 
CALLBACK_FUNC_DECL(CanvasRenderingContext2DPutImageData)419 CALLBACK_FUNC_DECL(CanvasRenderingContext2DPutImageData)
420 {
421     INC_STATS("DOM.CanvasRenderingContext2D.putImageData()");
422 
423     // Two froms:
424     // * putImageData(ImageData, x, y)
425     // * putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
426     if (args.Length() != 3 && args.Length() != 7) {
427         V8Proxy::setDOMException(SYNTAX_ERR);
428         return notHandledByInterceptor();
429     }
430 
431     CanvasRenderingContext2D* context = V8DOMWrapper::convertToNativeObject<CanvasRenderingContext2D>(V8ClassIndex::CANVASRENDERINGCONTEXT2D, args.Holder());
432 
433     ImageData* imageData = 0;
434 
435     // Need to check that the argument is of the correct type, since
436     // convertToNativeObject() expects it to be correct. If the argument was incorrect
437     // we leave it null, and putImageData() will throw the correct exception
438     // (TYPE_MISMATCH_ERR).
439     if (V8DOMWrapper::isWrapperOfType(args[0], V8ClassIndex::IMAGEDATA))
440         imageData = V8DOMWrapper::convertToNativeObject<ImageData>(V8ClassIndex::IMAGEDATA, v8::Handle<v8::Object>::Cast(args[0]));
441 
442     ExceptionCode ec = 0;
443 
444     if (args.Length() == 7)
445         context->putImageData(imageData, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), toFloat(args[5]), toFloat(args[6]), ec);
446     else
447         context->putImageData(imageData, toFloat(args[1]), toFloat(args[2]), ec);
448 
449     if (ec != 0) {
450         V8Proxy::setDOMException(ec);
451         return notHandledByInterceptor();
452     }
453 
454     return v8::Undefined();
455 }
456 
457 } // namespace WebCore
458