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 41using namespace JSC; 42 43namespace WebCore { 44 45static 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 54static 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 66JSValue JSCanvasRenderingContext2D::strokeStyle(ExecState* exec) const 67{ 68 CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); 69 return toJS(exec, context->strokeStyle()); 70} 71 72void 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 82JSValue JSCanvasRenderingContext2D::fillStyle(ExecState* exec) const 83{ 84 CanvasRenderingContext2D* context = static_cast<CanvasRenderingContext2D*>(impl()); 85 return toJS(exec, context->fillStyle()); 86} 87 88void 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 98JSValue 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 135JSValue 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 173JSValue 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 187JSValue 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 279JSValue 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 299JSValue 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 345JSValue 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 376JSValue 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 394JSValue 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 412JSValue 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 430JSValue 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