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