blob: ad05668139a514113e5bbd769409eec3bd41bbfd [file] [log] [blame]
jcgregorioe001da22014-10-29 05:33:27 -07001/*
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
15Global* Path2DBuilder::gGlobal = NULL;
16
17void 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.
33void 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
64Path2DBuilder* 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
71void Path2DBuilder::ClosePath(const v8::FunctionCallbackInfo<v8::Value>& args) {
72 Path2DBuilder* path = Unwrap(args);
73 path->fSkPath.close();
74}
75
76void 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
89void 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
102void 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
121void 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
143void 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
179void 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
201void 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
227void 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
250void 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}