262 lines
8.7 KiB
C++
262 lines
8.7 KiB
C++
|
/*
|
||
|
* Copyright 2014 Google Inc.
|
||
|
*
|
||
|
*
|
||
|
* Use of this source code is governed by a BSD-style license that can be
|
||
|
* found in the LICENSE file.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
#include "Global.h"
|
||
|
#include "Path2DBuilder.h"
|
||
|
#include "Path2D.h"
|
||
|
#include "SkPath.h"
|
||
|
|
||
|
Global* Path2DBuilder::gGlobal = NULL;
|
||
|
|
||
|
void Path2DBuilder::ConstructPath(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
v8::HandleScope handleScope(gGlobal->getIsolate());
|
||
|
Path2DBuilder* path = new Path2DBuilder();
|
||
|
args.This()->SetInternalField(
|
||
|
0, v8::External::New(gGlobal->getIsolate(), path));
|
||
|
}
|
||
|
|
||
|
#define ADD_METHOD(name, fn) \
|
||
|
constructor->InstanceTemplate()->Set( \
|
||
|
v8::String::NewFromUtf8( \
|
||
|
global->getIsolate(), name, \
|
||
|
v8::String::kInternalizedString), \
|
||
|
v8::FunctionTemplate::New(global->getIsolate(), fn))
|
||
|
|
||
|
// Install the constructor in the global scope so Path2DBuilders can be constructed
|
||
|
// in JS.
|
||
|
void Path2DBuilder::AddToGlobal(Global* global) {
|
||
|
gGlobal = global;
|
||
|
|
||
|
// Create a stack-allocated handle scope.
|
||
|
v8::HandleScope handleScope(gGlobal->getIsolate());
|
||
|
|
||
|
v8::Handle<v8::Context> context = gGlobal->getContext();
|
||
|
|
||
|
// Enter the scope so all operations take place in the scope.
|
||
|
v8::Context::Scope contextScope(context);
|
||
|
|
||
|
v8::Local<v8::FunctionTemplate> constructor = v8::FunctionTemplate::New(
|
||
|
gGlobal->getIsolate(), Path2DBuilder::ConstructPath);
|
||
|
constructor->InstanceTemplate()->SetInternalFieldCount(1);
|
||
|
|
||
|
ADD_METHOD("close", ClosePath);
|
||
|
ADD_METHOD("moveTo", MoveTo);
|
||
|
ADD_METHOD("lineTo", LineTo);
|
||
|
ADD_METHOD("quadraticCurveTo", QuadraticCurveTo);
|
||
|
ADD_METHOD("bezierCurveTo", BezierCurveTo);
|
||
|
ADD_METHOD("arc", Arc);
|
||
|
ADD_METHOD("rect", Rect);
|
||
|
ADD_METHOD("oval", Oval);
|
||
|
ADD_METHOD("conicTo", ConicTo);
|
||
|
|
||
|
ADD_METHOD("finalize", Finalize);
|
||
|
|
||
|
context->Global()->Set(v8::String::NewFromUtf8(
|
||
|
gGlobal->getIsolate(), "Path2DBuilder"), constructor->GetFunction());
|
||
|
}
|
||
|
|
||
|
Path2DBuilder* Path2DBuilder::Unwrap(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(
|
||
|
args.This()->GetInternalField(0));
|
||
|
void* ptr = field->Value();
|
||
|
return static_cast<Path2DBuilder*>(ptr);
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::ClosePath(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
path->fSkPath.close();
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::MoveTo(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 2) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 2 arguments required."));
|
||
|
return;
|
||
|
}
|
||
|
double x = args[0]->NumberValue();
|
||
|
double y = args[1]->NumberValue();
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
path->fSkPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::LineTo(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 2) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 2 arguments required."));
|
||
|
return;
|
||
|
}
|
||
|
double x = args[0]->NumberValue();
|
||
|
double y = args[1]->NumberValue();
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
path->fSkPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::QuadraticCurveTo(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 4) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 4 arguments required."));
|
||
|
return;
|
||
|
}
|
||
|
double cpx = args[0]->NumberValue();
|
||
|
double cpy = args[1]->NumberValue();
|
||
|
double x = args[2]->NumberValue();
|
||
|
double y = args[3]->NumberValue();
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
// TODO(jcgregorio) Doesn't handle the empty last path case correctly per
|
||
|
// the HTML 5 spec.
|
||
|
path->fSkPath.quadTo(
|
||
|
SkDoubleToScalar(cpx), SkDoubleToScalar(cpy),
|
||
|
SkDoubleToScalar(x), SkDoubleToScalar(y));
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::BezierCurveTo(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 6) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 6 arguments required."));
|
||
|
return;
|
||
|
}
|
||
|
double cp1x = args[0]->NumberValue();
|
||
|
double cp1y = args[1]->NumberValue();
|
||
|
double cp2x = args[2]->NumberValue();
|
||
|
double cp2y = args[3]->NumberValue();
|
||
|
double x = args[4]->NumberValue();
|
||
|
double y = args[5]->NumberValue();
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
// TODO(jcgregorio) Doesn't handle the empty last path case correctly per
|
||
|
// the HTML 5 spec.
|
||
|
path->fSkPath.cubicTo(
|
||
|
SkDoubleToScalar(cp1x), SkDoubleToScalar(cp1y),
|
||
|
SkDoubleToScalar(cp2x), SkDoubleToScalar(cp2y),
|
||
|
SkDoubleToScalar(x), SkDoubleToScalar(y));
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::Arc(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 5 && args.Length() != 6) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 5 or 6 args required."));
|
||
|
return;
|
||
|
}
|
||
|
double x = args[0]->NumberValue();
|
||
|
double y = args[1]->NumberValue();
|
||
|
double radius = args[2]->NumberValue();
|
||
|
double startAngle = args[3]->NumberValue();
|
||
|
double endAngle = args[4]->NumberValue();
|
||
|
bool antiClockwise = false;
|
||
|
if (args.Length() == 6) {
|
||
|
antiClockwise = args[5]->BooleanValue();
|
||
|
}
|
||
|
double sweepAngle;
|
||
|
if (!antiClockwise) {
|
||
|
sweepAngle = endAngle - startAngle;
|
||
|
} else {
|
||
|
sweepAngle = startAngle - endAngle;
|
||
|
startAngle = endAngle;
|
||
|
}
|
||
|
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
SkRect rect = {
|
||
|
SkDoubleToScalar(x-radius),
|
||
|
SkDoubleToScalar(y-radius),
|
||
|
SkDoubleToScalar(x+radius),
|
||
|
SkDoubleToScalar(y+radius)
|
||
|
};
|
||
|
|
||
|
path->fSkPath.addArc(rect, SkRadiansToDegrees(startAngle),
|
||
|
SkRadiansToDegrees(sweepAngle));
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::Rect(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 4) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 4 arguments required."));
|
||
|
return;
|
||
|
}
|
||
|
double x = args[0]->NumberValue();
|
||
|
double y = args[1]->NumberValue();
|
||
|
double w = args[2]->NumberValue();
|
||
|
double h = args[3]->NumberValue();
|
||
|
|
||
|
SkRect rect = {
|
||
|
SkDoubleToScalar(x),
|
||
|
SkDoubleToScalar(y),
|
||
|
SkDoubleToScalar(x) + SkDoubleToScalar(w),
|
||
|
SkDoubleToScalar(y) + SkDoubleToScalar(h)
|
||
|
};
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
path->fSkPath.addRect(rect);
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::Oval(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 4 && args.Length() != 5) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 4 or 5 args required."));
|
||
|
return;
|
||
|
}
|
||
|
double x = args[0]->NumberValue();
|
||
|
double y = args[1]->NumberValue();
|
||
|
double radiusX = args[2]->NumberValue();
|
||
|
double radiusY = args[3]->NumberValue();
|
||
|
SkPath::Direction dir = SkPath::kCW_Direction;
|
||
|
if (args.Length() == 5 && !args[4]->BooleanValue()) {
|
||
|
dir = SkPath::kCCW_Direction;
|
||
|
}
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
SkRect rect = {
|
||
|
SkDoubleToScalar(x-radiusX),
|
||
|
SkDoubleToScalar(y-radiusX),
|
||
|
SkDoubleToScalar(x+radiusY),
|
||
|
SkDoubleToScalar(y+radiusY)
|
||
|
};
|
||
|
|
||
|
path->fSkPath.addOval(rect, dir);
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::ConicTo(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
if (args.Length() != 5) {
|
||
|
args.GetIsolate()->ThrowException(
|
||
|
v8::String::NewFromUtf8(
|
||
|
args.GetIsolate(), "Error: 5 args required."));
|
||
|
return;
|
||
|
}
|
||
|
double x1 = args[0]->NumberValue();
|
||
|
double y1 = args[1]->NumberValue();
|
||
|
double x2 = args[2]->NumberValue();
|
||
|
double y2 = args[3]->NumberValue();
|
||
|
double w = args[4]->NumberValue();
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
|
||
|
path->fSkPath.conicTo(
|
||
|
SkDoubleToScalar(x1),
|
||
|
SkDoubleToScalar(y1),
|
||
|
SkDoubleToScalar(x2),
|
||
|
SkDoubleToScalar(y2),
|
||
|
SkDoubleToScalar(w)
|
||
|
);
|
||
|
}
|
||
|
|
||
|
void Path2DBuilder::Finalize(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||
|
Path2DBuilder* path = Unwrap(args);
|
||
|
|
||
|
// Build Path2D from out fSkPath and return it.
|
||
|
SkPath* skPath = new SkPath(path->fSkPath);
|
||
|
|
||
|
path->fSkPath.reset();
|
||
|
|
||
|
Path2D* pathWrap = new Path2D(skPath);
|
||
|
|
||
|
args.GetReturnValue().Set(pathWrap->persistent());
|
||
|
}
|