Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: experimental/SkV8Example/SkV8Example.cpp

Issue 110693002: Add a canvas object with drawRect() and inval(). (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Fix up code to Skia style. Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « experimental/SkV8Example/SkV8Example.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * 4 *
5 * Use of this source code is governed by a BSD-style license that can be 5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file. 6 * found in the LICENSE file.
7 * 7 *
8 */ 8 */
9 #include <v8.h> 9 #include <v8.h>
10 10
(...skipping 15 matching lines...) Expand all
26 SkEvent::Init(); 26 SkEvent::Init();
27 } 27 }
28 28
29 void application_term() { 29 void application_term() {
30 SkEvent::Term(); 30 SkEvent::Term();
31 SkGraphics::Term(); 31 SkGraphics::Term();
32 } 32 }
33 33
34 // Extracts a C string from a V8 Utf8Value. 34 // Extracts a C string from a V8 Utf8Value.
35 const char* ToCString(const v8::String::Utf8Value& value) { 35 const char* ToCString(const v8::String::Utf8Value& value) {
36 return *value ? *value : "<string conversion failed>"; 36 return *value ? *value : "<string conversion failed>";
37 } 37 }
38 38
39 // Slight modification to an original function found in the V8 sample shell.cc. 39 // Slight modification to an original function found in the V8 sample shell.cc.
40 void reportException(Isolate* isolate, TryCatch* try_catch) { 40 void reportException(Isolate* isolate, TryCatch* try_catch) {
41 HandleScope handle_scope(isolate); 41 HandleScope handleScope(isolate);
42 String::Utf8Value exception(try_catch->Exception()); 42 String::Utf8Value exception(try_catch->Exception());
43 const char* exception_string = ToCString(exception); 43 const char* exception_string = ToCString(exception);
44 Handle<Message> message = try_catch->Message(); 44 Handle<Message> message = try_catch->Message();
45 if (message.IsEmpty()) { 45 if (message.IsEmpty()) {
46 // V8 didn't provide any extra information about this error; just 46 // V8 didn't provide any extra information about this error; just
47 // print the exception. 47 // print the exception.
48 fprintf(stderr, "%s\n", exception_string); 48 fprintf(stderr, "%s\n", exception_string);
49 } else { 49 } else {
50 // Print (filename):(line number): (message). 50 // Print (filename):(line number): (message).
51 String::Utf8Value filename(message->GetScriptResourceName()); 51 String::Utf8Value filename(message->GetScriptResourceName());
52 const char* filename_string = ToCString(filename); 52 const char* filename_string = ToCString(filename);
53 int linenum = message->GetLineNumber(); 53 int linenum = message->GetLineNumber();
54 fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string); 54 fprintf(stderr,
55 // Print line of source code. 55 "%s:%i: %s\n", filename_string, linenum, exception_string);
56 String::Utf8Value sourceline(message->GetSourceLine()); 56 // Print line of source code.
57 const char* sourceline_string = ToCString(sourceline); 57 String::Utf8Value sourceline(message->GetSourceLine());
58 fprintf(stderr, "%s\n", sourceline_string); 58 const char* sourceline_string = ToCString(sourceline);
59 // Print wavy underline. 59 fprintf(stderr, "%s\n", sourceline_string);
60 int start = message->GetStartColumn(); 60 // Print wavy underline.
61 for (int i = 0; i < start; i++) { 61 int start = message->GetStartColumn();
62 fprintf(stderr, " "); 62 for (int i = 0; i < start; i++) {
63 } 63 fprintf(stderr, " ");
64 int end = message->GetEndColumn(); 64 }
65 for (int i = start; i < end; i++) { 65 int end = message->GetEndColumn();
66 fprintf(stderr, "^"); 66 for (int i = start; i < end; i++) {
67 } 67 fprintf(stderr, "^");
68 fprintf(stderr, "\n"); 68 }
69 String::Utf8Value stack_trace(try_catch->StackTrace()); 69 fprintf(stderr, "\n");
70 if (stack_trace.length() > 0) { 70 String::Utf8Value stack_trace(try_catch->StackTrace());
71 const char* stack_trace_string = ToCString(stack_trace); 71 if (stack_trace.length() > 0) {
72 fprintf(stderr, "%s\n", stack_trace_string); 72 const char* stack_trace_string = ToCString(stack_trace);
73 } 73 fprintf(stderr, "%s\n", stack_trace_string);
74 } 74 }
75 } 75 }
76 76 }
77 SkV8ExampleWindow::SkV8ExampleWindow(void* hwnd, 77
78 Isolate* isolate, 78 SkV8ExampleWindow::SkV8ExampleWindow(void* hwnd, JsCanvas* canvas)
79 Handle<Context> context,
80 Handle<Script> script)
81 : INHERITED(hwnd) 79 : INHERITED(hwnd)
82 , fIsolate(isolate) 80 , fJsCanvas(canvas)
83 { 81 {
84 // Convert the Handle<> objects into Persistent<> objects using Reset().
85 fContext.Reset(isolate, context);
86 fScript.Reset(isolate, script);
87
88 fRotationAngle = SkIntToScalar(0); 82 fRotationAngle = SkIntToScalar(0);
89 this->setConfig(SkBitmap::kARGB_8888_Config); 83 this->setConfig(SkBitmap::kARGB_8888_Config);
90 this->setVisibleP(true); 84 this->setVisibleP(true);
91 this->setClipToBounds(false); 85 this->setClipToBounds(false);
92 } 86 }
93 87
94 // Simple global for the Draw function. 88 JsCanvas* JsCanvas::unwrap(Handle<Object> obj) {
95 SkCanvas* gCanvas = NULL; 89 Handle<External> field = Handle<External>::Cast(obj->GetInternalField(0));
96 90 void* ptr = field->Value();
97 91 return static_cast<JsCanvas*>(ptr);
98 // Draw is called from within V8 when the Javascript function draw() is called. 92 }
99 void Draw(const v8::FunctionCallbackInfo<v8::Value>& args) { 93
100 if (NULL == gCanvas) { 94 void JsCanvas::inval(const v8::FunctionCallbackInfo<Value>& args) {
101 printf("Can't Draw Now.\n"); 95 unwrap(args.This())->fWindow->inval(NULL);
102 return; 96 }
103 } 97
104 98 void JsCanvas::drawRect(const v8::FunctionCallbackInfo<Value>& args) {
105 gCanvas->drawColor(SK_ColorWHITE); 99 SkCanvas* canvas = unwrap(args.This())->fCanvas;
106 SkPaint paint; 100
107 paint.setColor(SK_ColorRED); 101 canvas->drawColor(SK_ColorWHITE);
108 102
109 // Draw a rectangle with blue paint 103 // Draw a rectangle with red paint.
110 SkRect rect = { 104 SkPaint paint;
111 SkIntToScalar(10), SkIntToScalar(10), 105 paint.setColor(SK_ColorRED);
112 SkIntToScalar(128), SkIntToScalar(128) 106 SkRect rect = {
113 }; 107 SkIntToScalar(10), SkIntToScalar(10),
114 gCanvas->drawRect(rect, paint); 108 SkIntToScalar(128), SkIntToScalar(128)
109 };
110 canvas->drawRect(rect, paint);
111 }
112
113 Persistent<ObjectTemplate> JsCanvas::fCanvasTemplate;
114
115 Handle<ObjectTemplate> JsCanvas::makeCanvasTemplate() {
116 EscapableHandleScope handleScope(fIsolate);
117
118 Local<ObjectTemplate> result = ObjectTemplate::New();
119
120 // Add a field to store the pointer to a JsCanvas instance.
121 result->SetInternalFieldCount(1);
122
123 // Add accessors for each of the fields of the canvas object.
124 result->Set(
125 String::NewFromUtf8(
126 fIsolate, "drawRect", String::kInternalizedString),
127 FunctionTemplate::New(drawRect));
128 result->Set(
129 String::NewFromUtf8(
130 fIsolate, "inval", String::kInternalizedString),
131 FunctionTemplate::New(inval));
132
133 // Return the result through the current handle scope.
134 return handleScope.Escape(result);
135 }
136
137
138 // Wraps 'this' in a Javascript object.
139 Handle<Object> JsCanvas::wrap() {
140 // Handle scope for temporary handles.
141 EscapableHandleScope handleScope(fIsolate);
142
143 // Fetch the template for creating JavaScript JsCanvas wrappers.
144 // It only has to be created once, which we do on demand.
145 if (fCanvasTemplate.IsEmpty()) {
146 Handle<ObjectTemplate> raw_template = this->makeCanvasTemplate();
147 fCanvasTemplate.Reset(fIsolate, raw_template);
148 }
149 Handle<ObjectTemplate> templ =
150 Local<ObjectTemplate>::New(fIsolate, fCanvasTemplate);
151
152 // Create an empty JsCanvas wrapper.
153 Local<Object> result = templ->NewInstance();
154
155 // Wrap the raw C++ pointer in an External so it can be referenced
156 // from within JavaScript.
157 Handle<External> canvasPtr = External::New(fIsolate, this);
158
159 // Store the canvas pointer in the JavaScript wrapper.
160 result->SetInternalField(0, canvasPtr);
161
162 // Return the result through the current handle scope. Since each
163 // of these handles will go away when the handle scope is deleted
164 // we need to call Close to let one, the result, escape into the
165 // outer handle scope.
166 return handleScope.Escape(result);
167 }
168
169 void JsCanvas::onDraw(SkCanvas* canvas, SkOSWindow* window) {
170 // Record canvas and window in this.
171 fCanvas = canvas;
172 fWindow = window;
173
174 // Create a handle scope to keep the temporary object references.
175 HandleScope handleScope(fIsolate);
176
177 // Create a local context from our global context.
178 Local<Context> context = Local<Context>::New(fIsolate, fContext);
179
180 // Enter the context so all the remaining operations take place there.
181 Context::Scope contextScope(context);
182
183 // Wrap the C++ this pointer in a JavaScript wrapper.
184 Handle<Object> canvasObj = this->wrap();
185
186 // Set up an exception handler before calling the Process function.
187 TryCatch tryCatch;
188
189 // Invoke the process function, giving the global object as 'this'
190 // and one argument, this JsCanvas.
191 const int argc = 1;
192 Handle<Value> argv[argc] = { canvasObj };
193 Local<Function> onDraw =
194 Local<Function>::New(fIsolate, fOnDraw);
195 Handle<Value> result = onDraw->Call(context->Global(), argc, argv);
196
197 // Handle any exceptions or output.
198 if (result.IsEmpty()) {
199 SkASSERT(tryCatch.HasCaught());
200 // Print errors that happened during execution.
201 reportException(fIsolate, &tryCatch);
202 } else {
203 SkASSERT(!tryCatch.HasCaught());
204 if (!result->IsUndefined()) {
205 // If all went well and the result wasn't undefined then print
206 // the returned value.
207 String::Utf8Value str(result);
208 const char* cstr = ToCString(str);
209 printf("%s\n", cstr);
210 }
211 }
115 } 212 }
116 213
117 void SkV8ExampleWindow::onDraw(SkCanvas* canvas) { 214 void SkV8ExampleWindow::onDraw(SkCanvas* canvas) {
118 printf("Draw\n"); 215
119 216 canvas->save();
120 gCanvas = canvas; 217
121 canvas->save(); 218 fRotationAngle += SkDoubleToScalar(0.2);
122 fRotationAngle += SkDoubleToScalar(0.2); 219 if (fRotationAngle > SkDoubleToScalar(360.0)) {
123 if (fRotationAngle > SkDoubleToScalar(360.0)) { 220 fRotationAngle -= SkDoubleToScalar(360.0);
124 fRotationAngle -= SkDoubleToScalar(360.0); 221 }
125 } 222
126 canvas->rotate(fRotationAngle); 223 canvas->rotate(fRotationAngle);
127 224
128 // Create a Handle scope for temporary references. 225 // Now jump into JS and call the onDraw(canvas) method defined there.
129 HandleScope handle_scope(fIsolate); 226 fJsCanvas->onDraw(canvas, this);
130 227
131 // Create a local context from our persistent context. 228 canvas->restore();
132 Local<Context> context = 229
133 Local<Context>::New(fIsolate, fContext); 230 INHERITED::onDraw(canvas);
134 231 }
135 // Enter the context so all operations take place within it. 232
136 Context::Scope context_scope(context); 233
137
138 TryCatch try_catch;
139
140 // Create a local script from our persistent script.
141 Local<Script> script =
142 Local<Script>::New(fIsolate, fScript);
143
144 // Run the script.
145 Handle<Value> result = script->Run();
146
147 if (result.IsEmpty()) {
148 SkASSERT(try_catch.HasCaught());
149 // Print errors that happened during execution.
150 reportException(fIsolate, &try_catch);
151 } else {
152 SkASSERT(!try_catch.HasCaught());
153 if (!result->IsUndefined()) {
154 // If all went well and the result wasn't undefined then print
155 // the returned value.
156 String::Utf8Value str(result);
157 const char* cstr = ToCString(str);
158 printf("%s\n", cstr);
159 }
160 }
161
162 canvas->restore();
163
164 // Trigger an invalidation which should trigger another redraw to simulate
165 // animation.
166 this->inval(NULL);
167
168 INHERITED::onDraw(canvas);
169 }
170
171
172 #ifdef SK_BUILD_FOR_WIN 234 #ifdef SK_BUILD_FOR_WIN
173 void SkV8ExampleWindow::onHandleInval(const SkIRect& rect) { 235 void SkV8ExampleWindow::onHandleInval(const SkIRect& rect) {
174 RECT winRect; 236 RECT winRect;
175 winRect.top = rect.top(); 237 winRect.top = rect.top();
176 winRect.bottom = rect.bottom(); 238 winRect.bottom = rect.bottom();
177 winRect.right = rect.right(); 239 winRect.right = rect.right();
178 winRect.left = rect.left(); 240 winRect.left = rect.left();
179 InvalidateRect((HWND)this->getHWND(), &winRect, false); 241 InvalidateRect((HWND)this->getHWND(), &winRect, false);
180 } 242 }
181 #endif 243 #endif
182 244
183 // Creates a new execution environment containing the built-in 245 // Creates a new execution environment containing the built-in
184 // function draw(). 246 // function draw().
185 Handle<Context> createRootContext(Isolate* isolate) { 247 Handle<Context> createRootContext(Isolate* isolate) {
186 // Create a template for the global object. 248 // Create a template for the global object.
187 Handle<ObjectTemplate> global = ObjectTemplate::New(); 249 Handle<ObjectTemplate> global = ObjectTemplate::New();
188 // Bind the global 'draw' function to the C++ Draw callback. 250
189 global->Set(String::NewFromUtf8(isolate, "draw"), 251 // This is where we would inject any globals into the root Context
190 FunctionTemplate::New(Draw)); 252 // using global->Set(...)
191 253
192 return Context::New(isolate, NULL, global); 254 return Context::New(isolate, NULL, global);
193 } 255 }
194 256
257
258 // Parse and run script. Then fetch out the onDraw function from the global
259 // object.
260 bool JsCanvas::initialize(const char script[]) {
261
262 // Create a stack-allocated handle scope.
263 HandleScope handleScope(fIsolate);
264
265 printf("Before create context\n");
266
267 // Create a new context.
268 Handle<Context> context = createRootContext(fIsolate);
269
270 // Enter the scope so all operations take place in the scope.
271 Context::Scope contextScope(context);
272
273 v8::TryCatch try_catch;
274
275 // Compile the source code.
276 Handle<String> source = String::NewFromUtf8(fIsolate, script);
277 printf("Before Compile\n");
278 Handle<Script> compiled_script = Script::Compile(source);
279 printf("After Compile\n");
280
281 if (compiled_script.IsEmpty()) {
282 // Print errors that happened during compilation.
283 reportException(fIsolate, &try_catch);
284 return false;
285 }
286 printf("After Exception.\n");
287
288 // Try running it now to create the onDraw function.
289 Handle<Value> result = compiled_script->Run();
290
291 // Handle any exceptions or output.
292 if (result.IsEmpty()) {
293 SkASSERT(try_catch.HasCaught());
294 // Print errors that happened during execution.
295 reportException(fIsolate, &try_catch);
296 return false;
297 } else {
298 SkASSERT(!try_catch.HasCaught());
299 if (!result->IsUndefined()) {
300 // If all went well and the result wasn't undefined then print
301 // the returned value.
302 String::Utf8Value str(result);
303 const char* cstr = ToCString(str);
304 printf("%s\n", cstr);
305 return false;
306 }
307 }
308
309 Handle<String> fn_name = String::NewFromUtf8(fIsolate, "onDraw");
310 Handle<Value> fn_val = context->Global()->Get(fn_name);
311
312 if (!fn_val->IsFunction()) {
313 return false;
314 }
315
316 // It is a function; cast it to a Function.
317 Handle<Function> fn_fun = Handle<Function>::Cast(fn_val);
318
319 // Store the function in a Persistent handle, since we also want that to
320 // remain after this call returns.
321 fOnDraw.Reset(fIsolate, fn_fun);
322
323 // Also make the context persistent.
324 fContext.Reset(fIsolate, context);
325 return true;
326 }
327
195 SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { 328 SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
196 printf("Started\n"); 329 printf("Started\n");
197 330
198 // Get the default Isolate created at startup. 331 // Get the default Isolate created at startup.
199 Isolate* isolate = Isolate::GetCurrent(); 332 Isolate* isolate = Isolate::GetCurrent();
200 printf("Isolate\n");
201 333
202 // Create a stack-allocated handle scope. 334 JsCanvas* jsCanvas = new JsCanvas(isolate);
203 HandleScope handle_scope(isolate); 335 const char* script = "function onDraw(canvas){"
336 "canvas.drawRect();"
337 "canvas.inval();"
338 "};";
339 if (!jsCanvas->initialize(script)) {
340 printf("Failed to initialize.\n");
341 exit(1);
342 }
204 343
205 printf("Before create context\n"); 344 return new SkV8ExampleWindow(hwnd, jsCanvas);
206 // Create a new context.
207 //
208 Handle<Context> context = createRootContext(isolate);
209
210 // Enter the scope so all operations take place in the scope.
211 Context::Scope context_scope(context);
212
213 v8::TryCatch try_catch;
214
215 // Compile the source code.
216 Handle<String> source = String::NewFromUtf8(isolate, "draw();");
217 printf("Before Compile\n");
218 Handle<Script> script = Script::Compile(source);
219 printf("After Compile\n");
220
221 // Try running it now. It won't have a valid context, but shouldn't fail.
222 script->Run();
223
224 if (script.IsEmpty()) {
225 // Print errors that happened during compilation.
226 reportException(isolate, &try_catch);
227 exit(1);
228 }
229 printf("After Exception.\n");
230
231 // SkV8ExampleWindow will make persistent handles to hold the context and scri pt.
232 return new SkV8ExampleWindow(hwnd, isolate, context, script);
233 } 345 }
OLDNEW
« no previous file with comments | « experimental/SkV8Example/SkV8Example.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698