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