Browse Source

Update to NAN 2 and node 3+ APIs

v1.x
Zach Bjornson 9 years ago
parent
commit
d4d3b9c724
  1. 15
      .travis.yml
  2. 105
      benchmarks/run.js
  3. 4
      package.json
  4. 258
      src/Canvas.cc
  5. 8
      src/Canvas.h
  6. 73
      src/CanvasGradient.cc
  7. 6
      src/CanvasGradient.h
  8. 36
      src/CanvasPattern.cc
  9. 6
      src/CanvasPattern.h
  10. 939
      src/CanvasRenderingContext2d.cc
  11. 6
      src/CanvasRenderingContext2d.h
  12. 38
      src/FontFace.cc
  13. 6
      src/FontFace.h
  14. 105
      src/Image.cc
  15. 16
      src/Image.h
  16. 70
      src/ImageData.cc
  17. 6
      src/ImageData.h
  18. 32
      src/JPEGStream.h
  19. 6
      src/closure.h
  20. 12
      src/init.cc
  21. 18
      test/canvas.test.js

15
.travis.yml

@ -5,7 +5,20 @@ node_js:
- "0.12"
- "iojs-v1.8.4"
- "iojs-v2.5.0"
- "iojs-v3.3.0"
- "4"
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-4.8
before_install:
- '[ "${TRAVIS_NODE_VERSION}" != "0.8" ] || npm install -g npm@1.4.28'
- if [[ $TRAVIS_NODE_VERSION == 0.8 ]]; then npm install -g npm@1.4.28; fi
- if [[ $TRAVIS_OS_NAME == "linux" ]]; then export CXX=g++-4.8; fi
- $CXX --version
- sudo chown -R $USER /usr/local
- sh install
- npm explore npm -g -- npm install node-gyp@latest
after_script:
- make benchmark

105
benchmarks/run.js

