Home | History | Annotate | Download | only in SkV8Example
      1 /*
      2  * Copyright 2014 Google Inc.
      3  *
      4  *
      5  * Use of this source code is governed by a BSD-style license that can be
      6  * found in the LICENSE file.
      7  *
      8  */
      9 
     10 #include "Path2D.h"
     11 #include "Global.h"
     12 
     13 Global* Path2D::gGlobal = NULL;
     14 
     15 void Path2D::ConstructPath(const v8::FunctionCallbackInfo<Value>& args) {
     16     HandleScope handleScope(gGlobal->getIsolate());
     17     Path2D* path = new Path2D();
     18     args.This()->SetInternalField(
     19             0, External::New(gGlobal->getIsolate(), path));
     20 }
     21 
     22 #define ADD_METHOD(name, fn) \
     23     constructor->InstanceTemplate()->Set( \
     24             String::NewFromUtf8( \
     25                     global->getIsolate(), name, \
     26                     String::kInternalizedString), \
     27             FunctionTemplate::New(global->getIsolate(), fn))
     28 
     29 // Install the constructor in the global scope so Path2Ds can be constructed
     30 // in JS.
     31 void Path2D::AddToGlobal(Global* global) {
     32     gGlobal = global;
     33 
     34     // Create a stack-allocated handle scope.
     35     HandleScope handleScope(gGlobal->getIsolate());
     36 
     37     Handle<Context> context = gGlobal->getContext();
     38 
     39     // Enter the scope so all operations take place in the scope.
     40     Context::Scope contextScope(context);
     41 
     42     Local<FunctionTemplate> constructor = FunctionTemplate::New(
     43             gGlobal->getIsolate(), Path2D::ConstructPath);
     44     constructor->InstanceTemplate()->SetInternalFieldCount(1);
     45 
     46     ADD_METHOD("closePath", ClosePath);
     47     ADD_METHOD("moveTo", MoveTo);
     48     ADD_METHOD("lineTo", LineTo);
     49     ADD_METHOD("quadraticCurveTo", QuadraticCurveTo);
     50     ADD_METHOD("bezierCurveTo", BezierCurveTo);
     51     ADD_METHOD("arc", Arc);
     52     ADD_METHOD("rect", Rect);
     53     ADD_METHOD("oval", Oval);
     54     ADD_METHOD("conicTo", ConicTo);
     55 
     56     context->Global()->Set(String::NewFromUtf8(
     57             gGlobal->getIsolate(), "Path2D"), constructor->GetFunction());
     58 }
     59 
     60 Path2D* Path2D::Unwrap(const v8::FunctionCallbackInfo<Value>& args) {
     61     Handle<External> field = Handle<External>::Cast(
     62             args.This()->GetInternalField(0));
     63     void* ptr = field->Value();
     64     return static_cast<Path2D*>(ptr);
     65 }
     66 
     67 void Path2D::ClosePath(const v8::FunctionCallbackInfo<Value>& args) {
     68     Path2D* path = Unwrap(args);
     69     path->fSkPath.close();
     70 }
     71 
     72 void Path2D::MoveTo(const v8::FunctionCallbackInfo<Value>& args) {
     73     if (args.Length() != 2) {
     74         args.GetIsolate()->ThrowException(
     75                 v8::String::NewFromUtf8(
     76                         args.GetIsolate(), "Error: 2 arguments required."));
     77         return;
     78     }
     79     double x = args[0]->NumberValue();
     80     double y = args[1]->NumberValue();
     81     Path2D* path = Unwrap(args);
     82     path->fSkPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
     83 }
     84 
     85 void Path2D::LineTo(const v8::FunctionCallbackInfo<Value>& args) {
     86     if (args.Length() != 2) {
     87         args.GetIsolate()->ThrowException(
     88                 v8::String::NewFromUtf8(
     89                         args.GetIsolate(), "Error: 2 arguments required."));
     90         return;
     91     }
     92     double x = args[0]->NumberValue();
     93     double y = args[1]->NumberValue();
     94     Path2D* path = Unwrap(args);
     95     path->fSkPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
     96 }
     97 
     98 void Path2D::QuadraticCurveTo(const v8::FunctionCallbackInfo<Value>& args) {
     99     if (args.Length() != 4) {
    100         args.GetIsolate()->ThrowException(
    101                 v8::String::NewFromUtf8(
    102                         args.GetIsolate(), "Error: 4 arguments required."));
    103         return;
    104     }
    105     double cpx = args[0]->NumberValue();
    106     double cpy = args[1]->NumberValue();
    107     double x = args[2]->NumberValue();
    108     double y = args[3]->NumberValue();
    109     Path2D* path = Unwrap(args);
    110     // TODO(jcgregorio) Doesn't handle the empty last path case correctly per
    111     // the HTML 5 spec.
    112     path->fSkPath.quadTo(
    113             SkDoubleToScalar(cpx), SkDoubleToScalar(cpy),
    114             SkDoubleToScalar(x), SkDoubleToScalar(y));
    115 }
    116 
    117 void Path2D::BezierCurveTo(const v8::FunctionCallbackInfo<Value>& args) {
    118     if (args.Length() != 6) {
    119         args.GetIsolate()->ThrowException(
    120                 v8::String::NewFromUtf8(
    121                         args.GetIsolate(), "Error: 6 arguments required."));
    122         return;
    123     }
    124     double cp1x = args[0]->NumberValue();
    125     double cp1y = args[1]->NumberValue();
    126     double cp2x = args[2]->NumberValue();
    127     double cp2y = args[3]->NumberValue();
    128     double x = args[4]->NumberValue();
    129     double y = args[5]->NumberValue();
    130     Path2D* path = Unwrap(args);
    131     // TODO(jcgregorio) Doesn't handle the empty last path case correctly per
    132     // the HTML 5 spec.
    133     path->fSkPath.cubicTo(
    134             SkDoubleToScalar(cp1x), SkDoubleToScalar(cp1y),
    135             SkDoubleToScalar(cp2x), SkDoubleToScalar(cp2y),
    136             SkDoubleToScalar(x), SkDoubleToScalar(y));
    137 }
    138 
    139 void Path2D::Arc(const v8::FunctionCallbackInfo<Value>& args) {
    140     if (args.Length() != 5 && args.Length() != 6) {
    141         args.GetIsolate()->ThrowException(
    142                 v8::String::NewFromUtf8(
    143                         args.GetIsolate(), "Error: 5 or 6 args required."));
    144         return;
    145     }
    146     double x          = args[0]->NumberValue();
    147     double y          = args[1]->NumberValue();
    148     double radius     = args[2]->NumberValue();
    149     double startAngle = args[3]->NumberValue();
    150     double endAngle   = args[4]->NumberValue();
    151     bool antiClockwise = false;
    152     if (args.Length() == 6) {
    153        antiClockwise = args[5]->BooleanValue();
    154     }
    155     double sweepAngle;
    156     if (!antiClockwise) {
    157       sweepAngle = endAngle - startAngle;
    158     } else {
    159       sweepAngle = startAngle - endAngle;
    160       startAngle = endAngle;
    161     }
    162 
    163     Path2D* path = Unwrap(args);
    164     SkRect rect = {
    165         SkDoubleToScalar(x-radius),
    166         SkDoubleToScalar(y-radius),
    167         SkDoubleToScalar(x+radius),
    168         SkDoubleToScalar(y+radius)
    169     };
    170 
    171     path->fSkPath.addArc(rect, SkRadiansToDegrees(startAngle),
    172                          SkRadiansToDegrees(sweepAngle));
    173 }
    174 
    175 void Path2D::Rect(const v8::FunctionCallbackInfo<Value>& args) {
    176     if (args.Length() != 4) {
    177         args.GetIsolate()->ThrowException(
    178                 v8::String::NewFromUtf8(
    179                         args.GetIsolate(), "Error: 4 arguments required."));
    180         return;
    181     }
    182     double x = args[0]->NumberValue();
    183     double y = args[1]->NumberValue();
    184     double w = args[2]->NumberValue();
    185     double h = args[3]->NumberValue();
    186 
    187     SkRect rect = {
    188         SkDoubleToScalar(x),
    189         SkDoubleToScalar(y),
    190         SkDoubleToScalar(x) + SkDoubleToScalar(w),
    191         SkDoubleToScalar(y) + SkDoubleToScalar(h)
    192     };
    193     Path2D* path = Unwrap(args);
    194     path->fSkPath.addRect(rect);
    195 }
    196 
    197 void Path2D::Oval(const v8::FunctionCallbackInfo<Value>& args) {
    198     if (args.Length() != 4 && args.Length() != 5) {
    199         args.GetIsolate()->ThrowException(
    200                 v8::String::NewFromUtf8(
    201                         args.GetIsolate(), "Error: 4 or 5 args required."));
    202         return;
    203     }
    204     double x          = args[0]->NumberValue();
    205     double y          = args[1]->NumberValue();
    206     double radiusX    = args[2]->NumberValue();
    207     double radiusY    = args[3]->NumberValue();
    208     SkPath::Direction dir = SkPath::kCW_Direction;
    209     if (args.Length() == 5 && !args[4]->BooleanValue()) {
    210         dir = SkPath::kCCW_Direction;
    211     }
    212     Path2D* path = Unwrap(args);
    213     SkRect rect = {
    214         SkDoubleToScalar(x-radiusX),
    215         SkDoubleToScalar(y-radiusX),
    216         SkDoubleToScalar(x+radiusY),
    217         SkDoubleToScalar(y+radiusY)
    218     };
    219 
    220     path->fSkPath.addOval(rect, dir);
    221 }
    222 
    223 void Path2D::ConicTo(const v8::FunctionCallbackInfo<Value>& args) {
    224     if (args.Length() != 5) {
    225         args.GetIsolate()->ThrowException(
    226                 v8::String::NewFromUtf8(
    227                         args.GetIsolate(), "Error: 5 args required."));
    228         return;
    229     }
    230     double x1 = args[0]->NumberValue();
    231     double y1 = args[1]->NumberValue();
    232     double x2 = args[2]->NumberValue();
    233     double y2 = args[3]->NumberValue();
    234     double w  = args[4]->NumberValue();
    235     Path2D* path = Unwrap(args);
    236 
    237     path->fSkPath.conicTo(
    238             SkDoubleToScalar(x1),
    239             SkDoubleToScalar(y1),
    240             SkDoubleToScalar(x2),
    241             SkDoubleToScalar(y2),
    242             SkDoubleToScalar(w)
    243             );
    244 }
    245