Chromium Code Reviews| Index: experimental/SkV8Example/Global.cpp |
| diff --git a/experimental/SkV8Example/Global.cpp b/experimental/SkV8Example/Global.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..265f4413c98acb25ac96044569696d494cfb05c7 |
| --- /dev/null |
| +++ b/experimental/SkV8Example/Global.cpp |
| @@ -0,0 +1,224 @@ |
| +#include "Global.h" |
|
robertphillips
2013/12/17 23:35:53
Header!
jcgregorio
2013/12/18 04:32:53
Done.
|
| + |
| +#include "SkWindow.h" |
| +#include "SkEvent.h" |
| + |
| + |
| +Global* Global::gGlobal = NULL; |
| + |
| +// Extracts a C string from a V8 Utf8Value. |
|
robertphillips
2013/12/17 23:35:53
to_cstring?
jcgregorio
2013/12/18 04:32:53
Done.
|
| +static const char* ToCString(const v8::String::Utf8Value& value) { |
| + return *value ? *value : "<string conversion failed>"; |
| +} |
| + |
| +// Slight modification to an original function found in the V8 sample shell.cc. |
|
robertphillips
2013/12/17 23:35:53
tryCatch?
jcgregorio
2013/12/18 04:32:53
Done.
|
| +void Global::reportException(TryCatch* try_catch) { |
| + HandleScope handleScope(fIsolate); |
| + String::Utf8Value exception(try_catch->Exception()); |
|
robertphillips
2013/12/17 23:35:53
exceptionString?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + const char* exception_string = ToCString(exception); |
| + Handle<Message> message = try_catch->Message(); |
| + if (message.IsEmpty()) { |
| + // V8 didn't provide any extra information about this error; just |
| + // print the exception. |
| + fprintf(stderr, "%s\n", exception_string); |
| + } else { |
| + // Print (filename):(line number): (message). |
| + String::Utf8Value filename(message->GetScriptResourceName()); |
|
robertphillips
2013/12/17 23:35:53
filenameString?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + const char* filename_string = ToCString(filename); |
| + int linenum = message->GetLineNumber(); |
| + fprintf(stderr, |
| + "%s:%i: %s\n", filename_string, linenum, exception_string); |
| + // Print line of source code. |
| + String::Utf8Value sourceline(message->GetSourceLine()); |
|
robertphillips
2013/12/17 23:35:53
sourceLineString?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + const char* sourceline_string = ToCString(sourceline); |
| + fprintf(stderr, "%s\n", sourceline_string); |
| + // Print wavy underline. |
| + int start = message->GetStartColumn(); |
| + for (int i = 0; i < start; i++) { |
| + fprintf(stderr, " "); |
| + } |
| + int end = message->GetEndColumn(); |
| + for (int i = start; i < end; i++) { |
| + fprintf(stderr, "^"); |
| + } |
| + fprintf(stderr, "\n"); |
| + String::Utf8Value stack_trace(try_catch->StackTrace()); |
| + if (stack_trace.length() > 0) { |
|
robertphillips
2013/12/17 23:35:53
stackTraceString?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + const char* stack_trace_string = ToCString(stack_trace); |
| + fprintf(stderr, "%s\n", stack_trace_string); |
| + } |
| + } |
| +} |
| + |
| +// The callback that implements the JavaScript 'inval' function. |
| +// Invalidates the current window, forcing a redraw. |
| +// |
| +// JS: inval(); |
| +void Global::Inval(const v8::FunctionCallbackInfo<Value>& args) { |
| + gGlobal->getWindow()->inval(NULL); |
| +} |
| + |
| +// The callback that is invoked by v8 whenever the JavaScript 'print' |
| +// function is called. Prints its arguments on stdout separated by |
| +// spaces and ending with a newline. |
| +// |
| +// JS: print("foo", "bar"); |
| +void Global::Print(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| + bool first = true; |
|
robertphillips
2013/12/17 23:35:53
handleScope?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + HandleScope handle_scope(args.GetIsolate()); |
| + for (int i = 0; i < args.Length(); i++) { |
| + if (first) { |
| + first = false; |
| + } else { |
| + printf(" "); |
| + } |
| + v8::String::Utf8Value str(args[i]); |
| + printf("%s", ToCString(str)); |
| + } |
| + printf("\n"); |
| + fflush(stdout); |
| +} |
| + |
| +// The callback that is invoked by v8 whenever the JavaScript 'setTimeout' |
| +// function is called. |
| +// |
| +// JS: setTimeout(on_timeout, 500); |
| +// |
| +// TODO(jcgregorio) Currently only handles one timeout, should support any |
| +// number. |
| +void Global::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| + if (args.Length() != 2) { |
| + args.GetIsolate()->ThrowException( |
| + v8::String::NewFromUtf8( |
| + args.GetIsolate(), "Error: 2 arguments required.")); |
| + return; |
| + } |
| + |
| + // Pull out the first arg, make sure it's a function. |
| + if (!args[0]->IsFunction()) { |
| + printf("Not a function passed to setTimeout.\n"); |
| + return; |
| + } |
|
robertphillips
2013/12/17 23:35:53
timeoutFn?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + Handle<Function> timeout_fn = Handle<Function>::Cast(args[0]); |
| + gGlobal->fTimeout.Reset(args.GetIsolate(), timeout_fn); |
| + |
| + double delay = args[1]->NumberValue(); |
| + |
| + // Create an SkEvent and add it with the right delay. |
| + (new SkEvent())->setTargetProc(Global::TimeOutProc)->postDelay(delay); |
| + |
| + // TODO(jcgregorio) Return the ID as the return value. |
| +} |
| + |
| +// Callback function for SkEvents used to implement timeouts. |
| +bool Global::TimeOutProc(const SkEvent& evt) { |
| + // Create a handle scope to keep the temporary object references. |
| + HandleScope handleScope(gGlobal->getIsolate()); |
| + |
| + // Create a local context from our global context. |
| + Local<Context> context = gGlobal->getContext(); |
| + |
| + // Enter the context so all the remaining operations take place there. |
| + Context::Scope contextScope(context); |
| + |
| + // Set up an exception handler before calling the Process function. |
| + TryCatch tryCatch; |
| + |
| + const int argc = 0; |
| + Local<Function> onTimeout = |
| + Local<Function>::New(gGlobal->getIsolate(), gGlobal->fTimeout); |
| + Handle<Value> result = onTimeout->Call(context->Global(), argc, NULL); |
| + |
| + // Handle any exceptions or output. |
| + if (result.IsEmpty()) { |
| + SkASSERT(tryCatch.HasCaught()); |
| + // Print errors that happened during execution. |
| + gGlobal->reportException(&tryCatch); |
| + } else { |
| + SkASSERT(!tryCatch.HasCaught()); |
| + if (!result->IsUndefined()) { |
| + // If all went well and the result wasn't undefined then print the |
| + // returned value. |
| + String::Utf8Value str(result); |
| + const char* cstr = ToCString(str); |
| + printf("%s\n", cstr); |
| + } |
| + } |
| + return true; |
| +} |
| + |
| +// Creates a new execution environment containing the built-in functions. |
| +Handle<Context> Global::createRootContext() { |
| + // Create a template for the global object. |
| + Handle<ObjectTemplate> global = ObjectTemplate::New(); |
| + |
| + global->Set(v8::String::NewFromUtf8(fIsolate, "print"), |
| + v8::FunctionTemplate::New(Global::Print)); |
| + global->Set(v8::String::NewFromUtf8(fIsolate, "setTimeout"), |
| + v8::FunctionTemplate::New(Global::SetTimeout)); |
| + global->Set(v8::String::NewFromUtf8(fIsolate, "inval"), |
| + v8::FunctionTemplate::New(Global::Inval)); |
| + |
| + |
| + return Context::New(fIsolate, NULL, global); |
| +} |
| + |
| + |
| +// Creates the root context, parses the script into it, then stores the |
| +// context in a global. |
| +// |
| +// TODO(jcgregorio) Currently only handles one script. Need to move |
| +// createRootContext to another call that's only done once. |
| +bool Global::parseScript(const char script[]) { |
| + |
| + // Create a stack-allocated handle scope. |
| + HandleScope handleScope(fIsolate); |
| + |
| + printf("Before create context\n"); |
| + |
| + // Create a new context. |
| + Handle<Context> context = this->createRootContext(); |
| + |
| + // Enter the scope so all operations take place in the scope. |
| + Context::Scope contextScope(context); |
| + |
|
robertphillips
2013/12/17 23:35:53
tryCatch?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + v8::TryCatch try_catch; |
| + |
| + // Compile the source code. |
| + Handle<String> source = String::NewFromUtf8(fIsolate, script); |
| + printf("Before Compile\n"); |
|
robertphillips
2013/12/17 23:35:53
compiledScript?
jcgregorio
2013/12/18 04:32:53
Done.
|
| + Handle<Script> compiled_script = Script::Compile(source); |
| + printf("After Compile\n"); |
| + |
| + if (compiled_script.IsEmpty()) { |
| + // Print errors that happened during compilation. |
| + this->reportException(&try_catch); |
| + return false; |
| + } |
| + printf("After Exception.\n"); |
| + |
| + // Try running it now to create the onDraw function. |
| + Handle<Value> result = compiled_script->Run(); |
| + |
| + // Handle any exceptions or output. |
| + if (result.IsEmpty()) { |
| + SkASSERT(try_catch.HasCaught()); |
| + // Print errors that happened during execution. |
| + this->reportException(&try_catch); |
| + return false; |
| + } else { |
| + SkASSERT(!try_catch.HasCaught()); |
| + if (!result->IsUndefined()) { |
| + // If all went well and the result wasn't undefined then print |
| + // the returned value. |
| + String::Utf8Value str(result); |
| + const char* cstr = ToCString(str); |
| + printf("%s\n", cstr); |
| + return false; |
| + } |
| + } |
| + |
| + // Also make the context persistent. |
| + fContext.Reset(fIsolate, context); |
| + return true; |
| +} |