/* * Copyright 2013 Google Inc. * * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. * */ #include using namespace v8; #include "SkV8Example.h" #include "gl/GrGLUtil.h" #include "gl/GrGLDefines.h" #include "gl/GrGLInterface.h" #include "SkApplication.h" #include "SkDraw.h" #include "SkGpuDevice.h" #include "SkGraphics.h" void application_init() { SkGraphics::Init(); SkEvent::Init(); } void application_term() { SkEvent::Term(); SkGraphics::Term(); } // Extracts a C string from a V8 Utf8Value. const char* ToCString(const v8::String::Utf8Value& value) { return *value ? *value : ""; } // Slight modification to an original function found in the V8 sample shell.cc. void reportException(Isolate* isolate, TryCatch* try_catch) { HandleScope handleScope(isolate); String::Utf8Value exception(try_catch->Exception()); const char* exception_string = ToCString(exception); Handle 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()); 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()); 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) { const char* stack_trace_string = ToCString(stack_trace); fprintf(stderr, "%s\n", stack_trace_string); } } } SkV8ExampleWindow::SkV8ExampleWindow(void* hwnd, JsCanvas* canvas) : INHERITED(hwnd) , fJsCanvas(canvas) { fRotationAngle = SkIntToScalar(0); this->setConfig(SkBitmap::kARGB_8888_Config); this->setVisibleP(true); this->setClipToBounds(false); } JsCanvas* JsCanvas::unwrap(Handle obj) { Handle field = Handle::Cast(obj->GetInternalField(0)); void* ptr = field->Value(); return static_cast(ptr); } void JsCanvas::inval(const v8::FunctionCallbackInfo& args) { unwrap(args.This())->fWindow->inval(NULL); } void JsCanvas::drawRect(const v8::FunctionCallbackInfo& args) { SkCanvas* canvas = unwrap(args.This())->fCanvas; canvas->drawColor(SK_ColorWHITE); // Draw a rectangle with red paint. SkPaint paint; paint.setColor(SK_ColorRED); SkRect rect = { SkIntToScalar(10), SkIntToScalar(10), SkIntToScalar(128), SkIntToScalar(128) }; canvas->drawRect(rect, paint); } Persistent JsCanvas::fCanvasTemplate; Handle JsCanvas::makeCanvasTemplate() { EscapableHandleScope handleScope(fIsolate); Local result = ObjectTemplate::New(); // Add a field to store the pointer to a JsCanvas instance. result->SetInternalFieldCount(1); // Add accessors for each of the fields of the canvas object. result->Set( String::NewFromUtf8( fIsolate, "drawRect", String::kInternalizedString), FunctionTemplate::New(drawRect)); result->Set( String::NewFromUtf8( fIsolate, "inval", String::kInternalizedString), FunctionTemplate::New(inval)); // Return the result through the current handle scope. return handleScope.Escape(result); } // Wraps 'this' in a Javascript object. Handle JsCanvas::wrap() { // Handle scope for temporary handles. EscapableHandleScope handleScope(fIsolate); // Fetch the template for creating JavaScript JsCanvas wrappers. // It only has to be created once, which we do on demand. if (fCanvasTemplate.IsEmpty()) { Handle raw_template = this->makeCanvasTemplate(); fCanvasTemplate.Reset(fIsolate, raw_template); } Handle templ = Local::New(fIsolate, fCanvasTemplate); // Create an empty JsCanvas wrapper. Local result = templ->NewInstance(); // Wrap the raw C++ pointer in an External so it can be referenced // from within JavaScript. Handle canvasPtr = External::New(fIsolate, this); // Store the canvas pointer in the JavaScript wrapper. result->SetInternalField(0, canvasPtr); // Return the result through the current handle scope. Since each // of these handles will go away when the handle scope is deleted // we need to call Close to let one, the result, escape into the // outer handle scope. return handleScope.Escape(result); } void JsCanvas::onDraw(SkCanvas* canvas, SkOSWindow* window) { // Record canvas and window in this. fCanvas = canvas; fWindow = window; // Create a handle scope to keep the temporary object references. HandleScope handleScope(fIsolate); // Create a local context from our global context. Local context = Local::New(fIsolate, fContext); // Enter the context so all the remaining operations take place there. Context::Scope contextScope(context); // Wrap the C++ this pointer in a JavaScript wrapper. Handle canvasObj = this->wrap(); // Set up an exception handler before calling the Process function. TryCatch tryCatch; // Invoke the process function, giving the global object as 'this' // and one argument, this JsCanvas. const int argc = 1; Handle argv[argc] = { canvasObj }; Local onDraw = Local::New(fIsolate, fOnDraw); Handle result = onDraw->Call(context->Global(), argc, argv); // Handle any exceptions or output. if (result.IsEmpty()) { SkASSERT(tryCatch.HasCaught()); // Print errors that happened during execution. reportException(fIsolate, &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); } } } void SkV8ExampleWindow::onDraw(SkCanvas* canvas) { canvas->save(); fRotationAngle += SkDoubleToScalar(0.2); if (fRotationAngle > SkDoubleToScalar(360.0)) { fRotationAngle -= SkDoubleToScalar(360.0); } canvas->rotate(fRotationAngle); // Now jump into JS and call the onDraw(canvas) method defined there. fJsCanvas->onDraw(canvas, this); canvas->restore(); INHERITED::onDraw(canvas); } #ifdef SK_BUILD_FOR_WIN void SkV8ExampleWindow::onHandleInval(const SkIRect& rect) { RECT winRect; winRect.top = rect.top(); winRect.bottom = rect.bottom(); winRect.right = rect.right(); winRect.left = rect.left(); InvalidateRect((HWND)this->getHWND(), &winRect, false); } #endif // Creates a new execution environment containing the built-in // function draw(). Handle createRootContext(Isolate* isolate) { // Create a template for the global object. Handle global = ObjectTemplate::New(); // This is where we would inject any globals into the root Context // using global->Set(...) return Context::New(isolate, NULL, global); } // Parse and run script. Then fetch out the onDraw function from the global // object. bool JsCanvas::initialize(const char script[]) { // Create a stack-allocated handle scope. HandleScope handleScope(fIsolate); printf("Before create context\n"); // Create a new context. Handle context = createRootContext(fIsolate); // Enter the scope so all operations take place in the scope. Context::Scope contextScope(context); v8::TryCatch try_catch; // Compile the source code. Handle source = String::NewFromUtf8(fIsolate, script); printf("Before Compile\n"); Handle