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