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 "Global.h" 11 #include "Path2DBuilder.h" 12 #include "Path2D.h" 13 #include "SkPath.h" 14 15 Global* Path2DBuilder::gGlobal = NULL; 16 17 void 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. 33 void 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 64 Path2DBuilder* 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 71 void Path2DBuilder::ClosePath(const v8::FunctionCallbackInfo<v8::Value>& args) { 72 Path2DBuilder* path = Unwrap(args); 73 path->fSkPath.close(); 74 } 75 76 void 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 89 void 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 102 void 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 121 void 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 143 void 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 179 void 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 201 void 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 227 void 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 250 void 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 } 262