• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ConstructPath(const v8::FunctionCallbackInfo<Value> & args)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.
AddToGlobal(Global * global)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 
Unwrap(const v8::FunctionCallbackInfo<Value> & args)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 
ClosePath(const v8::FunctionCallbackInfo<Value> & args)67 void Path2D::ClosePath(const v8::FunctionCallbackInfo<Value>& args) {
68     Path2D* path = Unwrap(args);
69     path->fSkPath.close();
70 }
71 
MoveTo(const v8::FunctionCallbackInfo<Value> & args)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 
LineTo(const v8::FunctionCallbackInfo<Value> & args)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 
QuadraticCurveTo(const v8::FunctionCallbackInfo<Value> & args)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 
BezierCurveTo(const v8::FunctionCallbackInfo<Value> & args)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 
Arc(const v8::FunctionCallbackInfo<Value> & args)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 
Rect(const v8::FunctionCallbackInfo<Value> & args)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 
Oval(const v8::FunctionCallbackInfo<Value> & args)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 
ConicTo(const v8::FunctionCallbackInfo<Value> & args)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