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