C++程序  |  245行  |  8 KB

/*
 * 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 "Path2D.h"
#include "Global.h"

Global* Path2D::gGlobal = NULL;

void Path2D::ConstructPath(const v8::FunctionCallbackInfo<Value>& args) {
    HandleScope handleScope(gGlobal->getIsolate());
    Path2D* path = new Path2D();
    args.This()->SetInternalField(
            0, External::New(gGlobal->getIsolate(), path));
}

#define ADD_METHOD(name, fn) \
    constructor->InstanceTemplate()->Set( \
            String::NewFromUtf8( \
                    global->getIsolate(), name, \
                    String::kInternalizedString), \
            FunctionTemplate::New(global->getIsolate(), fn))

// Install the constructor in the global scope so Path2Ds can be constructed
// in JS.
void Path2D::AddToGlobal(Global* global) {
    gGlobal = global;

    // Create a stack-allocated handle scope.
    HandleScope handleScope(gGlobal->getIsolate());

    Handle<Context> context = gGlobal->getContext();

    // Enter the scope so all operations take place in the scope.
    Context::Scope contextScope(context);

    Local<FunctionTemplate> constructor = FunctionTemplate::New(
            gGlobal->getIsolate(), Path2D::ConstructPath);
    constructor->InstanceTemplate()->SetInternalFieldCount(1);

    ADD_METHOD("closePath", 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);

    context->Global()->Set(String::NewFromUtf8(
            gGlobal->getIsolate(), "Path2D"), constructor->GetFunction());
}

Path2D* Path2D::Unwrap(const v8::FunctionCallbackInfo<Value>& args) {
    Handle<External> field = Handle<External>::Cast(
            args.This()->GetInternalField(0));
    void* ptr = field->Value();
    return static_cast<Path2D*>(ptr);
}

void Path2D::ClosePath(const v8::FunctionCallbackInfo<Value>& args) {
    Path2D* path = Unwrap(args);
    path->fSkPath.close();
}

void Path2D::MoveTo(const v8::FunctionCallbackInfo<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();
    Path2D* path = Unwrap(args);
    path->fSkPath.moveTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
}

void Path2D::LineTo(const v8::FunctionCallbackInfo<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();
    Path2D* path = Unwrap(args);
    path->fSkPath.lineTo(SkDoubleToScalar(x), SkDoubleToScalar(y));
}

void Path2D::QuadraticCurveTo(const v8::FunctionCallbackInfo<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();
    Path2D* 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 Path2D::BezierCurveTo(const v8::FunctionCallbackInfo<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();
    Path2D* 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 Path2D::Arc(const v8::FunctionCallbackInfo<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;
    }

    Path2D* 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 Path2D::Rect(const v8::FunctionCallbackInfo<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)
    };
    Path2D* path = Unwrap(args);
    path->fSkPath.addRect(rect);
}

void Path2D::Oval(const v8::FunctionCallbackInfo<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;
    }
    Path2D* path = Unwrap(args);
    SkRect rect = {
        SkDoubleToScalar(x-radiusX),
        SkDoubleToScalar(y-radiusX),
        SkDoubleToScalar(x+radiusY),
        SkDoubleToScalar(y+radiusY)
    };

    path->fSkPath.addOval(rect, dir);
}

void Path2D::ConicTo(const v8::FunctionCallbackInfo<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();
    Path2D* path = Unwrap(args);

    path->fSkPath.conicTo(
            SkDoubleToScalar(x1),
            SkDoubleToScalar(y1),
            SkDoubleToScalar(x2),
            SkDoubleToScalar(y2),
            SkDoubleToScalar(w)
            );
}