Home | History | Annotate | Download | only in custom
      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 "V8CanvasRenderingContext2D.h"
     33 
     34 #include "CanvasGradient.h"
     35 #include "CanvasRenderingContext2D.h"
     36 #include "CanvasPattern.h"
     37 #include "CanvasStyle.h"
     38 #include "ExceptionCode.h"
     39 #include "FloatRect.h"
     40 
     41 #include "V8Binding.h"
     42 #include "V8CanvasGradient.h"
     43 #include "V8CanvasPattern.h"
     44 #include "V8HTMLCanvasElement.h"
     45 #include "V8HTMLImageElement.h"
     46 #include "V8HTMLVideoElement.h"
     47 #include "V8ImageData.h"
     48 #include "V8Proxy.h"
     49 
     50 namespace WebCore {
     51 
     52 static v8::Handle<v8::Value> toV8Object(CanvasStyle* style)
     53 {
     54     if (style->canvasGradient())
     55         return toV8(style->canvasGradient());
     56 
     57     if (style->canvasPattern())
     58         return toV8(style->canvasPattern());
     59 
     60     return v8String(style->color());
     61 }
     62 
     63 static PassRefPtr<CanvasStyle> toCanvasStyle(v8::Handle<v8::Value> value)
     64 {
     65     if (value->IsString())
     66         return CanvasStyle::create(toWebCoreString(value));
     67 
     68     if (V8CanvasGradient::HasInstance(value))
     69         return CanvasStyle::create(V8CanvasGradient::toNative(v8::Handle<v8::Object>::Cast(value)));
     70 
     71     if (V8CanvasPattern::HasInstance(value))
     72         return CanvasStyle::create(V8CanvasPattern::toNative(v8::Handle<v8::Object>::Cast(value)));
     73 
     74     return 0;
     75 }
     76 
     77 v8::Handle<v8::Value> V8CanvasRenderingContext2D::strokeStyleAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
     78 {
     79     CanvasRenderingContext2D* impl = V8CanvasRenderingContext2D::toNative(info.Holder());
     80     return toV8Object(impl->strokeStyle());
     81 }
     82 
     83 void V8CanvasRenderingContext2D::strokeStyleAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
     84 {
     85     CanvasRenderingContext2D* impl = V8CanvasRenderingContext2D::toNative(info.Holder());
     86     impl->setStrokeStyle(toCanvasStyle(value));
     87 }
     88 
     89 v8::Handle<v8::Value> V8CanvasRenderingContext2D::fillStyleAccessorGetter(v8::Local<v8::String> name, const v8::AccessorInfo& info)
     90 {
     91     CanvasRenderingContext2D* impl = V8CanvasRenderingContext2D::toNative(info.Holder());
     92     return toV8Object(impl->fillStyle());
     93 }
     94 
     95 void V8CanvasRenderingContext2D::fillStyleAccessorSetter(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::AccessorInfo& info)
     96 {
     97     CanvasRenderingContext2D* impl = V8CanvasRenderingContext2D::toNative(info.Holder());
     98     impl->setFillStyle(toCanvasStyle(value));
     99 }
    100 
    101 // TODO: SetStrokeColor and SetFillColor are similar except function names,
    102 // consolidate them into one.
    103 v8::Handle<v8::Value> V8CanvasRenderingContext2D::setStrokeColorCallback(const v8::Arguments& args)
    104 {
    105     INC_STATS("DOM.CanvasRenderingContext2D.setStrokeColor()");
    106     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    107     switch (args.Length()) {
    108     case 1:
    109         if (args[0]->IsString())
    110             context->setStrokeColor(toWebCoreString(args[0]));
    111         else
    112             context->setStrokeColor(toFloat(args[0]));
    113         break;
    114     case 2:
    115         if (args[0]->IsString())
    116             context->setStrokeColor(toWebCoreString(args[0]), toFloat(args[1]));
    117         else
    118             context->setStrokeColor(toFloat(args[0]), toFloat(args[1]));
    119         break;
    120     case 4:
    121         context->setStrokeColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
    122         break;
    123     case 5:
    124         context->setStrokeColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
    125         break;
    126     default:
    127         V8Proxy::throwError(V8Proxy::SyntaxError, "setStrokeColor: Invalid number of arguments");
    128         break;
    129     }
    130     return v8::Undefined();
    131 }
    132 
    133 v8::Handle<v8::Value> V8CanvasRenderingContext2D::setFillColorCallback(const v8::Arguments& args)
    134 {
    135     INC_STATS("DOM.CanvasRenderingContext2D.setFillColor()");
    136     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    137     switch (args.Length()) {
    138     case 1:
    139         if (args[0]->IsString())
    140             context->setFillColor(toWebCoreString(args[0]));
    141         else
    142             context->setFillColor(toFloat(args[0]));
    143         break;
    144     case 2:
    145         if (args[0]->IsString())
    146             context->setFillColor(toWebCoreString(args[0]), toFloat(args[1]));
    147         else
    148             context->setFillColor(toFloat(args[0]), toFloat(args[1]));
    149         break;
    150     case 4:
    151         context->setFillColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
    152         break;
    153     case 5:
    154         context->setFillColor(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
    155         break;
    156     default:
    157         V8Proxy::throwError(V8Proxy::SyntaxError, "setFillColor: Invalid number of arguments");
    158         break;
    159     }
    160     return v8::Undefined();
    161 }
    162 
    163 v8::Handle<v8::Value> V8CanvasRenderingContext2D::strokeRectCallback(const v8::Arguments& args)
    164 {
    165     INC_STATS("DOM.CanvasRenderingContext2D.strokeRect()");
    166     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    167     if (args.Length() == 5)
    168         context->strokeRect(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
    169     else if (args.Length() == 4)
    170         context->strokeRect(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
    171     else {
    172         V8Proxy::setDOMException(INDEX_SIZE_ERR);
    173         return notHandledByInterceptor();
    174     }
    175     return v8::Undefined();
    176 }
    177 
    178 v8::Handle<v8::Value> V8CanvasRenderingContext2D::setShadowCallback(const v8::Arguments& args)
    179 {
    180     INC_STATS("DOM.CanvasRenderingContext2D.setShadow()");
    181     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    182 
    183     switch (args.Length()) {
    184     case 3:
    185         context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]));
    186         break;
    187     case 4:
    188         if (args[3]->IsString())
    189             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toWebCoreString(args[3]));
    190         else
    191             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]));
    192         break;
    193     case 5:
    194         if (args[3]->IsString())
    195             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toWebCoreString(args[3]), toFloat(args[4]));
    196         else
    197             context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]));
    198         break;
    199     case 7:
    200         context->setShadow(toFloat(args[0]), toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), toFloat(args[5]), toFloat(args[6]));
    201         break;
    202     case 8:
    203         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]));
    204         break;
    205     default:
    206         V8Proxy::throwError(V8Proxy::SyntaxError, "setShadow: Invalid number of arguments");
    207         break;
    208     }
    209 
    210     return v8::Undefined();
    211 }
    212 
    213 v8::Handle<v8::Value> V8CanvasRenderingContext2D::drawImageCallback(const v8::Arguments& args)
    214 {
    215     INC_STATS("DOM.CanvasRenderingContext2D.drawImage()");
    216     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    217 
    218     v8::Handle<v8::Value> arg = args[0];
    219 
    220     if (V8HTMLImageElement::HasInstance(arg)) {
    221         ExceptionCode ec = 0;
    222         HTMLImageElement* imageElement = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    223         switch (args.Length()) {
    224         case 3:
    225             context->drawImage(imageElement, toFloat(args[1]), toFloat(args[2]));
    226             break;
    227         case 5:
    228             context->drawImage(imageElement, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), ec);
    229             if (ec != 0) {
    230                 V8Proxy::setDOMException(ec);
    231                 return notHandledByInterceptor();
    232             }
    233             break;
    234         case 9:
    235             context->drawImage(imageElement,
    236                 FloatRect(toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4])),
    237                 FloatRect(toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8])),
    238                 ec);
    239             if (ec != 0) {
    240                 V8Proxy::setDOMException(ec);
    241                 return notHandledByInterceptor();
    242             }
    243             break;
    244         default:
    245             return throwError("drawImage: Invalid number of arguments", V8Proxy::SyntaxError);
    246         }
    247         return v8::Undefined();
    248     }
    249 
    250     // HTMLCanvasElement
    251     if (V8HTMLCanvasElement::HasInstance(arg)) {
    252         ExceptionCode ec = 0;
    253         HTMLCanvasElement* canvasElement = V8HTMLCanvasElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    254         switch (args.Length()) {
    255         case 3:
    256             context->drawImage(canvasElement, toFloat(args[1]), toFloat(args[2]));
    257             break;
    258         case 5:
    259             context->drawImage(canvasElement, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), ec);
    260             if (ec != 0) {
    261                 V8Proxy::setDOMException(ec);
    262                 return notHandledByInterceptor();
    263             }
    264             break;
    265         case 9:
    266             context->drawImage(canvasElement,
    267                 FloatRect(toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4])),
    268                 FloatRect(toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8])),
    269                 ec);
    270             if (ec != 0) {
    271                 V8Proxy::setDOMException(ec);
    272                 return notHandledByInterceptor();
    273             }
    274             break;
    275         default:
    276             return throwError("drawImage: Invalid number of arguments", V8Proxy::SyntaxError);
    277         }
    278         return v8::Undefined();
    279     }
    280 
    281 #if ENABLE(VIDEO)
    282     // HTMLVideoElement
    283     if (V8HTMLVideoElement::HasInstance(arg)) {
    284         ExceptionCode ec = 0;
    285         HTMLVideoElement* videoElement = V8HTMLVideoElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    286         switch (args.Length()) {
    287         case 3:
    288             context->drawImage(videoElement, toFloat(args[1]), toFloat(args[2]));
    289             break;
    290         case 5:
    291             context->drawImage(videoElement, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), ec);
    292             if (ec != 0) {
    293                 V8Proxy::setDOMException(ec);
    294                 return notHandledByInterceptor();
    295             }
    296             break;
    297         case 9:
    298             context->drawImage(videoElement,
    299                 FloatRect(toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4])),
    300                 FloatRect(toFloat(args[5]), toFloat(args[6]), toFloat(args[7]), toFloat(args[8])),
    301                 ec);
    302             if (ec != 0) {
    303                 V8Proxy::setDOMException(ec);
    304                 return notHandledByInterceptor();
    305             }
    306             break;
    307         default:
    308             return throwError("drawImage: Invalid number of arguments", V8Proxy::SyntaxError);
    309         }
    310         return v8::Undefined();
    311     }
    312 #endif
    313 
    314     V8Proxy::setDOMException(TYPE_MISMATCH_ERR);
    315     return notHandledByInterceptor();
    316 }
    317 
    318 
    319 v8::Handle<v8::Value> V8CanvasRenderingContext2D::drawImageFromRectCallback(const v8::Arguments& args)
    320 {
    321     INC_STATS("DOM.CanvasRenderingContext2D.drawImageFromRect()");
    322     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    323 
    324     v8::Handle<v8::Value> arg = args[0];
    325 
    326     if (V8HTMLImageElement::HasInstance(arg)) {
    327         HTMLImageElement* imageElement = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    328         context->drawImageFromRect(imageElement,  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]));
    329     } else
    330         V8Proxy::throwError(V8Proxy::TypeError, "drawImageFromRect: Invalid type of arguments");
    331 
    332     return v8::Undefined();
    333 }
    334 
    335 v8::Handle<v8::Value> V8CanvasRenderingContext2D::createPatternCallback(const v8::Arguments& args)
    336 {
    337     INC_STATS("DOM.CanvasRenderingContext2D.createPattern()");
    338     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    339 
    340     v8::Handle<v8::Value> arg = args[0];
    341 
    342     if (V8HTMLImageElement::HasInstance(arg)) {
    343         HTMLImageElement* imageElement = V8HTMLImageElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    344         ExceptionCode ec = 0;
    345         RefPtr<CanvasPattern> pattern = context->createPattern(imageElement, toWebCoreStringWithNullCheck(args[1]), ec);
    346         if (ec != 0) {
    347             V8Proxy::setDOMException(ec);
    348             return notHandledByInterceptor();
    349         }
    350         return toV8(pattern.release());
    351     }
    352 
    353     if (V8HTMLCanvasElement::HasInstance(arg)) {
    354         HTMLCanvasElement* canvasElement = V8HTMLCanvasElement::toNative(v8::Handle<v8::Object>::Cast(arg));
    355         ExceptionCode ec = 0;
    356         RefPtr<CanvasPattern> pattern = context->createPattern(canvasElement, toWebCoreStringWithNullCheck(args[1]), ec);
    357         if (ec != 0) {
    358             V8Proxy::setDOMException(ec);
    359             return notHandledByInterceptor();
    360         }
    361         return toV8(pattern.release());
    362     }
    363 
    364     V8Proxy::setDOMException(TYPE_MISMATCH_ERR);
    365     return notHandledByInterceptor();
    366 }
    367 
    368 v8::Handle<v8::Value> V8CanvasRenderingContext2D::fillTextCallback(const v8::Arguments& args)
    369 {
    370     INC_STATS("DOM.CanvasRenderingContext2D.fillText()");
    371 
    372     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    373 
    374     // Two forms:
    375     // * fillText(text, x, y)
    376     // * fillText(text, x, y, maxWidth)
    377     if (args.Length() < 3 || args.Length() > 4) {
    378         V8Proxy::setDOMException(SYNTAX_ERR);
    379         return notHandledByInterceptor();
    380     }
    381 
    382     String text = toWebCoreString(args[0]);
    383     float x = toFloat(args[1]);
    384     float y = toFloat(args[2]);
    385 
    386     if (args.Length() == 4) {
    387         float maxWidth = toFloat(args[3]);
    388         context->fillText(text, x, y, maxWidth);
    389     } else
    390         context->fillText(text, x, y);
    391 
    392     return v8::Undefined();
    393 }
    394 
    395 v8::Handle<v8::Value> V8CanvasRenderingContext2D::strokeTextCallback(const v8::Arguments& args)
    396 {
    397     INC_STATS("DOM.CanvasRenderingContext2D.strokeText()");
    398     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    399 
    400     // Two forms:
    401     // * strokeText(text, x, y)
    402     // * strokeText(text, x, y, maxWidth)
    403     if (args.Length() < 3 || args.Length() > 4) {
    404         V8Proxy::setDOMException(SYNTAX_ERR);
    405         return notHandledByInterceptor();
    406     }
    407 
    408     String text = toWebCoreString(args[0]);
    409     float x = toFloat(args[1]);
    410     float y = toFloat(args[2]);
    411 
    412     if (args.Length() == 4) {
    413         float maxWidth = toFloat(args[3]);
    414         context->strokeText(text, x, y, maxWidth);
    415     } else
    416         context->strokeText(text, x, y);
    417 
    418     return v8::Undefined();
    419 }
    420 
    421 v8::Handle<v8::Value> V8CanvasRenderingContext2D::putImageDataCallback(const v8::Arguments& args)
    422 {
    423     INC_STATS("DOM.CanvasRenderingContext2D.putImageData()");
    424 
    425     // Two froms:
    426     // * putImageData(ImageData, x, y)
    427     // * putImageData(ImageData, x, y, dirtyX, dirtyY, dirtyWidth, dirtyHeight)
    428     if (args.Length() != 3 && args.Length() != 7) {
    429         V8Proxy::setDOMException(SYNTAX_ERR);
    430         return notHandledByInterceptor();
    431     }
    432 
    433     CanvasRenderingContext2D* context = V8CanvasRenderingContext2D::toNative(args.Holder());
    434 
    435     ImageData* imageData = 0;
    436 
    437     // Need to check that the argument is of the correct type, since
    438     // toNative() expects it to be correct. If the argument was incorrect
    439     // we leave it null, and putImageData() will throw the correct exception
    440     // (TYPE_MISMATCH_ERR).
    441     if (V8DOMWrapper::isWrapperOfType(args[0], V8ClassIndex::IMAGEDATA))
    442         imageData = V8ImageData::toNative(v8::Handle<v8::Object>::Cast(args[0]));
    443 
    444     ExceptionCode ec = 0;
    445 
    446     if (args.Length() == 7)
    447         context->putImageData(imageData, toFloat(args[1]), toFloat(args[2]), toFloat(args[3]), toFloat(args[4]), toFloat(args[5]), toFloat(args[6]), ec);
    448     else
    449         context->putImageData(imageData, toFloat(args[1]), toFloat(args[2]), ec);
    450 
    451     if (ec != 0) {
    452         V8Proxy::setDOMException(ec);
    453         return notHandledByInterceptor();
    454     }
    455 
    456     return v8::Undefined();
    457 }
    458 
    459 } // namespace WebCore
    460