blob: 90574f40f031f892563daeb1244a5dbc82708f6d [file] [log] [blame]
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +00001/*
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 "Path.h"
11#include "Global.h"
12
13Global* Path::gGlobal = NULL;
14
15void Path::ConstructPath(const v8::FunctionCallbackInfo<Value>& args) {
16 HandleScope handleScope(gGlobal->getIsolate());
17 Path* path = new Path();
commit-bot@chromium.orgb1639842014-01-08 15:14:09 +000018 args.This()->SetInternalField(
19 0, External::New(gGlobal->getIsolate(), path));
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000020}
21
22#define ADD_METHOD(name, fn) \
23 constructor->InstanceTemplate()->Set( \
24 String::NewFromUtf8( \
25 global->getIsolate(), name, \
26 String::kInternalizedString), \
commit-bot@chromium.orgb1639842014-01-08 15:14:09 +000027 FunctionTemplate::New(global->getIsolate(), fn))
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000028
29// Install the constructor in the global scope so Paths can be constructed
30// in JS.
31void Path::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(
commit-bot@chromium.orgb1639842014-01-08 15:14:09 +000043 gGlobal->getIsolate(), Path::ConstructPath);
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000044 constructor->InstanceTemplate()->SetInternalFieldCount(1);
45
commit-bot@chromium.orgcd110182014-01-10 21:33:01 +000046 ADD_METHOD("closePath", ClosePath);
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000047 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);
commit-bot@chromium.orgcd110182014-01-10 21:33:01 +000053 ADD_METHOD("oval", Oval);
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000054
commit-bot@chromium.orgb1639842014-01-08 15:14:09 +000055 context->Global()->Set(String::NewFromUtf8(
56 gGlobal->getIsolate(), "Path"), constructor->GetFunction());
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000057}
58
59Path* Path::Unwrap(const v8::FunctionCallbackInfo<Value>& args) {
60 Handle<External> field = Handle<External>::Cast(
61 args.This()->GetInternalField(0));
62 void* ptr = field->Value();
63 return static_cast<Path*>(ptr);
64}
65
66void Path::ClosePath(const v8::FunctionCallbackInfo<Value>& args) {
67 Path* path = Unwrap(args);
68 path->fSkPath.close();
69}
70
71void Path::MoveTo(const v8::FunctionCallbackInfo<Value>& args) {
72 if (args.Length() != 2) {
73 args.GetIsolate()->ThrowException(
74 v8::String::NewFromUtf8(
75 args.GetIsolate(), "Error: 2 arguments required."));
76 return;
77 }
78 double x = args[0]->NumberValue();
79 double y = args[1]->NumberValue();
80 Path* path = Unwrap(args);
81 path->fSkPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
82}
83
84void Path::LineTo(const v8::FunctionCallbackInfo<Value>& args) {
85 if (args.Length() != 2) {
86 args.GetIsolate()->ThrowException(
87 v8::String::NewFromUtf8(
88 args.GetIsolate(), "Error: 2 arguments required."));
89 return;
90 }
91 double x = args[0]->NumberValue();
92 double y = args[1]->NumberValue();
93 Path* path = Unwrap(args);
94 path->fSkPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
95}
96
97void Path::QuadraticCurveTo(const v8::FunctionCallbackInfo<Value>& args) {
98 if (args.Length() != 4) {
99 args.GetIsolate()->ThrowException(
100 v8::String::NewFromUtf8(
101 args.GetIsolate(), "Error: 4 arguments required."));
102 return;
103 }
104 double cpx = args[0]->NumberValue();
105 double cpy = args[1]->NumberValue();
106 double x = args[2]->NumberValue();
107 double y = args[3]->NumberValue();
108 Path* path = Unwrap(args);
109 // TODO(jcgregorio) Doesn't handle the empty last path case correctly per
110 // the HTML 5 spec.
111 path->fSkPath.quadTo(
112 SkDoubleToScalar(cpx), SkDoubleToScalar(cpy),
113 SkDoubleToScalar(x), SkDoubleToScalar(y));
114}
115
116void Path::BezierCurveTo(const v8::FunctionCallbackInfo<Value>& args) {
117 if (args.Length() != 6) {
118 args.GetIsolate()->ThrowException(
119 v8::String::NewFromUtf8(
120 args.GetIsolate(), "Error: 6 arguments required."));
121 return;
122 }
123 double cp1x = args[0]->NumberValue();
124 double cp1y = args[1]->NumberValue();
125 double cp2x = args[2]->NumberValue();
126 double cp2y = args[3]->NumberValue();
127 double x = args[4]->NumberValue();
128 double y = args[5]->NumberValue();
129 Path* path = Unwrap(args);
130 // TODO(jcgregorio) Doesn't handle the empty last path case correctly per
131 // the HTML 5 spec.
132 path->fSkPath.cubicTo(
133 SkDoubleToScalar(cp1x), SkDoubleToScalar(cp1y),
134 SkDoubleToScalar(cp2x), SkDoubleToScalar(cp2y),
135 SkDoubleToScalar(x), SkDoubleToScalar(y));
136}
137
138void Path::Arc(const v8::FunctionCallbackInfo<Value>& args) {
139 if (args.Length() != 5 && args.Length() != 6) {
140 args.GetIsolate()->ThrowException(
141 v8::String::NewFromUtf8(
142 args.GetIsolate(), "Error: 5 or 6 args required."));
143 return;
144 }
145 double x = args[0]->NumberValue();
146 double y = args[1]->NumberValue();
147 double radius = args[2]->NumberValue();
148 double startAngle = args[3]->NumberValue();
149 double endAngle = args[4]->NumberValue();
150 bool antiClockwise = false;
151 if (args.Length() == 6) {
152 antiClockwise = args[5]->BooleanValue();
153 }
154 double sweepAngle;
155 if (!antiClockwise) {
156 sweepAngle = endAngle - startAngle;
157 } else {
158 sweepAngle = startAngle - endAngle;
159 startAngle = endAngle;
160 }
161
162 Path* path = Unwrap(args);
163 SkRect rect = {
164 SkDoubleToScalar(x-radius),
165 SkDoubleToScalar(y-radius),
166 SkDoubleToScalar(x+radius),
167 SkDoubleToScalar(y+radius)
168 };
169
170 path->fSkPath.addArc(rect, SkRadiansToDegrees(startAngle),
171 SkRadiansToDegrees(sweepAngle));
172}
173
174void Path::Rect(const v8::FunctionCallbackInfo<Value>& args) {
175 if (args.Length() != 4) {
176 args.GetIsolate()->ThrowException(
177 v8::String::NewFromUtf8(
178 args.GetIsolate(), "Error: 4 arguments required."));
179 return;
180 }
181 double x = args[0]->NumberValue();
182 double y = args[1]->NumberValue();
183 double w = args[2]->NumberValue();
184 double h = args[3]->NumberValue();
185
186 SkRect rect = {
187 SkDoubleToScalar(x),
188 SkDoubleToScalar(y),
189 SkDoubleToScalar(x) + SkDoubleToScalar(w),
190 SkDoubleToScalar(y) + SkDoubleToScalar(h)
191 };
192 Path* path = Unwrap(args);
193 path->fSkPath.addRect(rect);
194}
commit-bot@chromium.orgcd110182014-01-10 21:33:01 +0000195
196void Path::Oval(const v8::FunctionCallbackInfo<Value>& args) {
197 if (args.Length() != 4 && args.Length() != 5) {
198 args.GetIsolate()->ThrowException(
199 v8::String::NewFromUtf8(
200 args.GetIsolate(), "Error: 4 or 5 args required."));
201 return;
202 }
203 double x = args[0]->NumberValue();
204 double y = args[1]->NumberValue();
205 double radiusX = args[2]->NumberValue();
206 double radiusY = args[3]->NumberValue();
207 SkPath::Direction dir = SkPath::kCW_Direction;
208 if (args.Length() == 5 && !args[4]->BooleanValue()) {
209 dir = SkPath::kCCW_Direction;
210 }
211 Path* path = Unwrap(args);
212 SkRect rect = {
213 SkDoubleToScalar(x-radiusX),
214 SkDoubleToScalar(y-radiusX),
215 SkDoubleToScalar(x+radiusY),
216 SkDoubleToScalar(y+radiusY)
217 };
218
219 path->fSkPath.addOval(rect, dir);
220}