@ -1,6 +1,7 @@
/**
* Module dependencies.
* Adaptive benchmarking. Starts with `initialTimes` iterations, increasing by
* a power of two each time until the benchmark takes at least `minDuration_ms`
* milliseconds to complete.
*/
var Canvas = require('../lib/canvas')
@ -8,34 +9,50 @@ var Canvas = require('../lib/canvas')
, largeCanvas = new Canvas(1000, 1000)
, ctx = canvas.getContext('2d');
var times = 10000;
console.log('\n \x1b[33m%s\x1b[0m times\n', times);
var initialTimes = 10;
var minDuration_ms = 2000;
function bm(label, overrideTimes, fn) {
var start = new Date
, n = times;
var queue = [], running = false;
if ('function' == typeof overrideTimes) {
fn = overrideTimes;
} else {
n = overrideTimes;
label += ' (' + n + ' times)';
}
var pending = n;
function bm(label, fn) {
queue.push({label: label, fn: fn});
next();
}
function done(){
var duration = (new Date - start) / 1000;
console.log(' - \x1b[33m%s\x1b[0m %ss', label, duration);
function next() {
if (queue.length && !running) {
run(queue.pop(), initialTimes, Date.now());
}
}
if (fn.length) {
while (n--) fn(function(){
--pending || done();
function run(benchmark, n, start) {
running = true;
var originalN = n;
var fn = benchmark.fn;
if (fn.length) { // async
var pending = n;
while (n--) fn(function () {
--pending || done(benchmark, originalN, start, true);
});
} else {
while (n--) fn();
done();
done(benchmark, originalN, start);
}
}
function done(benchmark, times, start, async) {
var duration = Date.now() - start;
if (duration < minDuration_ms) {
run(benchmark, times * 2, Date.now());
} else {
var opsSec = times / duration * 1000
if (async) {
console.log(' - \x1b[33m%s\x1b[0m %s ops/sec (%s times, async)', benchmark.label, opsSec.toLocaleString(), times);
} else {
console.log(' - \x1b[33m%s\x1b[0m %s ops/sec (%s times)', benchmark.label, opsSec.toLocaleString(), times);
}
running = false;
next();
}
}
@ -46,7 +63,7 @@ bm('lineTo()', function(){
});
bm('arc()', function(){
ctx.arc(75,75,50,0,Math.PI*2,true);
ctx.arc(75,75,50,0,Math.PI*2,true);
});
bm('fillStyle= hex', function(){
@ -57,6 +74,8 @@ bm('fillStyle= rgba()', function(){
ctx.fillStyle = 'rgba(0,255,80,1)';
});
// Apparently there's a bug in cairo by which the fillRect and strokeRect are
// slow only after a ton of arcs have been drawn.
bm('fillRect()', function(){
ctx.fillRect(50, 50, 100, 100);
});
@ -73,19 +92,31 @@ bm('linear gradients', function(){
ctx.fillRect(10,10,130,130);
});
bm('toBuffer() 200x200', 50, function(){
bm('toBuffer() 200x200', function(){
canvas.toBuffer();
});
bm('toBuffer() 1000x1000', 50, function(){
bm('toBuffer() 1000x1000', function(){
largeCanvas.toBuffer();
});
bm('toBuffer().toString("base64") 200x200', 50, function(){
bm('toBuffer() async 200x200', function(done){
canvas.toBuffer(function (err, buf) {
done();
});
});
bm('toBuffer() async 1000x1000', function(done){
largeCanvas.toBuffer(function (err, buf) {
done();
});
});
bm('toBuffer().toString("base64") 200x200', function(){
canvas.toBuffer().toString('base64');
});
bm('toDataURL() 200x200', 50, function(){
bm('toDataURL() 200x200', function(){
canvas.toDataURL();
});
@ -109,14 +140,12 @@ bm('getImageData(0,0,100,100)', function(){
ctx.getImageData(0,0,100,100);
});
// bm('PNGStream 200x200', 50, function(done){
// var stream = canvas.createSyncPNGStream();
// stream.on('data', function(chunk){
// // whatever
// });
// stream.on('end', function(){
// done();
// });
// });
console.log();
bm('PNGStream 200x200', function(done){
var stream = canvas.createSyncPNGStream();
stream.on('data', function(chunk){
// whatever
});
stream.on('end', function(){
done();
});
});

4
package.json

@ -24,7 +24,7 @@
"test": "make test"
},
"dependencies": {
"nan": "^1.8.4"
"nan": "^2.0.9"
},
"devDependencies": {
"body-parser": "^1.13.3",
@ -33,7 +33,7 @@
"mocha": "*"
},
"engines": {
"node": ">=0.8.0 <3"
"node": ">=0.8.0"
},
"main": "./lib/canvas.js",
"license": "MIT"

258
src/Canvas.cc

@ -20,42 +20,42 @@
#include "JPEGStream.h"
#endif
Persistent<FunctionTemplate> Canvas::constructor;
Nan::Persistent<FunctionTemplate> Canvas::constructor;
/*
* Initialize Canvas.
*/
void
Canvas::Initialize(Handle<Object> target) {
NanScope();
Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = NanNew<FunctionTemplate>(Canvas::New);
NanAssignPersistent(constructor, ctor);
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Canvas::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("Canvas"));
ctor->SetClassName(Nan::New("Canvas").ToLocalChecked());
// Prototype
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
NODE_SET_PROTOTYPE_METHOD(ctor, "toBuffer", ToBuffer);
NODE_SET_PROTOTYPE_METHOD(ctor, "streamPNGSync", StreamPNGSync);
Nan::SetPrototypeMethod(ctor, "toBuffer", ToBuffer);
Nan::SetPrototypeMethod(ctor, "streamPNGSync", StreamPNGSync);
#ifdef HAVE_JPEG
NODE_SET_PROTOTYPE_METHOD(ctor, "streamJPEGSync", StreamJPEGSync);
Nan::SetPrototypeMethod(ctor, "streamJPEGSync", StreamJPEGSync);
#endif
proto->SetAccessor(NanNew("type"), GetType);
proto->SetAccessor(NanNew("width"), GetWidth, SetWidth);
proto->SetAccessor(NanNew("height"), GetHeight, SetHeight);
NanSetTemplate(proto, "PNG_NO_FILTERS", NanNew<Uint32>(PNG_NO_FILTERS));
NanSetTemplate(proto, "PNG_FILTER_NONE", NanNew<Uint32>(PNG_FILTER_NONE));
NanSetTemplate(proto, "PNG_FILTER_SUB", NanNew<Uint32>(PNG_FILTER_SUB));
NanSetTemplate(proto, "PNG_FILTER_UP", NanNew<Uint32>(PNG_FILTER_UP));
NanSetTemplate(proto, "PNG_FILTER_AVG", NanNew<Uint32>(PNG_FILTER_AVG));
NanSetTemplate(proto, "PNG_FILTER_PAETH", NanNew<Uint32>(PNG_FILTER_PAETH));
NanSetTemplate(proto, "PNG_ALL_FILTERS", NanNew<Uint32>(PNG_ALL_FILTERS));
target->Set(NanNew("Canvas"), ctor->GetFunction());
Nan::SetAccessor(proto, Nan::New("type").ToLocalChecked(), GetType);
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth);
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight);
Nan::SetTemplate(proto, "PNG_NO_FILTERS", Nan::New<Uint32>(PNG_NO_FILTERS));
Nan::SetTemplate(proto, "PNG_FILTER_NONE", Nan::New<Uint32>(PNG_FILTER_NONE));
Nan::SetTemplate(proto, "PNG_FILTER_SUB", Nan::New<Uint32>(PNG_FILTER_SUB));
Nan::SetTemplate(proto, "PNG_FILTER_UP", Nan::New<Uint32>(PNG_FILTER_UP));
Nan::SetTemplate(proto, "PNG_FILTER_AVG", Nan::New<Uint32>(PNG_FILTER_AVG));
Nan::SetTemplate(proto, "PNG_FILTER_PAETH", Nan::New<Uint32>(PNG_FILTER_PAETH));
Nan::SetTemplate(proto, "PNG_ALL_FILTERS", Nan::New<Uint32>(PNG_ALL_FILTERS));
Nan::Set(target, Nan::New("Canvas").ToLocalChecked(), ctor->GetFunction());
}
/*
@ -63,19 +63,18 @@ Canvas::Initialize(Handle<Object> target) {
*/
NAN_METHOD(Canvas::New) {
NanScope();
int width = 0, height = 0;
canvas_type_t type = CANVAS_TYPE_IMAGE;
if (args[0]->IsNumber()) width = args[0]->Uint32Value();
if (args[1]->IsNumber()) height = args[1]->Uint32Value();
if (args[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(args[2]))
if (info[0]->IsNumber()) width = info[0]->Uint32Value();
if (info[1]->IsNumber()) height = info[1]->Uint32Value();
if (info[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(info[2]))
? CANVAS_TYPE_PDF
: !strcmp("svg", *String::Utf8Value(args[2]))
: !strcmp("svg", *String::Utf8Value(info[2]))
? CANVAS_TYPE_SVG
: CANVAS_TYPE_IMAGE;
Canvas *canvas = new Canvas(width, height, type);
canvas->Wrap(args.This());
NanReturnValue(args.This());
canvas->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
/*
@ -83,9 +82,8 @@ NAN_METHOD(Canvas::New) {
*/
NAN_GETTER(Canvas::GetType) {
NanScope();
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
NanReturnValue(NanNew<String>(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image"));
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<String>(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image").ToLocalChecked());
}
/*
@ -93,9 +91,8 @@ NAN_GETTER(Canvas::GetType) {
*/
NAN_GETTER(Canvas::GetWidth) {
NanScope();
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
NanReturnValue(NanNew<Number>(canvas->width));
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(canvas->width));
}
/*
@ -103,11 +100,10 @@ NAN_GETTER(Canvas::GetWidth) {
*/
NAN_SETTER(Canvas::SetWidth) {
NanScope();
if (value->IsNumber()) {
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
canvas->width = value->Uint32Value();
canvas->resurface(args.This());
canvas->resurface(info.This());
}
}
@ -116,9 +112,8 @@ NAN_SETTER(Canvas::SetWidth) {
*/
NAN_GETTER(Canvas::GetHeight) {
NanScope();
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
NanReturnValue(NanNew<Number>(canvas->height));
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(canvas->height));
}
/*
@ -126,11 +121,10 @@ NAN_GETTER(Canvas::GetHeight) {
*/
NAN_SETTER(Canvas::SetHeight) {
NanScope();
if (value->IsNumber()) {
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
canvas->height = value->Uint32Value();
canvas->resurface(args.This());
canvas->resurface(info.This());
}
}
@ -200,7 +194,7 @@ int
Canvas::EIO_AfterToBuffer(eio_req *req) {
#endif
NanScope();
Nan::HandleScope scope;
closure_t *closure = (closure_t *) req->data;
#if NODE_VERSION_AT_LEAST(0, 6, 0)
delete req;
@ -212,9 +206,9 @@ Canvas::EIO_AfterToBuffer(eio_req *req) {
Local<Value> argv[1] = { Canvas::Error(closure->status) };
closure->pfn->Call(1, argv);
} else {
Local<Object> buf = NanNewBufferHandle((char*)closure->data, closure->len);
Local<Object> buf = Nan::CopyBuffer((char*)closure->data, closure->len).ToLocalChecked();
memcpy(Buffer::Data(buf), closure->data, closure->len);
Local<Value> argv[2] = { NanNew(NanNull()), buf };
Local<Value> argv[2] = { Nan::Null(), buf };
closure->pfn->Call(2, argv);
}
@ -234,31 +228,31 @@ Canvas::EIO_AfterToBuffer(eio_req *req) {
*/
NAN_METHOD(Canvas::ToBuffer) {
NanScope();
cairo_status_t status;
uint32_t compression_level = 6;
uint32_t filter = PNG_ALL_FILTERS;
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
// TODO: async / move this out
if (canvas->isPDF() || canvas->isSVG()) {
cairo_surface_finish(canvas->surface());
closure_t *closure = (closure_t *) canvas->closure();
Local<Object> buf = NanNewBufferHandle((char*) closure->data, closure->len);
NanReturnValue(buf);
Local<Object> buf = Nan::CopyBuffer((char*) closure->data, closure->len).ToLocalChecked();
info.GetReturnValue().Set(buf);
return;
}
if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) {
if (!args[1]->StrictEquals(NanUndefined())) {
if (info.Length() > 1 && !(info[1]->IsUndefined() && info[2]->IsUndefined())) {
if (!info[1]->IsUndefined()) {
bool good = true;
if (args[1]->IsNumber()) {
compression_level = args[1]->Uint32Value();
} else if (args[1]->IsString()) {
if (args[1]->StrictEquals(NanNew<String>("0"))) {
if (info[1]->IsNumber()) {
compression_level = info[1]->Uint32Value();
} else if (info[1]->IsString()) {
if (info[1]->StrictEquals(Nan::New<String>("0").ToLocalChecked())) {
compression_level = 0;
} else {
uint32_t tmp = args[1]->Uint32Value();
uint32_t tmp = info[1]->Uint32Value();
if (tmp == 0) {
good = false;
} else {
@ -271,24 +265,24 @@ NAN_METHOD(Canvas::ToBuffer) {
if (good) {
if (compression_level > 9) {
return NanThrowRangeError("Allowed compression levels lie in the range [0, 9].");
return Nan::ThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return NanThrowTypeError("Compression level must be a number.");
return Nan::ThrowTypeError("Compression level must be a number.");
}
}
if (!args[2]->StrictEquals(NanUndefined())) {
if (args[2]->IsUint32()) {
filter = args[2]->Uint32Value();
if (!info[2]->IsUndefined()) {
if (info[2]->IsUint32()) {
filter = info[2]->Uint32Value();
} else {
return NanThrowTypeError("Invalid filter value.");
return Nan::ThrowTypeError("Invalid filter value.");
}
}
}
// Async
if (args[0]->IsFunction()) {
if (info[0]->IsFunction()) {
closure_t *closure = (closure_t *) malloc(sizeof(closure_t));
status = closure_init(closure, canvas, compression_level, filter);
@ -296,12 +290,12 @@ NAN_METHOD(Canvas::ToBuffer) {
if (status) {
closure_destroy(closure);
free(closure);
return NanThrowError(Canvas::Error(status));
return Nan::ThrowError(Canvas::Error(status));
}
// TODO: only one callback fn in closure
canvas->Ref();
closure->pfn = new NanCallback(args[0].As<Function>());
closure->pfn = new Nan::Callback(info[0].As<Function>());
#if NODE_VERSION_AT_LEAST(0, 6, 0)
uv_work_t* req = new uv_work_t;
@ -312,7 +306,7 @@ NAN_METHOD(Canvas::ToBuffer) {
ev_ref(EV_DEFAULT_UC);
#endif
NanReturnUndefined();
return;
// Sync
} else {
closure_t closure;
@ -321,7 +315,7 @@ NAN_METHOD(Canvas::ToBuffer) {
// ensure closure is ok
if (status) {
closure_destroy(&closure);
return NanThrowError(Canvas::Error(status));
return Nan::ThrowError(Canvas::Error(status));
}
TryCatch try_catch;
@ -329,14 +323,16 @@ NAN_METHOD(Canvas::ToBuffer) {
if (try_catch.HasCaught()) {
closure_destroy(&closure);
NanReturnValue(try_catch.ReThrow());
try_catch.ReThrow();
return;
} else if (status) {
closure_destroy(&closure);
return NanThrowError(Canvas::Error(status));
return Nan::ThrowError(Canvas::Error(status));
} else {
Local<Object> buf = NanNewBufferHandle((char *)closure.data, closure.len);
Local<Object> buf = Nan::CopyBuffer((char *)closure.data, closure.len).ToLocalChecked();
closure_destroy(&closure);
NanReturnValue(buf);
info.GetReturnValue().Set(buf);
return;
}
}
}
@ -347,14 +343,14 @@ NAN_METHOD(Canvas::ToBuffer) {
static cairo_status_t
streamPNG(void *c, const uint8_t *data, unsigned len) {
NanScope();
Nan::HandleScope scope;
closure_t *closure = (closure_t *) c;
Local<Object> buf = NanNewBufferHandle((char *)data, len);
Local<Object> buf = Nan::CopyBuffer((char *)data, len).ToLocalChecked();
Local<Value> argv[3] = {
NanNew(NanNull())
Nan::Null()
, buf
, NanNew<Number>(len) };
NanMakeCallback(NanGetCurrentContext()->Global(), closure->fn, 3, argv);
, Nan::New<Number>(len) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure->fn, 3, argv);
return CAIRO_STATUS_SUCCESS;
}
@ -363,23 +359,22 @@ streamPNG(void *c, const uint8_t *data, unsigned len) {
*/
NAN_METHOD(Canvas::StreamPNGSync) {
NanScope();
uint32_t compression_level = 6;
uint32_t filter = PNG_ALL_FILTERS;
// TODO: async as well
if (!args[0]->IsFunction())
return NanThrowTypeError("callback function required");
if (!info[0]->IsFunction())
return Nan::ThrowTypeError("callback function required");
if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) {
if (!args[1]->StrictEquals(NanUndefined())) {
if (info.Length() > 1 && !(info[1]->IsUndefined() && info[2]->IsUndefined())) {
if (!info[1]->IsUndefined()) {
bool good = true;
if (args[1]->IsNumber()) {
compression_level = args[1]->Uint32Value();
} else if (args[1]->IsString()) {
if (args[1]->StrictEquals(NanNew<String>("0"))) {
if (info[1]->IsNumber()) {
compression_level = info[1]->Uint32Value();
} else if (info[1]->IsString()) {
if (info[1]->StrictEquals(Nan::New<String>("0").ToLocalChecked())) {
compression_level = 0;
} else {
uint32_t tmp = args[1]->Uint32Value();
uint32_t tmp = info[1]->Uint32Value();
if (tmp == 0) {
good = false;
} else {
@ -392,26 +387,26 @@ NAN_METHOD(Canvas::StreamPNGSync) {
if (good) {
if (compression_level > 9) {
return NanThrowRangeError("Allowed compression levels lie in the range [0, 9].");
return Nan::ThrowRangeError("Allowed compression levels lie in the range [0, 9].");
}
} else {
return NanThrowTypeError("Compression level must be a number.");
return Nan::ThrowTypeError("Compression level must be a number.");
}
}
if (!args[2]->StrictEquals(NanUndefined())) {
if (args[2]->IsUint32()) {
filter = args[2]->Uint32Value();
if (!info[2]->IsUndefined()) {
if (info[2]->IsUint32()) {
filter = info[2]->Uint32Value();
} else {
return NanThrowTypeError("Invalid filter value.");
return Nan::ThrowTypeError("Invalid filter value.");
}
}
}
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
closure_t closure;
closure.fn = Handle<Function>::Cast(args[0]);
closure.fn = Local<Function>::Cast(info[0]);
closure.compression_level = compression_level;
closure.filter = filter;
@ -420,18 +415,19 @@ NAN_METHOD(Canvas::StreamPNGSync) {
cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure);
if (try_catch.HasCaught()) {
NanReturnValue(try_catch.ReThrow());
try_catch.ReThrow();
return;
} else if (status) {
Local<Value> argv[1] = { Canvas::Error(status) };
NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
} else {
Local<Value> argv[3] = {
NanNew(NanNull())
, NanNew(NanNull())
, NanNew<Uint32>(0) };
NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv);
Nan::Null()
, Nan::Null()
, Nan::New<Uint32>(0) };
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
}
NanReturnUndefined();
return;
}
/*
@ -441,27 +437,27 @@ NAN_METHOD(Canvas::StreamPNGSync) {
#ifdef HAVE_JPEG
NAN_METHOD(Canvas::StreamJPEGSync) {
NanScope();
// TODO: async as well
if (!args[0]->IsNumber())
return NanThrowTypeError("buffer size required");
if (!args[1]->IsNumber())
return NanThrowTypeError("quality setting required");
if (!args[2]->IsBoolean())
return NanThrowTypeError("progressive setting required");
if (!args[3]->IsFunction())
return NanThrowTypeError("callback function required");
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(args.This());
if (!info[0]->IsNumber())
return Nan::ThrowTypeError("buffer size required");
if (!info[1]->IsNumber())
return Nan::ThrowTypeError("quality setting required");
if (!info[2]->IsBoolean())
return Nan::ThrowTypeError("progressive setting required");
if (!info[3]->IsFunction())
return Nan::ThrowTypeError("callback function required");
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
closure_t closure;
closure.fn = Handle<Function>::Cast(args[3]);
closure.fn = Local<Function>::Cast(info[3]);
TryCatch try_catch;
write_to_jpeg_stream(canvas->surface(), args[0]->NumberValue(), args[1]->NumberValue(), args[2]->BooleanValue(), &closure);
write_to_jpeg_stream(canvas->surface(), info[0]->NumberValue(), info[1]->NumberValue(), info[2]->BooleanValue(), &closure);
if (try_catch.HasCaught())
NanReturnValue(try_catch.ReThrow());
NanReturnUndefined();
if (try_catch.HasCaught()) {
try_catch.ReThrow();
}
return;
}
#endif
@ -470,7 +466,7 @@ NAN_METHOD(Canvas::StreamJPEGSync) {
* Initialize cairo surface.
*/
Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() {
Canvas::Canvas(int w, int h, canvas_type_t t): Nan::ObjectWrap() {
type = t;
width = w;
height = h;
@ -492,7 +488,7 @@ Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() {
} else {
_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
assert(_surface);
NanAdjustExternalMemory(4 * w * h);
Nan::AdjustExternalMemory(4 * w * h);
}
}
@ -511,7 +507,7 @@ Canvas::~Canvas() {
break;
case CANVAS_TYPE_IMAGE:
cairo_surface_destroy(_surface);
NanAdjustExternalMemory(-4 * width * height);
Nan::AdjustExternalMemory(-4 * width * height);
break;
}
}
@ -521,9 +517,9 @@ Canvas::~Canvas() {
*/
void
Canvas::resurface(Handle<Object> canvas) {
NanScope();
Handle<Value> context;
Canvas::resurface(Local<Object> canvas) {
Nan::HandleScope scope;
Local<Value> context;
switch (type) {
case CANVAS_TYPE_PDF:
cairo_pdf_surface_set_size(_surface, width, height);
@ -537,9 +533,9 @@ Canvas::resurface(Handle<Object> canvas) {
_surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height);
// Reset context
context = canvas->Get(NanNew<String>("context"));
context = canvas->Get(Nan::New<String>("context").ToLocalChecked());
if (!context->IsUndefined()) {
Context2d *context2d = ObjectWrap::Unwrap<Context2d>(context->ToObject());
Context2d *context2d = Nan::ObjectWrap::Unwrap<Context2d>(context->ToObject());
cairo_t *prev = context2d->context();
context2d->setContext(cairo_create(surface()));
cairo_destroy(prev);
@ -551,12 +547,12 @@ Canvas::resurface(Handle<Object> canvas) {
int old_height = cairo_image_surface_get_height(_surface);
cairo_surface_destroy(_surface);
_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
NanAdjustExternalMemory(4 * (width * height - old_width * old_height));
Nan::AdjustExternalMemory(4 * (width * height - old_width * old_height));
// Reset context
context = canvas->Get(NanNew<String>("context"));
context = canvas->Get(Nan::New<String>("context").ToLocalChecked());
if (!context->IsUndefined()) {
Context2d *context2d = ObjectWrap::Unwrap<Context2d>(context->ToObject());
Context2d *context2d = Nan::ObjectWrap::Unwrap<Context2d>(context->ToObject());
cairo_t *prev = context2d->context();
context2d->setContext(cairo_create(surface()));
cairo_destroy(prev);
@ -571,5 +567,5 @@ Canvas::resurface(Handle<Object> canvas) {
Local<Value>
Canvas::Error(cairo_status_t status) {
return Exception::Error(NanNew<String>(cairo_status_to_string(status)));
return Exception::Error(Nan::New<String>(cairo_status_to_string(status)).ToLocalChecked());
}

8
src/Canvas.h

@ -47,13 +47,13 @@ typedef enum {
* Canvas.
*/
class Canvas: public node::ObjectWrap {
class Canvas: public Nan::ObjectWrap {
public:
int width;
int height;
canvas_type_t type;
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_METHOD(ToBuffer);
static NAN_GETTER(GetType);
@ -85,7 +85,7 @@ class Canvas: public node::ObjectWrap {
inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
inline int stride(){ return cairo_image_surface_get_stride(_surface); }
Canvas(int width, int height, canvas_type_t type);
void resurface(Handle<Object> canvas);
void resurface(Local<Object> canvas);
private:
~Canvas();

73
src/CanvasGradient.cc

@ -9,25 +9,25 @@
#include "Canvas.h"
#include "CanvasGradient.h"
Persistent<FunctionTemplate> Gradient::constructor;
Nan::Persistent<FunctionTemplate> Gradient::constructor;
/*
* Initialize CanvasGradient.
*/
void
Gradient::Initialize(Handle<Object> target) {
NanScope();
Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = NanNew<FunctionTemplate>(Gradient::New);
NanAssignPersistent(constructor, ctor);
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Gradient::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("CanvasGradient"));
ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked());
// Prototype
NODE_SET_PROTOTYPE_METHOD(ctor, "addColorStop", AddColorStop);
target->Set(NanNew("CanvasGradient"), ctor->GetFunction());
Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop);
Nan::Set(target, Nan::New("CanvasGradient").ToLocalChecked(), ctor->GetFunction());
}
/*
@ -35,33 +35,33 @@ Gradient::Initialize(Handle<Object> target) {
*/
NAN_METHOD(Gradient::New) {
NanScope();
// Linear
if (4 == args.Length()) {
if (4 == info.Length()) {
Gradient *grad = new Gradient(
args[0]->NumberValue()
, args[1]->NumberValue()
, args[2]->NumberValue()
, args[3]->NumberValue());
grad->Wrap(args.This());
NanReturnValue(args.This());
info[0]->NumberValue()
, info[1]->NumberValue()
, info[2]->NumberValue()
, info[3]->NumberValue());
grad->Wrap(info.This());
info.GetReturnValue().Set(info.This());
return;
}
// Radial
if (6 == args.Length()) {
if (6 == info.Length()) {
Gradient *grad = new Gradient(
args[0]->NumberValue()
, args[1]->NumberValue()
, args[2]->NumberValue()
, args[3]->NumberValue()
, args[4]->NumberValue()
, args[5]->NumberValue());
grad->Wrap(args.This());
NanReturnValue(args.This());
info[0]->NumberValue()
, info[1]->NumberValue()
, info[2]->NumberValue()
, info[3]->NumberValue()
, info[4]->NumberValue()
, info[5]->NumberValue());
grad->Wrap(info.This());
info.GetReturnValue().Set(info.This());
return;
}
return NanThrowTypeError("invalid arguments");
return Nan::ThrowTypeError("invalid arguments");
}
/*
@ -69,31 +69,28 @@ NAN_METHOD(Gradient::New) {
*/
NAN_METHOD(Gradient::AddColorStop) {
NanScope();
if (!args[0]->IsNumber())
return NanThrowTypeError("offset required");
if (!args[1]->IsString())
return NanThrowTypeError("color string required");
if (!info[0]->IsNumber())
return Nan::ThrowTypeError("offset required");
if (!info[1]->IsString())
return Nan::ThrowTypeError("color string required");
Gradient *grad = ObjectWrap::Unwrap<Gradient>(args.This());
Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(info.This());
short ok;
String::Utf8Value str(args[1]);
String::Utf8Value str(info[1]);
uint32_t rgba = rgba_from_string(*str, &ok);
if (ok) {
rgba_t color = rgba_create(rgba);
cairo_pattern_add_color_stop_rgba(
grad->pattern()
, args[0]->NumberValue()
, info[0]->NumberValue()
, color.r
, color.g
, color.b
, color.a);
} else {
return NanThrowTypeError("parse color failed");
return Nan::ThrowTypeError("parse color failed");
}
NanReturnUndefined();
}
/*

6
src/CanvasGradient.h

@ -10,10 +10,10 @@
#include "Canvas.h"
class Gradient: public node::ObjectWrap {
class Gradient: public Nan::ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_METHOD(AddColorStop);
Gradient(double x0, double y0, double x1, double y1);

36
src/CanvasPattern.cc

@ -9,27 +9,27 @@
#include "Image.h"
#include "CanvasPattern.h"
Persistent<FunctionTemplate> Pattern::constructor;
Nan::Persistent<FunctionTemplate> Pattern::constructor;
/*
* Initialize CanvasPattern.
*/
void
Pattern::Initialize(Handle<Object> target) {
NanScope();
Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = NanNew<FunctionTemplate>(Pattern::New);
NanAssignPersistent(constructor, ctor);
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Pattern::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("CanvasPattern"));
ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("CanvasPattern"));
ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
// Prototype
target->Set(NanNew("CanvasPattern"), ctor->GetFunction());
Nan::Set(target, Nan::New("CanvasPattern").ToLocalChecked(), ctor->GetFunction());
}
/*
@ -37,39 +37,37 @@ Pattern::Initialize(Handle<Object> target) {
*/
NAN_METHOD(Pattern::New) {
NanScope();
int w = 0
, h = 0;
cairo_surface_t *surface;
Local<Object> obj = args[0]->ToObject();
Local<Object> obj = info[0]->ToObject();
// Image
if (NanHasInstance(Image::constructor, obj)) {
Image *img = ObjectWrap::Unwrap<Image>(obj);
if (Nan::New(Image::constructor)->HasInstance(obj)) {
Image *img = Nan::ObjectWrap::Unwrap<Image>(obj);
if (!img->isComplete()) {
return NanThrowError("Image given has not completed loading");
return Nan::ThrowError("Image given has not completed loading");
}
w = img->width;
h = img->height;
surface = img->surface();
// Canvas
} else if (NanHasInstance(Canvas::constructor, obj)) {
Canvas *canvas = ObjectWrap::Unwrap<Canvas>(obj);
} else if (Nan::New(Canvas::constructor)->HasInstance(obj)) {
Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
w = canvas->width;
h = canvas->height;
surface = canvas->surface();
// Invalid
} else {
return NanThrowTypeError("Image or Canvas expected");
return Nan::ThrowTypeError("Image or Canvas expected");
}
Pattern *pattern = new Pattern(surface,w,h);
pattern->Wrap(args.This());
NanReturnValue(args.This());
pattern->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}

6
src/CanvasPattern.h

@ -10,10 +10,10 @@
#include "Canvas.h"
class Pattern: public node::ObjectWrap {
class Pattern: public Nan::ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
Pattern(cairo_surface_t *surface, int w, int h);
inline cairo_pattern_t *pattern(){ return _pattern; }

939
src/CanvasRenderingContext2d.cc

File diff suppressed because it is too large

6
src/CanvasRenderingContext2d.h

@ -63,14 +63,14 @@ typedef struct {
void state_assign_fontFamily(canvas_state_t *state, const char *str);
#endif
class Context2d: public node::ObjectWrap {
class Context2d: public Nan::ObjectWrap {
public:
short stateno;
canvas_state_t *states[CANVAS_MAX_STATES];
canvas_state_t *state;
Context2d(Canvas *canvas);
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_METHOD(DrawImage);
static NAN_METHOD(PutImageData);

38
src/FontFace.cc

@ -8,7 +8,7 @@
#include <fontconfig/fontconfig.h>
Persistent<FunctionTemplate> FontFace::constructor;
Nan::Persistent<FunctionTemplate> FontFace::constructor;
/*
* Destroy ft_face.
@ -26,17 +26,17 @@ FontFace::~FontFace() {
*/
void
FontFace::Initialize(Handle<Object> target) {
NanScope();
FontFace::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = NanNew<FunctionTemplate>(FontFace::New);
NanAssignPersistent(constructor, ctor);
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(FontFace::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("FontFace"));
ctor->SetClassName(Nan::New("FontFace").ToLocalChecked());
// Prototype
target->Set(NanNew("FontFace"), ctor->GetFunction());
Nan::Set(target, Nan::New("FontFace").ToLocalChecked(), ctor->GetFunction());
}
/*
@ -53,15 +53,13 @@ static cairo_user_data_key_t key;
*/
NAN_METHOD(FontFace::New) {
NanScope();
if (!args[0]->IsString()
|| !args[1]->IsNumber()) {
return NanThrowError("Wrong argument types passed to FontFace constructor");
if (!info[0]->IsString()
|| !info[1]->IsNumber()) {
return Nan::ThrowError("Wrong argument types passed to FontFace constructor");
}
String::Utf8Value filePath(args[0]);
int faceIdx = int(args[1]->NumberValue());
String::Utf8Value filePath(info[0]);
int faceIdx = int(info[1]->NumberValue());
FT_Face ftFace;
FT_Error ftError;
@ -71,21 +69,21 @@ NAN_METHOD(FontFace::New) {
_initLibrary = false;
ftError = FT_Init_FreeType(&library);
if (ftError) {
return NanThrowError("Could not load library");
return Nan::ThrowError("Could not load library");
}
}
// Create new freetype font face.
ftError = FT_New_Face(library, *filePath, faceIdx, &ftFace);
if (ftError) {
return NanThrowError("Could not load font file");
return Nan::ThrowError("Could not load font file");
}
#if HAVE_PANGO
// Load the font file in fontconfig
FcBool ok = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(*filePath));
if (!ok) {
return NanThrowError("Could not load font in FontConfig");
return Nan::ThrowError("Could not load font in FontConfig");
}
#endif
@ -98,7 +96,7 @@ NAN_METHOD(FontFace::New) {
if (status) {
cairo_font_face_destroy (crFace);
FT_Done_Face (ftFace);
return NanThrowError("Failed to setup cairo font face user data");
return Nan::ThrowError("Failed to setup cairo font face user data");
}
// Explicit reference count the cairo font face. Otherwise the font face might
@ -106,7 +104,7 @@ NAN_METHOD(FontFace::New) {
cairo_font_face_reference(crFace);
FontFace *face = new FontFace(ftFace, crFace);
face->Wrap(args.This());
NanReturnValue(args.This());
face->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}

6
src/FontFace.h

@ -13,10 +13,10 @@
#include <cairo-ft.h>
#include FT_FREETYPE_H
class FontFace: public node::ObjectWrap {
class FontFace: public Nan::ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
FontFace(FT_Face ftFace, cairo_font_face_t *crFace)
:_ftFace(ftFace), _crFace(crFace) {}

105
src/Image.cc

@ -28,38 +28,38 @@ typedef struct {
uint8_t *buf;
} read_closure_t;
Persistent<FunctionTemplate> Image::constructor;
Nan::Persistent<FunctionTemplate> Image::constructor;
/*
* Initialize Image.
*/
void
Image::Initialize(Handle<Object> target) {
NanScope();
Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
Local<FunctionTemplate> ctor = NanNew<FunctionTemplate>(Image::New);
NanAssignPersistent(constructor, ctor);
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Image::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("Image"));
ctor->SetClassName(Nan::New("Image").ToLocalChecked());
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("Image"));
ctor->SetClassName(Nan::New("Image").ToLocalChecked());
// Prototype
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
proto->SetAccessor(NanNew("source"), GetSource, SetSource);
proto->SetAccessor(NanNew("complete"), GetComplete);
proto->SetAccessor(NanNew("width"), GetWidth);
proto->SetAccessor(NanNew("height"), GetHeight);
proto->SetAccessor(NanNew("onload"), GetOnload, SetOnload);
proto->SetAccessor(NanNew("onerror"), GetOnerror, SetOnerror);
Nan::SetAccessor(proto, Nan::New("source").ToLocalChecked(), GetSource, SetSource);
Nan::SetAccessor(proto, Nan::New("complete").ToLocalChecked(), GetComplete);
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
Nan::SetAccessor(proto, Nan::New("onload").ToLocalChecked(), GetOnload, SetOnload);
Nan::SetAccessor(proto, Nan::New("onerror").ToLocalChecked(), GetOnerror, SetOnerror);
#if CAIRO_VERSION_MINOR >= 10
proto->SetAccessor(NanNew("dataMode"), GetDataMode, SetDataMode);
ctor->Set(NanNew("MODE_IMAGE"), NanNew<Number>(DATA_IMAGE));
ctor->Set(NanNew("MODE_MIME"), NanNew<Number>(DATA_MIME));
Nan::SetAccessor(proto, Nan::New("dataMode").ToLocalChecked(), GetDataMode, SetDataMode);
ctor->Set(Nan::New("MODE_IMAGE").ToLocalChecked(), Nan::New<Number>(DATA_IMAGE));
ctor->Set(Nan::New("MODE_MIME").ToLocalChecked(), Nan::New<Number>(DATA_MIME));
#endif
target->Set(NanNew("Image"), ctor->GetFunction());
Nan::Set(target, Nan::New("Image").ToLocalChecked(), ctor->GetFunction());
}
/*
@ -67,11 +67,10 @@ Image::Initialize(Handle<Object> target) {
*/
NAN_METHOD(Image::New) {
NanScope();
Image *img = new Image;
img->data_mode = DATA_IMAGE;
img->Wrap(args.This());
NanReturnValue(args.This());
img->Wrap(info.This());
info.GetReturnValue().Set(info.This());
}
/*
@ -79,9 +78,8 @@ NAN_METHOD(Image::New) {
*/
NAN_GETTER(Image::GetComplete) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
NanReturnValue(NanNew<Boolean>(Image::COMPLETE == img->state));
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Boolean>(Image::COMPLETE == img->state));
}
#if CAIRO_VERSION_MINOR >= 10
@ -91,9 +89,8 @@ NAN_GETTER(Image::GetComplete) {
*/
NAN_GETTER(Image::GetDataMode) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
NanReturnValue(NanNew<Number>(img->data_mode));
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(img->data_mode));
}
/*
@ -102,7 +99,7 @@ NAN_GETTER(Image::GetDataMode) {
NAN_SETTER(Image::SetDataMode) {
if (value->IsNumber()) {
Image *img = ObjectWrap::Unwrap<Image>(args.This());
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
int mode = value->Uint32Value();
img->data_mode = (data_mode_t) mode;
}
@ -115,18 +112,16 @@ NAN_SETTER(Image::SetDataMode) {
*/
NAN_GETTER(Image::GetWidth) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
NanReturnValue(NanNew<Number>(img->width));
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(img->width));
}
/*
* Get height.
*/
NAN_GETTER(Image::GetHeight) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
NanReturnValue(NanNew<Number>(img->height));
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(img->height));
}
/*
@ -134,9 +129,8 @@ NAN_GETTER(Image::GetHeight) {
*/
NAN_GETTER(Image::GetSource) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
NanReturnValue(NanNew<String>(img->filename ? img->filename : ""));
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
info.GetReturnValue().Set(Nan::New<String>(img->filename ? img->filename : "").ToLocalChecked());
}
/*
@ -147,7 +141,7 @@ void
Image::clearData() {
if (_surface) {
cairo_surface_destroy(_surface);
NanAdjustExternalMemory(-_data_len);
Nan::AdjustExternalMemory(-_data_len);
_data_len = 0;
_surface = NULL;
}
@ -167,8 +161,7 @@ Image::clearData() {
*/
NAN_SETTER(Image::SetSource) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
cairo_status_t status = CAIRO_STATUS_READ_ERROR;
img->clearData();
@ -259,12 +252,11 @@ Image::readPNG(void *c, uint8_t *data, unsigned int len) {
*/
NAN_GETTER(Image::GetOnload) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
if (img->onload) {
NanReturnValue(img->onload->GetFunction());
info.GetReturnValue().Set(img->onload->GetFunction());
} else {
NanReturnNull();
info.GetReturnValue().SetNull();
}
}
@ -274,8 +266,8 @@ NAN_GETTER(Image::GetOnload) {
NAN_SETTER(Image::SetOnload) {
if (value->IsFunction()) {
Image *img = ObjectWrap::Unwrap<Image>(args.This());
img->onload = new NanCallback(value.As<Function>());
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
img->onload = new Nan::Callback(value.As<Function>());
}
}
@ -284,12 +276,11 @@ NAN_SETTER(Image::SetOnload) {
*/
NAN_GETTER(Image::GetOnerror) {
NanScope();
Image *img = ObjectWrap::Unwrap<Image>(args.This());
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
if (img->onerror) {
NanReturnValue(img->onerror->GetFunction());
info.GetReturnValue().Set(img->onerror->GetFunction());
} else {
NanReturnNull();
info.GetReturnValue().SetNull();
}
}
@ -299,8 +290,8 @@ NAN_GETTER(Image::GetOnerror) {
NAN_SETTER(Image::SetOnerror) {
if (value->IsFunction()) {
Image *img = ObjectWrap::Unwrap<Image>(args.This());
img->onerror = new NanCallback(value.As<Function>());
Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
img->onerror = new Nan::Callback(value.As<Function>());
}
}
@ -356,13 +347,13 @@ Image::load() {
void
Image::loaded() {
NanScope();
Nan::HandleScope scope;
state = COMPLETE;
width = cairo_image_surface_get_width(_surface);
height = cairo_image_surface_get_height(_surface);
_data_len = height * cairo_image_surface_get_stride(_surface);
NanAdjustExternalMemory(_data_len);
Nan::AdjustExternalMemory(_data_len);
if (onload != NULL) {
onload->Call(0, NULL);
@ -377,7 +368,7 @@ Image::loaded() {
void
Image::error(Local<Value> err) {
NanScope();
Nan::HandleScope scope;
if (onerror != NULL) {
Local<Value> argv[1] = { err };
onerror->Call(1, argv);
@ -448,7 +439,7 @@ get_gif_transparent_color(GifFileType *gif, int frame) {
int len = gif->SavedImages[frame].ExtensionBlockCount;
for (int x = 0; x < len; ++x, ++ext) {
if ((ext->Function == GRAPHICS_EXT_FUNC_CODE) && (ext->Bytes[0] & 1)) {
return ext->Bytes[3] == 0 ? 0 : (uint8_t) ext->Bytes[3];
return ext->Bytes[3] == 0 ? 0 : (uint8_t) ext->Bytes[3];
}
}
return -1;
@ -810,7 +801,7 @@ Image::decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len) {
void
clearMimeData(void *closure) {
NanAdjustExternalMemory(-((read_closure_t *)closure)->len);
Nan::AdjustExternalMemory(-((read_closure_t *)closure)->len);
free(((read_closure_t *) closure)->buf);
free(closure);
}
@ -837,7 +828,7 @@ Image::assignDataAsMime(uint8_t *data, int len, const char *mime_type) {
mime_closure->buf = mime_data;
mime_closure->len = len;
NanAdjustExternalMemory(len);
Nan::AdjustExternalMemory(len);
return cairo_surface_set_mime_data(_surface
, mime_type

16
src/Image.h

@ -27,14 +27,14 @@
class Image: public node::ObjectWrap {
class Image: public Nan::ObjectWrap {
public:
char *filename;
int width, height;
NanCallback *onload;
NanCallback *onerror;
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
Nan::Callback *onload;
Nan::Callback *onerror;
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_GETTER(GetSource);
static NAN_GETTER(GetOnload);
@ -47,9 +47,9 @@ class Image: public node::ObjectWrap {
static NAN_SETTER(SetOnload);
static NAN_SETTER(SetOnerror);
static NAN_SETTER(SetDataMode);
inline cairo_surface_t *surface(){ return _surface; }
inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
inline int stride(){ return cairo_image_surface_get_stride(_surface); }
inline cairo_surface_t *surface(){ return _surface; }
inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
inline int stride(){ return cairo_image_surface_get_stride(_surface); }
static int isPNG(uint8_t *data);
static int isJPEG(uint8_t *data);
static int isGIF(uint8_t *data);

70
src/ImageData.cc

@ -7,27 +7,27 @@
#include "ImageData.h"
Persistent<FunctionTemplate> ImageData::constructor;
Nan::Persistent<FunctionTemplate> ImageData::constructor;
/*
* Initialize ImageData.
*/
void
ImageData::Initialize(Handle<Object> target) {
NanScope();
ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
Nan::HandleScope scope;
// Constructor
Local<FunctionTemplate> ctor = NanNew<FunctionTemplate>(ImageData::New);
NanAssignPersistent(constructor, ctor);
Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(ImageData::New);
constructor.Reset(ctor);
ctor->InstanceTemplate()->SetInternalFieldCount(1);
ctor->SetClassName(NanNew("ImageData"));
ctor->SetClassName(Nan::New("ImageData").ToLocalChecked());
// Prototype
Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
proto->SetAccessor(NanNew("width"), GetWidth);
proto->SetAccessor(NanNew("height"), GetHeight);
target->Set(NanNew("ImageData"), ctor->GetFunction());
Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
Nan::Set(target, Nan::New("ImageData").ToLocalChecked(), ctor->GetFunction());
}
/*
@ -35,8 +35,6 @@ ImageData::Initialize(Handle<Object> target) {
*/
NAN_METHOD(ImageData::New) {
NanScope();
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
Local<v8::Object> clampedArray;
Local<Object> global = Context::GetCurrent()->Global();
@ -47,29 +45,29 @@ NAN_METHOD(ImageData::New) {
int width;
int height;
if (args[0]->IsUint32() && args[1]->IsUint32()) {
width = args[0]->Uint32Value();
height = args[1]->Uint32Value();
if (info[0]->IsUint32() && info[1]->IsUint32()) {
width = info[0]->Uint32Value();
height = info[1]->Uint32Value();
int size = width * height;
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
Handle<Value> caargv[] = { NanNew(size) };
Local<Object> clampedArray = global->Get(NanNew("Uint8ClampedArray")).As<Function>()->NewInstance(1, caargv);
Local<Int32> sizeHandle = Nan::New(size);
Local<Value> caargv[] = { sizeHandle };
clampedArray = global->Get(Nan::New("Uint8ClampedArray").ToLocalChecked()).As<Function>()->NewInstance(1, caargv);
#else
clampedArray = Uint8ClampedArray::New(ArrayBuffer::New(Isolate::GetCurrent(), size), 0, size);
#endif
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
} else if (args[0]->ToObject()->GetIndexedPropertiesExternalArrayDataType() == kExternalPixelArray && args[1]->IsUint32()) {
clampedArray = args[0]->ToObject();
} else if (info[0]->ToObject()->GetIndexedPropertiesExternalArrayDataType() == kExternalPixelArray && info[1]->IsUint32()) {
clampedArray = info[0]->ToObject();
#else
} else if (args[0]->IsUint8ClampedArray() && args[1]->IsUint32()) {
clampedArray = args[0].As<Uint8ClampedArray>();
} else if (info[0]->IsUint8ClampedArray() && info[1]->IsUint32()) {
clampedArray = info[0].As<Uint8ClampedArray>();
#endif
width = args[1]->Uint32Value();
if (args[2]->IsUint32()) {
height = args[2]->Uint32Value();
width = info[1]->Uint32Value();
if (info[2]->IsUint32()) {
height = info[2]->Uint32Value();
} else {
#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
height = clampedArray->GetIndexedPropertiesExternalArrayDataLength() / width;
@ -78,20 +76,24 @@ NAN_METHOD(ImageData::New) {
#endif
}
} else {
NanThrowTypeError("Expected (Uint8ClampedArray, width[, height]) or (width, height)");
NanReturnUndefined();
Nan::ThrowTypeError("Expected (Uint8ClampedArray, width[, height]) or (width, height)");
return;
}
// No behavior defined in spec. This is what WebKit does:
if (width < 1) width = 1;
if (height < 1) height = 1;
#if NODE_MAJOR_VERSION < 3
void *dataPtr = clampedArray->GetIndexedPropertiesExternalArrayData();
#else
void *dataPtr = clampedArray->Buffer()->GetContents().Data();
#endif
ImageData *imageData = new ImageData(reinterpret_cast<uint8_t*>(dataPtr), width, height);
imageData->Wrap(args.This());
args.This()->Set(NanNew("data"), clampedArray);
NanReturnValue(args.This());
imageData->Wrap(info.This());
info.This()->Set(Nan::New("data").ToLocalChecked(), clampedArray);
info.GetReturnValue().Set(info.This());
}
/*
@ -99,9 +101,8 @@ NAN_METHOD(ImageData::New) {
*/
NAN_GETTER(ImageData::GetWidth) {
NanScope();
ImageData *imageData = ObjectWrap::Unwrap<ImageData>(args.This());
NanReturnValue(NanNew<Number>(imageData->width()));
ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(imageData->width()));
}
/*
@ -109,7 +110,6 @@ NAN_GETTER(ImageData::GetWidth) {
*/
NAN_GETTER(ImageData::GetHeight) {
NanScope();
ImageData *imageData = ObjectWrap::Unwrap<ImageData>(args.This());
NanReturnValue(NanNew<Number>(imageData->height()));
ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
info.GetReturnValue().Set(Nan::New<Number>(imageData->height()));
}

6
src/ImageData.h

@ -12,10 +12,10 @@
#include <stdlib.h>
#include "v8.h"
class ImageData: public node::ObjectWrap {
class ImageData: public Nan::ObjectWrap {
public:
static Persistent<FunctionTemplate> constructor;
static void Initialize(Handle<Object> target);
static Nan::Persistent<FunctionTemplate> constructor;
static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
static NAN_METHOD(New);
static NAN_GETTER(GetWidth);
static NAN_GETTER(GetHeight);

32
src/JPEGStream.h

@ -29,15 +29,15 @@ init_closure_destination(j_compress_ptr cinfo){
boolean
empty_closure_output_buffer(j_compress_ptr cinfo){
NanScope();
Nan::HandleScope scope;
closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
Local<Object> buf = NanNewBufferHandle((char *)dest->buffer, dest->bufsize);
Local<Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize).ToLocalChecked();
Local<Value> argv[3] = {
NanNew(NanNull())
, NanNew(buf)
, NanNew<Integer>(dest->bufsize)
Nan::Null()
, buf
, Nan::New<Integer>(dest->bufsize)
};
NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, argv);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 3, argv);
cinfo->dest->next_output_byte = dest->buffer;
cinfo->dest->free_in_buffer = dest->bufsize;
return true;
@ -45,28 +45,28 @@ empty_closure_output_buffer(j_compress_ptr cinfo){
void
term_closure_destination(j_compress_ptr cinfo){
NanScope();
Nan::HandleScope scope;
closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
/* emit remaining data */
size_t remaining = dest->bufsize - cinfo->dest->free_in_buffer;
Local<Object> buf = NanNewBufferHandle((char *)dest->buffer, remaining);
Local<Object> buf = Nan::NewBuffer((char *)dest->buffer, remaining).ToLocalChecked();
Local<Value> data_argv[3] = {
NanNew(NanNull())
, NanNew(buf)
, NanNew<Number>(remaining)
Nan::Null()
, buf
, Nan::New<Number>(remaining)
};
NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, data_argv);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 3, data_argv);
// emit "end"
Local<Value> end_argv[3] = {
NanNew(NanNull())
, NanNew(NanNull())
, NanNew<Integer>(0)
Nan::Null()
, Nan::Null()
, Nan::New<Integer>(0)
};
NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, end_argv);
Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 3, end_argv);
}
void

6
src/closure.h

@ -23,8 +23,8 @@
*/
typedef struct {
NanCallback *pfn;
Handle<Function> fn;
Nan::Callback *pfn;
Local<Function> fn;
unsigned len;
unsigned max_len;
uint8_t *data;
@ -58,7 +58,7 @@ void
closure_destroy(closure_t *closure) {
if (closure->len) {
free(closure->data);
NanAdjustExternalMemory(-((intptr_t) closure->max_len));
Nan::AdjustExternalMemory(-((intptr_t) closure->max_len));
}
}

12
src/init.cc

@ -17,9 +17,7 @@
#include "FontFace.h"
#endif
extern "C" void
init (Handle<Object> target) {
NanScope();
NAN_MODULE_INIT(init) {
Canvas::Initialize(target);
Image::Initialize(target);
ImageData::Initialize(target);
@ -30,7 +28,7 @@ init (Handle<Object> target) {
FontFace::Initialize(target);
#endif
target->Set(NanNew<String>("cairoVersion"), NanNew<String>(cairo_version_string()));
target->Set(Nan::New<String>("cairoVersion").ToLocalChecked(), Nan::New<String>(cairo_version_string()).ToLocalChecked());
#ifdef HAVE_JPEG
#ifndef JPEG_LIB_VERSION_MAJOR
@ -55,16 +53,16 @@ init (Handle<Object> target) {
} else {
snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR);
}
target->Set(NanNew<String>("jpegVersion"), NanNew<String>(jpeg_version));
target->Set(Nan::New<String>("jpegVersion").ToLocalChecked(), Nan::New<String>(jpeg_version).ToLocalChecked());
#endif
#ifdef HAVE_GIF
#ifndef GIF_LIB_VERSION
char gif_version[10];
snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE);
target->Set(NanNew<String>("gifVersion"), NanNew<String>(gif_version));
target->Set(Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(gif_version).ToLocalChecked());
#else
target->Set(NanNew<String>("gifVersion"), NanNew<String>(GIF_LIB_VERSION));
target->Set(Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(GIF_LIB_VERSION).ToLocalChecked());
#endif
#endif
}

18
test/canvas.test.js

@ -639,5 +639,23 @@ module.exports = {
assert.equal(0, imageData.data[i+2]);
assert.equal(255, imageData.data[i+3]);
},
'test Canvas#createSyncPNGStream()': function(done) {
var canvas = new Canvas(20, 20);
var stream = canvas.createSyncPNGStream();
var firstChunk = true;
stream.on('data', function(chunk){
if (firstChunk) {
firstChunk = false;
assert.equal('PNG', chunk.slice(1,4).toString());
}
});
stream.on('end', function(){
done();
});
stream.on('error', function(err) {
done(err);
});
}
}

Loading…
Cancel
Save