SkV8Example.cpp revision 80bd0c995d9ec6a70330d6dc3f2f8dd387701d1d
1/*
2 * Copyright 2013 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
11using namespace v8;
12
13#include "SkV8Example.h"
14
15#include "gl/GrGLUtil.h"
16#include "gl/GrGLDefines.h"
17#include "gl/GrGLInterface.h"
18#include "SkApplication.h"
19#include "SkDraw.h"
20#include "SkGpuDevice.h"
21#include "SkGraphics.h"
22
23
24void application_init() {
25    SkGraphics::Init();
26    SkEvent::Init();
27}
28
29void application_term() {
30    SkEvent::Term();
31    SkGraphics::Term();
32}
33
34// Extracts a C string from a V8 Utf8Value.
35const char* ToCString(const v8::String::Utf8Value& value) {
36  return *value ? *value : "<string conversion failed>";
37}
38
39// Slight modification to an original function found in the V8 sample shell.cc.
40void reportException(Isolate* isolate, TryCatch* try_catch) {
41  HandleScope handle_scope(isolate);
42  String::Utf8Value exception(try_catch->Exception());
43  const char* exception_string = ToCString(exception);
44  Handle<Message> message = try_catch->Message();
45  if (message.IsEmpty()) {
46    // V8 didn't provide any extra information about this error; just
47    // print the exception.
48    fprintf(stderr, "%s\n", exception_string);
49  } else {
50    // Print (filename):(line number): (message).
51    String::Utf8Value filename(message->GetScriptResourceName());
52    const char* filename_string = ToCString(filename);
53    int linenum = message->GetLineNumber();
54    fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string);
55    // Print line of source code.
56    String::Utf8Value sourceline(message->GetSourceLine());
57    const char* sourceline_string = ToCString(sourceline);
58    fprintf(stderr, "%s\n", sourceline_string);
59    // Print wavy underline.
60    int start = message->GetStartColumn();
61    for (int i = 0; i < start; i++) {
62      fprintf(stderr, " ");
63    }
64    int end = message->GetEndColumn();
65    for (int i = start; i < end; i++) {
66      fprintf(stderr, "^");
67    }
68    fprintf(stderr, "\n");
69    String::Utf8Value stack_trace(try_catch->StackTrace());
70    if (stack_trace.length() > 0) {
71      const char* stack_trace_string = ToCString(stack_trace);
72      fprintf(stderr, "%s\n", stack_trace_string);
73    }
74  }
75}
76
77SkV8ExampleWindow::SkV8ExampleWindow(void* hwnd,
78                     Isolate* isolate,
79                     Handle<Context> context,
80                     Handle<Script> script)
81    : INHERITED(hwnd)
82    , fIsolate(isolate)
83{
84    // Convert the Handle<> objects into Persistent<> objects using Reset().
85    fContext.Reset(isolate, context);
86    fScript.Reset(isolate, script);
87
88    fRotationAngle = SkIntToScalar(0);
89    this->setConfig(SkBitmap::kARGB_8888_Config);
90    this->setVisibleP(true);
91    this->setClipToBounds(false);
92}
93
94// Simple global for the Draw function.
95SkCanvas* gCanvas = NULL;
96
97
98// Draw is called from within V8 when the Javascript function draw() is called.
99void Draw(const v8::FunctionCallbackInfo<v8::Value>& args) {
100  if (NULL == gCanvas) {
101    printf("Can't Draw Now.\n");
102    return;
103  }
104
105  gCanvas->drawColor(SK_ColorWHITE);
106  SkPaint paint;
107  paint.setColor(SK_ColorRED);
108
109  // Draw a rectangle with blue paint
110  SkRect rect = {
111    SkIntToScalar(10), SkIntToScalar(10),
112    SkIntToScalar(128), SkIntToScalar(128)
113  };
114  gCanvas->drawRect(rect, paint);
115}
116
117void SkV8ExampleWindow::onDraw(SkCanvas* canvas) {
118  printf("Draw\n");
119
120  gCanvas = canvas;
121  canvas->save();
122  fRotationAngle += SkDoubleToScalar(0.2);
123  if (fRotationAngle > SkDoubleToScalar(360.0)) {
124    fRotationAngle -= SkDoubleToScalar(360.0);
125  }
126  canvas->rotate(fRotationAngle);
127
128  // Create a Handle scope for temporary references.
129  HandleScope handle_scope(fIsolate);
130
131  // Create a local context from our persistent context.
132  Local<Context> context =
133            Local<Context>::New(fIsolate, fContext);
134
135  // Enter the context so all operations take place within it.
136  Context::Scope context_scope(context);
137
138  TryCatch try_catch;
139
140  // Create a local script from our persistent script.
141  Local<Script> script =
142            Local<Script>::New(fIsolate, fScript);
143
144  // Run the script.
145  Handle<Value> result = script->Run();
146
147  if (result.IsEmpty()) {
148    SkASSERT(try_catch.HasCaught());
149    // Print errors that happened during execution.
150    reportException(fIsolate, &try_catch);
151  } else {
152    SkASSERT(!try_catch.HasCaught());
153    if (!result->IsUndefined()) {
154      // If all went well and the result wasn't undefined then print
155      // the returned value.
156      String::Utf8Value str(result);
157      const char* cstr = ToCString(str);
158      printf("%s\n", cstr);
159    }
160  }
161
162  canvas->restore();
163
164  // Trigger an invalidation which should trigger another redraw to simulate
165  // animation.
166  this->inval(NULL);
167
168  INHERITED::onDraw(canvas);
169}
170
171
172#ifdef SK_BUILD_FOR_WIN
173void SkV8ExampleWindow::onHandleInval(const SkIRect& rect) {
174    RECT winRect;
175    winRect.top = rect.top();
176    winRect.bottom = rect.bottom();
177    winRect.right = rect.right();
178    winRect.left = rect.left();
179    InvalidateRect((HWND)this->getHWND(), &winRect, false);
180}
181#endif
182
183// Creates a new execution environment containing the built-in
184// function draw().
185Handle<Context> createRootContext(Isolate* isolate) {
186  // Create a template for the global object.
187  Handle<ObjectTemplate> global = ObjectTemplate::New();
188  // Bind the global 'draw' function to the C++ Draw callback.
189  global->Set(String::NewFromUtf8(isolate, "draw"),
190              FunctionTemplate::New(Draw));
191
192  return Context::New(isolate, NULL, global);
193}
194
195SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
196  printf("Started\n");
197
198  // Get the default Isolate created at startup.
199  Isolate* isolate = Isolate::GetCurrent();
200  printf("Isolate\n");
201
202  // Create a stack-allocated handle scope.
203  HandleScope handle_scope(isolate);
204
205  printf("Before create context\n");
206  // Create a new context.
207  //
208  Handle<Context> context = createRootContext(isolate);
209
210  // Enter the scope so all operations take place in the scope.
211  Context::Scope context_scope(context);
212
213  v8::TryCatch try_catch;
214
215  // Compile the source code.
216  Handle<String> source = String::NewFromUtf8(isolate, "draw();");
217  printf("Before Compile\n");
218  Handle<Script> script = Script::Compile(source);
219  printf("After Compile\n");
220
221  // Try running it now. It won't have a valid context, but shouldn't fail.
222  script->Run();
223
224  if (script.IsEmpty()) {
225    // Print errors that happened during compilation.
226    reportException(isolate, &try_catch);
227    exit(1);
228  }
229  printf("After Exception.\n");
230
231  // SkV8ExampleWindow will make persistent handles to hold the context and script.
232  return new SkV8ExampleWindow(hwnd, isolate, context, script);
233}
234