// // Image.cc // // Copyright (c) 2010 LearnBoost // #include "Canvas.h" #include "Image.h" /* * Initialize Image. */ void Image::Initialize(Handle target) { HandleScope scope; Local t = FunctionTemplate::New(Image::New); t->InstanceTemplate()->SetInternalFieldCount(1); t->SetClassName(String::NewSymbol("Image")); Local proto = t->PrototypeTemplate(); NODE_SET_PROTOTYPE_METHOD(t, "inspect", Inspect); proto->SetAccessor(String::NewSymbol("src"), GetSrc, SetSrc); proto->SetAccessor(String::NewSymbol("complete"), GetComplete); proto->SetAccessor(String::NewSymbol("onload"), GetOnload, SetOnload); proto->SetAccessor(String::NewSymbol("onerror"), GetOnerror, SetOnerror); target->Set(String::NewSymbol("Image"), t->GetFunction()); } /* * Initialize a new Image. */ Handle Image::New(const Arguments &args) { HandleScope scope; Image *img = new Image; img->Wrap(args.This()); return args.This(); } /* * Custom inspect. */ Handle Image::Inspect(const Arguments &args) { HandleScope scope; Image *img = ObjectWrap::Unwrap(args.This()); Local str = String::New("[Image"); if (img->filename) { str = String::Concat(str, String::New(" ")); str = String::Concat(str, String::New(img->filename)); } str = String::Concat(str, String::New("]")); return scope.Close(str); } /* * Get complete boolean. */ Handle Image::GetComplete(Local, const AccessorInfo &info) { Image *img = ObjectWrap::Unwrap(info.This()); return Boolean::New(img->complete); } /* * Get src path. */ Handle Image::GetSrc(Local, const AccessorInfo &info) { Image *img = ObjectWrap::Unwrap(info.This()); return String::New(img->filename); } /* * Set src path. */ void Image::SetSrc(Local, Local val, const AccessorInfo &info) { if (val->IsString()) { String::AsciiValue src(val); Image *img = ObjectWrap::Unwrap(info.This()); img->filename = *src; img->load(); } } /* * Get onload callback. */ Handle Image::GetOnload(Local, const AccessorInfo &info) { Image *img = ObjectWrap::Unwrap(info.This()); return img->onload; } /* * Set onload callback. */ void Image::SetOnload(Local, Local val, const AccessorInfo &info) { if (val->IsFunction()) { Image *img = ObjectWrap::Unwrap(info.This()); img->onload = Persistent::New(Handle::Cast(val)); } } /* * Get onerror callback. */ Handle Image::GetOnerror(Local, const AccessorInfo &info) { Image *img = ObjectWrap::Unwrap(info.This()); return img->onerror; } /* * Set onerror callback. */ void Image::SetOnerror(Local, Local val, const AccessorInfo &info) { if (val->IsFunction()) { Image *img = ObjectWrap::Unwrap(info.This()); img->onerror = Persistent::New(Handle::Cast(val)); } } /* * Initialize a new Image. */ Image::Image() { complete = false; filename = NULL; _surface = NULL; } /* * Destroy image and associated surface. */ Image::~Image() { if (_surface) cairo_surface_destroy(_surface); } /* * Load callback. */ static int EIO_Load(eio_req *req) { Image *img = (Image *) req->data; req->result = img->loadSurface(); return 0; } /* * After load callback. */ static int EIO_AfterLoad(eio_req *req) { HandleScope scope; Image *img = (Image *) req->data; if (req->result) { img->error(Canvas::Error((cairo_status_t) req->result)); } else { img->loaded(); } ev_unref(EV_DEFAULT_UC); return 0; } /* * Initiate image loading. */ void Image::load() { Ref(); complete = false; eio_custom(EIO_Load, EIO_PRI_DEFAULT, EIO_AfterLoad, this); ev_ref(EV_DEFAULT_UC); } /* * Invoke onload (when assigned). */ void Image::loaded() { HandleScope scope; complete = true; if (!onload.IsEmpty()) { TryCatch try_catch; onload->Call(Context::GetCurrent()->Global(), 0, NULL); onload.Dispose(); if (try_catch.HasCaught()) { error(try_catch.Exception()); } } Unref(); } /* * Invoke onerror (when assigned) with the given err. */ void Image::error(Local err) { HandleScope scope; // TODO: handle exception in onerror segfault if (!onerror.IsEmpty()) { Local argv[1] = { err }; onerror->Call(Context::GetCurrent()->Global(), 1, argv); } } /* * Load cairo surface from the image src. * * TODO: support more formats */ cairo_status_t Image::loadSurface() { _surface = cairo_image_surface_create_from_png(filename); return cairo_surface_status(_surface); }