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#include <v8.h>
10
11#include "Global.h"
12#include "DrawingMethods.h"
13#include "Path2D.h"
14#include "SkCanvas.h"
15#include "SkPaint.h"
16
17
18DrawingMethods* DrawingMethods::Unwrap(v8::Handle<v8::Object> obj) {
19    v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(obj->GetInternalField(0));
20    void* ptr = field->Value();
21    return static_cast<DrawingMethods*>(ptr);
22}
23
24
25void DrawingMethods::Save(const v8::FunctionCallbackInfo<v8::Value>& args) {
26    DrawingMethods* drawingMethods = Unwrap(args.This());
27    SkCanvas* canvas = drawingMethods->getCanvas();
28    if (NULL == canvas) {
29        return;
30    }
31
32    canvas->save();
33}
34
35void DrawingMethods::Restore(const v8::FunctionCallbackInfo<v8::Value>& args) {
36    DrawingMethods* drawingMethods = Unwrap(args.This());
37    SkCanvas* canvas = drawingMethods->getCanvas();
38    if (NULL == canvas) {
39        return;
40    }
41
42    canvas->restore();
43}
44
45void DrawingMethods::Rotate(const v8::FunctionCallbackInfo<v8::Value>& args) {
46    DrawingMethods* drawingMethods = Unwrap(args.This());
47    SkCanvas* canvas = drawingMethods->getCanvas();
48    if (NULL == canvas) {
49        return;
50    }
51
52    if (args.Length() != 1) {
53        args.GetIsolate()->ThrowException(
54                v8::String::NewFromUtf8(
55                        args.GetIsolate(), "Error: 1 arguments required."));
56        return;
57    }
58    double angle = args[0]->NumberValue();
59    canvas->rotate(SkRadiansToDegrees(angle));
60}
61
62void DrawingMethods::Translate(const v8::FunctionCallbackInfo<v8::Value>& args) {
63    DrawingMethods* drawingMethods = Unwrap(args.This());
64    SkCanvas* canvas = drawingMethods->getCanvas();
65    if (NULL == canvas) {
66        return;
67    }
68
69    if (args.Length() != 2) {
70        args.GetIsolate()->ThrowException(
71                v8::String::NewFromUtf8(
72                        args.GetIsolate(), "Error: 2 arguments required."));
73        return;
74    }
75    double dx = args[0]->NumberValue();
76    double dy = args[1]->NumberValue();
77    canvas->translate(SkDoubleToScalar(dx), SkDoubleToScalar(dy));
78}
79
80void DrawingMethods::ResetTransform(const v8::FunctionCallbackInfo<v8::Value>& args) {
81    DrawingMethods* drawingMethods = Unwrap(args.This());
82    SkCanvas* canvas = drawingMethods->getCanvas();
83    if (NULL == canvas) {
84        return;
85    }
86
87    canvas->resetMatrix();
88}
89
90void DrawingMethods::DrawPath(const v8::FunctionCallbackInfo<v8::Value>& args) {
91    DrawingMethods* drawingMethods = Unwrap(args.This());
92    SkCanvas* canvas = drawingMethods->getCanvas();
93    if (NULL == canvas) {
94        return;
95    }
96
97    if (args.Length() != 1) {
98        args.GetIsolate()->ThrowException(
99                v8::String::NewFromUtf8(
100                        args.GetIsolate(), "Error: 1 argument required."));
101        return;
102    }
103
104    v8::Handle<v8::External> field = v8::Handle<v8::External>::Cast(
105            args[0]->ToObject()->GetInternalField(0));
106    void* ptr = field->Value();
107    Path2D* path = static_cast<Path2D*>(ptr);
108    if (NULL == path) {
109        return;
110    }
111    // TODO(jcgregorio) Add support for Paint2D parameter after Paint2D is
112    // implemented.
113    SkPaint fillStyle;
114    fillStyle.setColor(SK_ColorBLACK);
115    fillStyle.setAntiAlias(true);
116    fillStyle.setStyle(SkPaint::kFill_Style);
117    canvas->drawPath(*(path->path()), fillStyle);
118}
119
120
121void DrawingMethods::GetWidth(v8::Local<v8::String> name,
122        const v8::PropertyCallbackInfo<v8::Value>& info) {
123    DrawingMethods* drawingMethods = Unwrap(info.This());
124    SkCanvas* canvas = drawingMethods->getCanvas();
125    if (NULL == canvas) {
126        return;
127    }
128
129    info.GetReturnValue().Set(
130            v8::Int32::New(
131                drawingMethods->fGlobal->getIsolate(), canvas->imageInfo().width()));
132}
133
134void DrawingMethods::GetHeight(v8::Local<v8::String> name,
135        const v8::PropertyCallbackInfo<v8::Value>& info) {
136    DrawingMethods* drawingMethods = Unwrap(info.This());
137    SkCanvas* canvas = drawingMethods->getCanvas();
138    if (NULL == canvas) {
139        return;
140    }
141
142    info.GetReturnValue().Set(
143            v8::Int32::New(
144                drawingMethods->fGlobal->getIsolate(), canvas->imageInfo().height()));
145}
146
147#define ADD_METHOD(name, fn) \
148    tmpl->Set(v8::String::NewFromUtf8( \
149         fGlobal->getIsolate(), name, \
150         v8::String::kInternalizedString), \
151             v8::FunctionTemplate::New(fGlobal->getIsolate(), fn))
152
153void DrawingMethods::addAttributesAndMethods(v8::Handle<v8::ObjectTemplate> tmpl) {
154    v8::HandleScope scope(fGlobal->getIsolate());
155
156    // Add accessors for each of the fields of the context object.
157    tmpl->SetAccessor(v8::String::NewFromUtf8(
158        fGlobal->getIsolate(), "width", v8::String::kInternalizedString),
159            GetWidth);
160    tmpl->SetAccessor(v8::String::NewFromUtf8(
161        fGlobal->getIsolate(), "height", v8::String::kInternalizedString),
162            GetHeight);
163
164    // Add methods.
165    ADD_METHOD("save", Save);
166    ADD_METHOD("restore", Restore);
167    ADD_METHOD("rotate", Rotate);
168    ADD_METHOD("translate", Translate);
169    ADD_METHOD("resetTransform", ResetTransform);
170
171    ADD_METHOD("drawPath", DrawPath);
172}
173