1
2/*
3 * Copyright 2013 Google Inc.
4 *
5 *
6 * Use of this source code is governed by a BSD-style license that can be
7 * found in the LICENSE file.
8 *
9 */
10#include <v8.h>
11
12using namespace v8;
13
14#include "Global.h"
15#include "JsContext.h"
16#include "Path2D.h"
17#include "SkCanvas.h"
18
19
20// Extracts a C string from a V8 Utf8Value.
21// TODO(jcgregrio) Currently dup'd in two files, fix.
22static const char* to_cstring(const v8::String::Utf8Value& value) {
23    return *value ? *value : "<string conversion failed>";
24}
25
26Persistent<ObjectTemplate> JsContext::gContextTemplate;
27
28// Wraps 'this' in a Javascript object.
29Handle<Object> JsContext::wrap() {
30    // Handle scope for temporary handles.
31    EscapableHandleScope handleScope(fGlobal->getIsolate());
32
33    // Fetch the template for creating JavaScript JsContext wrappers.
34    // It only has to be created once, which we do on demand.
35    if (gContextTemplate.IsEmpty()) {
36        Local<ObjectTemplate> localTemplate = ObjectTemplate::New();
37
38        // Add a field to store the pointer to a JsContext instance.
39        localTemplate->SetInternalFieldCount(1);
40
41        this->addAttributesAndMethods(localTemplate);
42
43        gContextTemplate.Reset(fGlobal->getIsolate(), localTemplate);
44    }
45    Handle<ObjectTemplate> templ =
46            Local<ObjectTemplate>::New(fGlobal->getIsolate(), gContextTemplate);
47
48    // Create an empty JsContext wrapper.
49    Local<Object> result = templ->NewInstance();
50
51    // Wrap the raw C++ pointer in an External so it can be referenced
52    // from within JavaScript.
53    Handle<External> contextPtr = External::New(fGlobal->getIsolate(), this);
54
55    // Store the context pointer in the JavaScript wrapper.
56    result->SetInternalField(0, contextPtr);
57
58    // Return the result through the current handle scope.  Since each
59    // of these handles will go away when the handle scope is deleted
60    // we need to call Close to let one, the result, escape into the
61    // outer handle scope.
62    return handleScope.Escape(result);
63}
64
65void JsContext::onDraw(SkCanvas* canvas) {
66    // Record canvas and window in this.
67    fCanvas = canvas;
68
69    // Create a handle scope to keep the temporary object references.
70    HandleScope handleScope(fGlobal->getIsolate());
71
72    // Create a local context from our global context.
73    Local<Context> context = fGlobal->getContext();
74
75    // Enter the context so all the remaining operations take place there.
76    Context::Scope contextScope(context);
77
78    // Wrap the C++ this pointer in a JavaScript wrapper.
79    Handle<Object> contextObj = this->wrap();
80
81    // Set up an exception handler before calling the Process function.
82    TryCatch tryCatch;
83
84    // Invoke the process function, giving the global object as 'this'
85    // and one argument, this JsContext.
86    const int argc = 1;
87    Handle<Value> argv[argc] = { contextObj };
88    Local<Function> onDraw =
89            Local<Function>::New(fGlobal->getIsolate(), fOnDraw);
90    Handle<Value> result = onDraw->Call(context->Global(), argc, argv);
91
92    // Handle any exceptions or output.
93    if (result.IsEmpty()) {
94        SkASSERT(tryCatch.HasCaught());
95        // Print errors that happened during execution.
96        fGlobal->reportException(&tryCatch);
97    } else {
98        SkASSERT(!tryCatch.HasCaught());
99        if (!result->IsUndefined()) {
100            // If all went well and the result wasn't undefined then print
101            // the returned value.
102            String::Utf8Value str(result);
103            const char* cstr = to_cstring(str);
104            printf("%s\n", cstr);
105        }
106    }
107}
108
109// Fetch the onDraw function from the global context.
110bool JsContext::initialize() {
111
112    // Create a stack-allocated handle scope.
113    HandleScope handleScope(fGlobal->getIsolate());
114
115    // Create a local context from our global context.
116    Local<Context> context = fGlobal->getContext();
117
118    // Enter the scope so all operations take place in the scope.
119    Context::Scope contextScope(context);
120
121    v8::TryCatch try_catch;
122
123    Handle<String> fn_name = String::NewFromUtf8(
124        fGlobal->getIsolate(), "onDraw");
125    Handle<Value> fn_val = context->Global()->Get(fn_name);
126
127    if (!fn_val->IsFunction()) {
128        printf("Not a function.\n");
129        return false;
130    }
131
132    // It is a function; cast it to a Function.
133    Handle<Function> fn_fun = Handle<Function>::Cast(fn_val);
134
135    // Store the function in a Persistent handle, since we also want that to
136    // remain after this call returns.
137    fOnDraw.Reset(fGlobal->getIsolate(), fn_fun);
138
139    return true;
140}
141