OLD | NEW |
(Empty) | |
| 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 "Global.h" |
| 10 |
| 11 #include "SkWindow.h" |
| 12 #include "SkEvent.h" |
| 13 |
| 14 |
| 15 Global* Global::gGlobal = NULL; |
| 16 |
| 17 // Extracts a C string from a V8 Utf8Value. |
| 18 static const char* to_cstring(const v8::String::Utf8Value& value) { |
| 19 return *value ? *value : "<string conversion failed>"; |
| 20 } |
| 21 |
| 22 // Slight modification to an original function found in the V8 sample shell.cc. |
| 23 void Global::reportException(TryCatch* tryCatch) { |
| 24 HandleScope handleScope(fIsolate); |
| 25 String::Utf8Value exception(tryCatch->Exception()); |
| 26 const char* exceptionString = to_cstring(exception); |
| 27 Handle<Message> message = tryCatch->Message(); |
| 28 if (message.IsEmpty()) { |
| 29 // V8 didn't provide any extra information about this error; just |
| 30 // print the exception. |
| 31 fprintf(stderr, "%s\n", exceptionString); |
| 32 } else { |
| 33 // Print (filename):(line number): (message). |
| 34 String::Utf8Value filename(message->GetScriptResourceName()); |
| 35 const char* filenameString = to_cstring(filename); |
| 36 int linenum = message->GetLineNumber(); |
| 37 fprintf(stderr, |
| 38 "%s:%i: %s\n", filenameString, linenum, exceptionString); |
| 39 // Print line of source code. |
| 40 String::Utf8Value sourceline(message->GetSourceLine()); |
| 41 const char* sourceLineString = to_cstring(sourceline); |
| 42 fprintf(stderr, "%s\n", sourceLineString); |
| 43 // Print wavy underline. |
| 44 int start = message->GetStartColumn(); |
| 45 for (int i = 0; i < start; i++) { |
| 46 fprintf(stderr, " "); |
| 47 } |
| 48 int end = message->GetEndColumn(); |
| 49 for (int i = start; i < end; i++) { |
| 50 fprintf(stderr, "^"); |
| 51 } |
| 52 fprintf(stderr, "\n"); |
| 53 String::Utf8Value stackTrace(tryCatch->StackTrace()); |
| 54 if (stackTrace.length() > 0) { |
| 55 const char* stackTraceString = to_cstring(stackTrace); |
| 56 fprintf(stderr, "%s\n", stackTraceString); |
| 57 } |
| 58 } |
| 59 } |
| 60 |
| 61 // The callback that implements the JavaScript 'inval' function. |
| 62 // Invalidates the current window, forcing a redraw. |
| 63 // |
| 64 // JS: inval(); |
| 65 void Global::Inval(const v8::FunctionCallbackInfo<Value>& args) { |
| 66 gGlobal->getWindow()->inval(NULL); |
| 67 } |
| 68 |
| 69 // The callback that is invoked by v8 whenever the JavaScript 'print' |
| 70 // function is called. Prints its arguments on stdout separated by |
| 71 // spaces and ending with a newline. |
| 72 // |
| 73 // JS: print("foo", "bar"); |
| 74 void Global::Print(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 75 bool first = true; |
| 76 HandleScope handleScope(args.GetIsolate()); |
| 77 for (int i = 0; i < args.Length(); i++) { |
| 78 if (first) { |
| 79 first = false; |
| 80 } else { |
| 81 printf(" "); |
| 82 } |
| 83 v8::String::Utf8Value str(args[i]); |
| 84 printf("%s", to_cstring(str)); |
| 85 } |
| 86 printf("\n"); |
| 87 fflush(stdout); |
| 88 } |
| 89 |
| 90 // The callback that is invoked by v8 whenever the JavaScript 'setTimeout' |
| 91 // function is called. |
| 92 // |
| 93 // JS: setTimeout(on_timeout, 500); |
| 94 // |
| 95 // TODO(jcgregorio) Currently only handles one timeout, should support any |
| 96 // number. |
| 97 void Global::SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 98 if (args.Length() != 2) { |
| 99 args.GetIsolate()->ThrowException( |
| 100 v8::String::NewFromUtf8( |
| 101 args.GetIsolate(), "Error: 2 arguments required.")); |
| 102 return; |
| 103 } |
| 104 |
| 105 // Pull out the first arg, make sure it's a function. |
| 106 if (!args[0]->IsFunction()) { |
| 107 printf("Not a function passed to setTimeout.\n"); |
| 108 return; |
| 109 } |
| 110 Handle<Function> timeoutFn = Handle<Function>::Cast(args[0]); |
| 111 gGlobal->fTimeout.Reset(args.GetIsolate(), timeoutFn); |
| 112 |
| 113 double delay = args[1]->NumberValue(); |
| 114 |
| 115 // Create an SkEvent and add it with the right delay. |
| 116 (new SkEvent())->setTargetProc(Global::TimeOutProc)->postDelay(delay); |
| 117 |
| 118 // TODO(jcgregorio) Return the ID as the return value. |
| 119 } |
| 120 |
| 121 // Callback function for SkEvents used to implement timeouts. |
| 122 bool Global::TimeOutProc(const SkEvent& evt) { |
| 123 // Create a handle scope to keep the temporary object references. |
| 124 HandleScope handleScope(gGlobal->getIsolate()); |
| 125 |
| 126 // Create a local context from our global context. |
| 127 Local<Context> context = gGlobal->getContext(); |
| 128 |
| 129 // Enter the context so all the remaining operations take place there. |
| 130 Context::Scope contextScope(context); |
| 131 |
| 132 // Set up an exception handler before calling the Process function. |
| 133 TryCatch tryCatch; |
| 134 |
| 135 const int argc = 0; |
| 136 Local<Function> onTimeout = |
| 137 Local<Function>::New(gGlobal->getIsolate(), gGlobal->fTimeout); |
| 138 Handle<Value> result = onTimeout->Call(context->Global(), argc, NULL); |
| 139 |
| 140 // Handle any exceptions or output. |
| 141 if (result.IsEmpty()) { |
| 142 SkASSERT(tryCatch.HasCaught()); |
| 143 // Print errors that happened during execution. |
| 144 gGlobal->reportException(&tryCatch); |
| 145 } else { |
| 146 SkASSERT(!tryCatch.HasCaught()); |
| 147 if (!result->IsUndefined()) { |
| 148 // If all went well and the result wasn't undefined then print the |
| 149 // returned value. |
| 150 String::Utf8Value str(result); |
| 151 const char* cstr = to_cstring(str); |
| 152 printf("%s\n", cstr); |
| 153 } |
| 154 } |
| 155 return true; |
| 156 } |
| 157 |
| 158 // Creates a new execution environment containing the built-in functions. |
| 159 Handle<Context> Global::createRootContext() { |
| 160 // Create a template for the global object. |
| 161 Handle<ObjectTemplate> global = ObjectTemplate::New(); |
| 162 |
| 163 global->Set(v8::String::NewFromUtf8(fIsolate, "print"), |
| 164 v8::FunctionTemplate::New(Global::Print)); |
| 165 global->Set(v8::String::NewFromUtf8(fIsolate, "setTimeout"), |
| 166 v8::FunctionTemplate::New(Global::SetTimeout)); |
| 167 global->Set(v8::String::NewFromUtf8(fIsolate, "inval"), |
| 168 v8::FunctionTemplate::New(Global::Inval)); |
| 169 |
| 170 |
| 171 return Context::New(fIsolate, NULL, global); |
| 172 } |
| 173 |
| 174 |
| 175 // Creates the root context, parses the script into it, then stores the |
| 176 // context in a global. |
| 177 // |
| 178 // TODO(jcgregorio) Currently only handles one script. Need to move |
| 179 // createRootContext to another call that's only done once. |
| 180 bool Global::parseScript(const char script[]) { |
| 181 |
| 182 // Create a stack-allocated handle scope. |
| 183 HandleScope handleScope(fIsolate); |
| 184 |
| 185 printf("Before create context\n"); |
| 186 |
| 187 // Create a new context. |
| 188 Handle<Context> context = this->createRootContext(); |
| 189 |
| 190 // Enter the scope so all operations take place in the scope. |
| 191 Context::Scope contextScope(context); |
| 192 |
| 193 v8::TryCatch tryCatch; |
| 194 |
| 195 // Compile the source code. |
| 196 Handle<String> source = String::NewFromUtf8(fIsolate, script); |
| 197 printf("Before Compile\n"); |
| 198 Handle<Script> compiledScript = Script::Compile(source); |
| 199 printf("After Compile\n"); |
| 200 |
| 201 if (compiledScript.IsEmpty()) { |
| 202 // Print errors that happened during compilation. |
| 203 this->reportException(&tryCatch); |
| 204 return false; |
| 205 } |
| 206 printf("After Exception.\n"); |
| 207 |
| 208 // Try running it now to create the onDraw function. |
| 209 Handle<Value> result = compiledScript->Run(); |
| 210 |
| 211 // Handle any exceptions or output. |
| 212 if (result.IsEmpty()) { |
| 213 SkASSERT(tryCatch.HasCaught()); |
| 214 // Print errors that happened during execution. |
| 215 this->reportException(&tryCatch); |
| 216 return false; |
| 217 } else { |
| 218 SkASSERT(!tryCatch.HasCaught()); |
| 219 if (!result->IsUndefined()) { |
| 220 // If all went well and the result wasn't undefined then print |
| 221 // the returned value. |
| 222 String::Utf8Value str(result); |
| 223 const char* cstr = to_cstring(str); |
| 224 printf("%s\n", cstr); |
| 225 return false; |
| 226 } |
| 227 } |
| 228 |
| 229 // Also make the context persistent. |
| 230 fContext.Reset(fIsolate, context); |
| 231 return true; |
| 232 } |
OLD | NEW |