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