SkV8Example.cpp revision 80bd0c995d9ec6a70330d6dc3f2f8dd387701d1d
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 <v8.h> 10 11using namespace v8; 12 13#include "SkV8Example.h" 14 15#include "gl/GrGLUtil.h" 16#include "gl/GrGLDefines.h" 17#include "gl/GrGLInterface.h" 18#include "SkApplication.h" 19#include "SkDraw.h" 20#include "SkGpuDevice.h" 21#include "SkGraphics.h" 22 23 24void application_init() { 25 SkGraphics::Init(); 26 SkEvent::Init(); 27} 28 29void application_term() { 30 SkEvent::Term(); 31 SkGraphics::Term(); 32} 33 34// Extracts a C string from a V8 Utf8Value. 35const char* ToCString(const v8::String::Utf8Value& value) { 36 return *value ? *value : "<string conversion failed>"; 37} 38 39// Slight modification to an original function found in the V8 sample shell.cc. 40void reportException(Isolate* isolate, TryCatch* try_catch) { 41 HandleScope handle_scope(isolate); 42 String::Utf8Value exception(try_catch->Exception()); 43 const char* exception_string = ToCString(exception); 44 Handle<Message> message = try_catch->Message(); 45 if (message.IsEmpty()) { 46 // V8 didn't provide any extra information about this error; just 47 // print the exception. 48 fprintf(stderr, "%s\n", exception_string); 49 } else { 50 // Print (filename):(line number): (message). 51 String::Utf8Value filename(message->GetScriptResourceName()); 52 const char* filename_string = ToCString(filename); 53 int linenum = message->GetLineNumber(); 54 fprintf(stderr, "%s:%i: %s\n", filename_string, linenum, exception_string); 55 // Print line of source code. 56 String::Utf8Value sourceline(message->GetSourceLine()); 57 const char* sourceline_string = ToCString(sourceline); 58 fprintf(stderr, "%s\n", sourceline_string); 59 // Print wavy underline. 60 int start = message->GetStartColumn(); 61 for (int i = 0; i < start; i++) { 62 fprintf(stderr, " "); 63 } 64 int end = message->GetEndColumn(); 65 for (int i = start; i < end; i++) { 66 fprintf(stderr, "^"); 67 } 68 fprintf(stderr, "\n"); 69 String::Utf8Value stack_trace(try_catch->StackTrace()); 70 if (stack_trace.length() > 0) { 71 const char* stack_trace_string = ToCString(stack_trace); 72 fprintf(stderr, "%s\n", stack_trace_string); 73 } 74 } 75} 76 77SkV8ExampleWindow::SkV8ExampleWindow(void* hwnd, 78 Isolate* isolate, 79 Handle<Context> context, 80 Handle<Script> script) 81 : INHERITED(hwnd) 82 , fIsolate(isolate) 83{ 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); 89 this->setConfig(SkBitmap::kARGB_8888_Config); 90 this->setVisibleP(true); 91 this->setClipToBounds(false); 92} 93 94// Simple global for the Draw function. 95SkCanvas* gCanvas = NULL; 96 97 98// Draw is called from within V8 when the Javascript function draw() is called. 99void Draw(const v8::FunctionCallbackInfo<v8::Value>& args) { 100 if (NULL == gCanvas) { 101 printf("Can't Draw Now.\n"); 102 return; 103 } 104 105 gCanvas->drawColor(SK_ColorWHITE); 106 SkPaint paint; 107 paint.setColor(SK_ColorRED); 108 109 // Draw a rectangle with blue paint 110 SkRect rect = { 111 SkIntToScalar(10), SkIntToScalar(10), 112 SkIntToScalar(128), SkIntToScalar(128) 113 }; 114 gCanvas->drawRect(rect, paint); 115} 116 117void SkV8ExampleWindow::onDraw(SkCanvas* canvas) { 118 printf("Draw\n"); 119 120 gCanvas = canvas; 121 canvas->save(); 122 fRotationAngle += SkDoubleToScalar(0.2); 123 if (fRotationAngle > SkDoubleToScalar(360.0)) { 124 fRotationAngle -= SkDoubleToScalar(360.0); 125 } 126 canvas->rotate(fRotationAngle); 127 128 // Create a Handle scope for temporary references. 129 HandleScope handle_scope(fIsolate); 130 131 // Create a local context from our persistent context. 132 Local<Context> context = 133 Local<Context>::New(fIsolate, fContext); 134 135 // Enter the context so all operations take place within it. 136 Context::Scope context_scope(context); 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 173void SkV8ExampleWindow::onHandleInval(const SkIRect& rect) { 174 RECT winRect; 175 winRect.top = rect.top(); 176 winRect.bottom = rect.bottom(); 177 winRect.right = rect.right(); 178 winRect.left = rect.left(); 179 InvalidateRect((HWND)this->getHWND(), &winRect, false); 180} 181#endif 182 183// Creates a new execution environment containing the built-in 184// function draw(). 185Handle<Context> createRootContext(Isolate* isolate) { 186 // Create a template for the global object. 187 Handle<ObjectTemplate> global = ObjectTemplate::New(); 188 // Bind the global 'draw' function to the C++ Draw callback. 189 global->Set(String::NewFromUtf8(isolate, "draw"), 190 FunctionTemplate::New(Draw)); 191 192 return Context::New(isolate, NULL, global); 193} 194 195SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) { 196 printf("Started\n"); 197 198 // Get the default Isolate created at startup. 199 Isolate* isolate = Isolate::GetCurrent(); 200 printf("Isolate\n"); 201 202 // Create a stack-allocated handle scope. 203 HandleScope handle_scope(isolate); 204 205 printf("Before create context\n"); 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 script. 232 return new SkV8ExampleWindow(hwnd, isolate, context, script); 233} 234