Home | History | Annotate | Download | only in SkV8Example
      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 
     12 using 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.
     22 static const char* to_cstring(const v8::String::Utf8Value& value) {
     23     return *value ? *value : "<string conversion failed>";
     24 }
     25 
     26 Persistent<ObjectTemplate> JsContext::gContextTemplate;
     27 
     28 // Wraps 'this' in a Javascript object.
     29 Handle<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 
     65 void 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.
    110 bool 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