blob: 2b53a0f8e16ba9cdc2eb8c60bb683a16580c7bfb [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
46 ADD_METHOD("close", 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
commit-bot@chromium.orgb1639842014-01-08 15:14:09 +000054 context->Global()->Set(String::NewFromUtf8(
55 gGlobal->getIsolate(), "Path"), constructor->GetFunction());
commit-bot@chromium.orgc8d73282014-01-06 18:17:24 +000056}
57
58Path* Path::Unwrap(const v8::FunctionCallbackInfo<Value>& args) {
59 Handle<External> field = Handle<External>::Cast(
60 args.This()->GetInternalField(0));
61 void* ptr = field->Value();
62 return static_cast<Path*>(ptr);
63}
64
65void Path::ClosePath(const v8::FunctionCallbackInfo<Value>& args) {
66 Path* path = Unwrap(args);
67 path->fSkPath.close();
68}
69
70void Path::MoveTo(const v8::FunctionCallbackInfo<Value>& args) {
71 if (args.Length() != 2) {
72 args.GetIsolate()->ThrowException(
73 v8::String::NewFromUtf8(
74 args.GetIsolate(), "Error: 2 arguments required."));
75 return;
76 }
77 double x = args[0]->NumberValue();
78 double y = args[1]->NumberValue();
79 Path* path = Unwrap(args);
80 path->fSkPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
81}
82
83void Path::LineTo(const v8::FunctionCallbackInfo<Value>& args) {
84 if (args.Length() != 2) {
85 args.GetIsolate()->ThrowException(
86 v8::String::NewFromUtf8(
87 args.GetIsolate(), "Error: 2 arguments required."));
88 return;
89 }
90 double x = args[0]->NumberValue();
91 double y = args[1]->NumberValue();
92 Path* path = Unwrap(args);
93 path->fSkPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
94}
95
96void Path::QuadraticCurveTo(const v8::FunctionCallbackInfo<Value>& args) {
97 if (args.Length() != 4) {
98 args.GetIsolate()->ThrowException(
99 v8::String::NewFromUtf8(
100 args.GetIsolate(), "Error: 4 arguments required."));
101 return;
102 }
103 double cpx = args[0]->NumberValue();
104 double cpy = args[1]->NumberValue();
105 double x = args[2]->NumberValue();
106 double y = args[3]->NumberValue();
107 Path* path = Unwrap(args);
108 // TODO(jcgregorio) Doesn't handle the empty last path case correctly per
109 // the HTML 5 spec.
110 path->fSkPath.quadTo(
111 SkDoubleToScalar(cpx), SkDoubleToScalar(cpy),
112 SkDoubleToScalar(x), SkDoubleToScalar(y));
113}
114
115void Path::BezierCurveTo(const v8::FunctionCallbackInfo<Value>& args) {
116 if (args.Length() != 6) {
117 args.GetIsolate()->ThrowException(
118 v8::String::NewFromUtf8(
119 args.GetIsolate(), "Error: 6 arguments required."));
120 return;
121 }
122 double cp1x = args[0]->NumberValue();
123 double cp1y = args[1]->NumberValue();
124 double cp2x = args[2]->NumberValue();
125 double cp2y = args[3]->NumberValue();
126 double x = args[4]->NumberValue();
127 double y = args[5]->NumberValue();
128 Path* path = Unwrap(args);
129 // TODO(jcgregorio) Doesn't handle the empty last path case correctly per
130 // the HTML 5 spec.
131 path->fSkPath.cubicTo(
132 SkDoubleToScalar(cp1x), SkDoubleToScalar(cp1y),
133 SkDoubleToScalar(cp2x), SkDoubleToScalar(cp2y),
134 SkDoubleToScalar(x), SkDoubleToScalar(y));
135}
136
137void Path::Arc(const v8::FunctionCallbackInfo<Value>& args) {
138 if (args.Length() != 5 && args.Length() != 6) {
139 args.GetIsolate()->ThrowException(
140 v8::String::NewFromUtf8(
141 args.GetIsolate(), "Error: 5 or 6 args required."));
142 return;
143 }
144 double x = args[0]->NumberValue();
145 double y = args[1]->NumberValue();
146 double radius = args[2]->NumberValue();
147 double startAngle = args[3]->NumberValue();
148 double endAngle = args[4]->NumberValue();
149 bool antiClockwise = false;
150 if (args.Length() == 6) {
151 antiClockwise = args[5]->BooleanValue();
152 }
153 double sweepAngle;
154 if (!antiClockwise) {
155 sweepAngle = endAngle - startAngle;
156 } else {
157 sweepAngle = startAngle - endAngle;
158 startAngle = endAngle;
159 }
160
161 Path* path = Unwrap(args);
162 SkRect rect = {
163 SkDoubleToScalar(x-radius),
164 SkDoubleToScalar(y-radius),
165 SkDoubleToScalar(x+radius),
166 SkDoubleToScalar(y+radius)
167 };
168
169 path->fSkPath.addArc(rect, SkRadiansToDegrees(startAngle),
170 SkRadiansToDegrees(sweepAngle));
171}
172
173void Path::Rect(const v8::FunctionCallbackInfo<Value>& args) {
174 if (args.Length() != 4) {
175 args.GetIsolate()->ThrowException(
176 v8::String::NewFromUtf8(
177 args.GetIsolate(), "Error: 4 arguments required."));
178 return;
179 }
180 double x = args[0]->NumberValue();
181 double y = args[1]->NumberValue();
182 double w = args[2]->NumberValue();
183 double h = args[3]->NumberValue();
184
185 SkRect rect = {
186 SkDoubleToScalar(x),
187 SkDoubleToScalar(y),
188 SkDoubleToScalar(x) + SkDoubleToScalar(w),
189 SkDoubleToScalar(y) + SkDoubleToScalar(h)
190 };
191 Path* path = Unwrap(args);
192 path->fSkPath.addRect(rect);
193}