From 68b2f35c1cbbfa8e51dd5415003f0baa3fb8df83 Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Wed, 2 Feb 2022 20:24:16 +0800 Subject: [PATCH 01/10] feat: support node worker[aka context aware] --- src/Canvas.cc | 3 -- src/Canvas.h | 1 - src/CanvasGradient.cc | 3 -- src/CanvasGradient.h | 2 +- src/CanvasPattern.cc | 22 +++++++----- src/CanvasPattern.h | 2 -- src/CanvasRenderingContext2d.cc | 62 +++++++++++++++++++-------------- src/CanvasRenderingContext2d.h | 5 ++- src/Image.cc | 9 +++-- src/Image.h | 1 - src/ImageData.cc | 3 -- src/ImageData.h | 1 - src/Util.h | 10 ++++++ src/init.cc | 9 ++++- 14 files changed, 75 insertions(+), 58 deletions(-) diff --git a/src/Canvas.cc b/src/Canvas.cc index bd39d4329..b0161ea55 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -38,8 +38,6 @@ using namespace v8; using namespace std; -Nan::Persistent Canvas::constructor; - std::vector font_face_list; /* @@ -52,7 +50,6 @@ Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Canvas::New); - constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("Canvas").ToLocalChecked()); diff --git a/src/Canvas.h b/src/Canvas.h index f356af035..06aa213bc 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -37,7 +37,6 @@ class FontFace { class Canvas: public Nan::ObjectWrap { public: - static Nan::Persistent constructor; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(ToBuffer); diff --git a/src/CanvasGradient.cc b/src/CanvasGradient.cc index 280fc2e8c..12cf489f8 100644 --- a/src/CanvasGradient.cc +++ b/src/CanvasGradient.cc @@ -7,8 +7,6 @@ using namespace v8; -Nan::Persistent Gradient::constructor; - /* * Initialize CanvasGradient. */ @@ -19,7 +17,6 @@ Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Gradient::New); - constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked()); diff --git a/src/CanvasGradient.h b/src/CanvasGradient.h index b6902c428..c5f01c054 100644 --- a/src/CanvasGradient.h +++ b/src/CanvasGradient.h @@ -5,10 +5,10 @@ #include #include #include +#include class Gradient: public Nan::ObjectWrap { public: - static Nan::Persistent constructor; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(AddColorStop); diff --git a/src/CanvasPattern.cc b/src/CanvasPattern.cc index fa3848b37..cc5d721a8 100644 --- a/src/CanvasPattern.cc +++ b/src/CanvasPattern.cc @@ -2,6 +2,7 @@ #include "CanvasPattern.h" +#include "Util.h" #include "Canvas.h" #include "Image.h" @@ -9,9 +10,6 @@ using namespace v8; const cairo_user_data_key_t *pattern_repeat_key; -Nan::Persistent Pattern::constructor; -Nan::Persistent Pattern::_DOMMatrix; - /* * Initialize CanvasPattern. */ @@ -22,7 +20,6 @@ Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Pattern::New); - constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked()); Nan::SetPrototypeMethod(ctor, "setTransform", SetTransform); @@ -38,7 +35,13 @@ Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { */ NAN_METHOD(Pattern::SaveExternalModules) { - _DOMMatrix.Reset(Nan::To(info[0]).ToLocalChecked()); + Local DOMMatrixName = Nan::New("CanvasPattern_DOMMatrix").ToLocalChecked(); + Local exports = Nan::Get(Nan::GetCurrentContext()->Global(), Nan::New("__node_canvas").ToLocalChecked()) + .ToLocalChecked() + .As(); + + Nan::Set(exports, DOMMatrixName, Nan::To(info[0]).ToLocalChecked()); + // _DOMMatrix.Reset(Nan::To(info[0]).ToLocalChecked()); } /* @@ -53,9 +56,11 @@ NAN_METHOD(Pattern::New) { cairo_surface_t *surface; Local obj = Nan::To(info[0]).ToLocalChecked(); + Local canvas_ctor = getFromExports("Canvas").As(); + Local image_ctor = getFromExports("Image").As(); // Image - if (Nan::New(Image::constructor)->HasInstance(obj)) { + if (obj->InstanceOf(Nan::GetCurrentContext(), image_ctor).FromJust()) { Image *img = Nan::ObjectWrap::Unwrap(obj); if (!img->isComplete()) { return Nan::ThrowError("Image given has not completed loading"); @@ -63,7 +68,7 @@ NAN_METHOD(Pattern::New) { surface = img->surface(); // Canvas - } else if (Nan::New(Canvas::constructor)->HasInstance(obj)) { + } else if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); surface = canvas->surface(); // Invalid @@ -92,7 +97,8 @@ NAN_METHOD(Pattern::SetTransform) { Local mat = Nan::To(info[0]).ToLocalChecked(); #if NODE_MAJOR_VERSION >= 8 - if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) { + Local _DOMMatrix = getFromExports("CanvasPattern_DOMMatrix").As(); + if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } #endif diff --git a/src/CanvasPattern.h b/src/CanvasPattern.h index 29e2171b6..86d5f8f8f 100644 --- a/src/CanvasPattern.h +++ b/src/CanvasPattern.h @@ -21,8 +21,6 @@ extern const cairo_user_data_key_t *pattern_repeat_key; class Pattern: public Nan::ObjectWrap { public: - static Nan::Persistent constructor; - static Nan::Persistent _DOMMatrix; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(SaveExternalModules); diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index b98fe4520..584939d13 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -21,8 +21,6 @@ using namespace v8; -Nan::Persistent Context2d::constructor; - /* * Rectangle arg assertions. */ @@ -81,9 +79,6 @@ inline static bool checkArgs(const Nan::FunctionCallbackInfo &info, doubl return areArgsValid; } -Nan::Persistent Context2d::_DOMMatrix; -Nan::Persistent Context2d::_parseFont; - /* * Initialize Context2d. */ @@ -94,7 +89,6 @@ Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Context2d::New); - constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("CanvasRenderingContext2D").ToLocalChecked()); @@ -675,7 +669,8 @@ NAN_METHOD(Context2d::New) { if (!info[0]->IsObject()) return Nan::ThrowTypeError("Canvas expected"); Local obj = Nan::To(info[0]).ToLocalChecked(); - if (!Nan::New(Canvas::constructor)->HasInstance(obj)) + Local canvas_ctor = getFromExports("Canvas").As(); + if (!obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) return Nan::ThrowTypeError("Canvas expected"); Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); @@ -718,8 +713,13 @@ NAN_METHOD(Context2d::New) { */ NAN_METHOD(Context2d::SaveExternalModules) { - _DOMMatrix.Reset(Nan::To(info[0]).ToLocalChecked()); - _parseFont.Reset(Nan::To(info[1]).ToLocalChecked()); + Local exports = Nan::Get(Nan::GetCurrentContext()->Global(), Nan::New("__node_canvas").ToLocalChecked()) + .ToLocalChecked() + .As(); + Local DOMMatrixName = Nan::New("CanvasRenderingContext2D_DOMMatrix").ToLocalChecked(); + Local parseFontName = Nan::New("CanvasRenderingContext2D_parseFont").ToLocalChecked(); + Nan::Set(exports, DOMMatrixName, Nan::To(info[0]).ToLocalChecked()); + Nan::Set(exports, parseFontName, Nan::To(info[0]).ToLocalChecked()); } /* @@ -773,7 +773,8 @@ NAN_METHOD(Context2d::PutImageData) { if (!info[0]->IsObject()) return Nan::ThrowTypeError("ImageData expected"); Local obj = Nan::To(info[0]).ToLocalChecked(); - if (!Nan::New(ImageData::constructor)->HasInstance(obj)) + Local image_data_ctor = getFromExports("ImageData").As(); + if (!obj->InstanceOf(Nan::GetCurrentContext(), image_data_ctor).FromJust()) return Nan::ThrowTypeError("ImageData expected"); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); @@ -1121,7 +1122,7 @@ NAN_METHOD(Context2d::GetImageData) { Local shHandle = Nan::New(sh); Local argv[argc] = { dataArray, swHandle, shHandle }; - Local ctor = Nan::GetFunction(Nan::New(ImageData::constructor)).ToLocalChecked(); + Local ctor = getFromExports("ImageData").As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -1162,7 +1163,7 @@ NAN_METHOD(Context2d::CreateImageData){ const int argc = 3; Local argv[argc] = { arr, Nan::New(width), Nan::New(height) }; - Local ctor = Nan::GetFunction(Nan::New(ImageData::constructor)).ToLocalChecked(); + Local ctor = getFromExports("ImageData").As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -1217,9 +1218,11 @@ NAN_METHOD(Context2d::DrawImage) { cairo_surface_t *surface; Local obj = Nan::To(info[0]).ToLocalChecked(); + Local canvas_ctor = getFromExports("Canvas").As(); + Local image_ctor = getFromExports("Image").As(); // Image - if (Nan::New(Image::constructor)->HasInstance(obj)) { + if (obj->InstanceOf(Nan::GetCurrentContext(), image_ctor).FromJust()) { Image *img = Nan::ObjectWrap::Unwrap(obj); if (!img->isComplete()) { return Nan::ThrowError("Image given has not completed loading"); @@ -1229,7 +1232,7 @@ NAN_METHOD(Context2d::DrawImage) { surface = img->surface(); // Canvas - } else if (Nan::New(Canvas::constructor)->HasInstance(obj)) { + } else if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); source_w = sw = canvas->getWidth(); source_h = sh = canvas->getHeight(); @@ -1761,7 +1764,8 @@ get_current_transform(Context2d *context) { const int argc = 1; Local argv[argc] = { arr }; - return Nan::NewInstance(context->_DOMMatrix.Get(iso), argc, argv).ToLocalChecked(); + Local _DOMMatrix = getFromExports("CanvasRenderingContext2D_DOMMatrix").As(); + return Nan::NewInstance(_DOMMatrix, argc, argv).ToLocalChecked(); } /* @@ -1799,9 +1803,10 @@ NAN_SETTER(Context2d::SetCurrentTransform) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Local ctx = Nan::GetCurrentContext(); Local mat = Nan::To(value).ToLocalChecked(); + Local _DOMMatrix = getFromExports("CanvasRenderingContext2D_DOMMatrix").As(); #if NODE_MAJOR_VERSION >= 8 - if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) { + if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } #endif @@ -1843,12 +1848,14 @@ NAN_SETTER(Context2d::SetFillStyle) { context->_fillStyle.Reset(); context->_setFillColor(str); } else if (value->IsObject()) { + Local canvas_ctor = getFromExports("Canvas").As(); + Local pattern_ctor = getFromExports("CanvasPattern").As(); Local obj = Nan::To(value).ToLocalChecked(); - if (Nan::New(Gradient::constructor)->HasInstance(obj)) { + if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { context->_fillStyle.Reset(value); Gradient *grad = Nan::ObjectWrap::Unwrap(obj); context->state->fillGradient = grad->pattern(); - } else if (Nan::New(Pattern::constructor)->HasInstance(obj)) { + } else if (obj->InstanceOf(Nan::GetCurrentContext(), pattern_ctor).FromJust()) { context->_fillStyle.Reset(value); Pattern *pattern = Nan::ObjectWrap::Unwrap(obj); context->state->fillPattern = pattern->pattern(); @@ -1887,11 +1894,13 @@ NAN_SETTER(Context2d::SetStrokeStyle) { context->_setStrokeColor(str); } else if (value->IsObject()) { Local obj = Nan::To(value).ToLocalChecked(); - if (Nan::New(Gradient::constructor)->HasInstance(obj)) { + Local pattern_ctor = getFromExports("CanvasPattern").As(); + Local gradient_ctor = getFromExports("CanvasGradient").As(); + if (obj->InstanceOf(Nan::GetCurrentContext(), gradient_ctor).FromJust()) { context->_strokeStyle.Reset(value); Gradient *grad = Nan::ObjectWrap::Unwrap(obj); context->state->strokeGradient = grad->pattern(); - } else if (Nan::New(Pattern::constructor)->HasInstance(obj)) { + } else if (obj->InstanceOf(Nan::GetCurrentContext(), pattern_ctor).FromJust()) { context->_strokeStyle.Reset(value); Pattern *pattern = Nan::ObjectWrap::Unwrap(obj); context->state->strokePattern = pattern->pattern(); @@ -2103,7 +2112,7 @@ NAN_METHOD(Context2d::CreatePattern) { const int argc = 2; Local argv[argc] = { image, repetition }; - Local ctor = Nan::GetFunction(Nan::New(Pattern::constructor)).ToLocalChecked(); + Local ctor = getFromExports("CanvasPattern").As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2112,8 +2121,8 @@ NAN_METHOD(Context2d::CreatePattern) { NAN_METHOD(Context2d::CreateLinearGradient) { const int argc = 4; Local argv[argc] = { info[0], info[1], info[2], info[3] }; + Local ctor = getFromExports("CanvasGradient").As(); - Local ctor = Nan::GetFunction(Nan::New(Gradient::constructor)).ToLocalChecked(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2123,7 +2132,7 @@ NAN_METHOD(Context2d::CreateRadialGradient) { const int argc = 6; Local argv[argc] = { info[0], info[1], info[2], info[3], info[4], info[5] }; - Local ctor = Nan::GetFunction(Nan::New(Gradient::constructor)).ToLocalChecked(); + Local ctor = getFromExports("CanvasGradient").As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2282,7 +2291,8 @@ NAN_METHOD(Context2d::SetTransform) { #if NODE_MAJOR_VERSION >= 8 Local ctx = Nan::GetCurrentContext(); - if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) { + Local _DOMMatrix = getFromExports("CanvasRenderingContext2D_DOMMatrix").As(); + if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } #endif @@ -2540,7 +2550,6 @@ NAN_GETTER(Context2d::GetFont) { NAN_SETTER(Context2d::SetFont) { if (!value->IsString()) return; - Isolate *iso = Isolate::GetCurrent(); Local ctx = Nan::GetCurrentContext(); Local str = Nan::To(value).ToLocalChecked(); @@ -2548,8 +2557,9 @@ NAN_SETTER(Context2d::SetFont) { const int argc = 1; Local argv[argc] = { value }; + Local _parseFont = getFromExports("CanvasRenderingContext2D_parseFont").As(); - Local mparsed = Nan::Call(_parseFont.Get(iso), ctx->Global(), argc, argv).ToLocalChecked(); + Local mparsed = Nan::Call(_parseFont, ctx->Global(), argc, argv).ToLocalChecked(); // parseFont returns undefined for invalid CSS font strings if (mparsed->IsUndefined()) return; Local font = Nan::To(mparsed).ToLocalChecked(); diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 8afb433d1..de41cdafc 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -62,9 +62,8 @@ class Context2d: public Nan::ObjectWrap { canvas_state_t *states[CANVAS_MAX_STATES]; canvas_state_t *state; Context2d(Canvas *canvas); - static Nan::Persistent _DOMMatrix; - static Nan::Persistent _parseFont; - static Nan::Persistent constructor; + // static Nan::Persistent _DOMMatrix; + // static Nan::Persistent _parseFont; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(SaveExternalModules); diff --git a/src/Image.cc b/src/Image.cc index 103b65ee7..e32aae2be 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -43,8 +43,6 @@ typedef struct { using namespace v8; -Nan::Persistent Image::constructor; - /* * Initialize Image. */ @@ -54,7 +52,6 @@ Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { Nan::HandleScope scope; Local ctor = Nan::New(Image::New); - constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("Image").ToLocalChecked()); @@ -186,7 +183,8 @@ NAN_SETTER(Image::SetHeight) { */ NAN_METHOD(Image::GetSource){ - if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Local ctor = getFromExports("Image").As(); + if (!info.This()->InstanceOf(Nan::GetCurrentContext(), ctor).FromJust()) { // #1534 Nan::ThrowTypeError("Method Image.GetSource called on incompatible receiver"); return; @@ -231,7 +229,8 @@ Image::clearData() { */ NAN_METHOD(Image::SetSource){ - if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Local ctor = getFromExports("Image").As(); + if (!info.This()->InstanceOf(Nan::GetCurrentContext(), ctor).FromJust()) { // #1534 Nan::ThrowTypeError("Method Image.SetSource called on incompatible receiver"); return; diff --git a/src/Image.h b/src/Image.h index 62bc3f13b..edd8625b6 100644 --- a/src/Image.h +++ b/src/Image.h @@ -39,7 +39,6 @@ class Image: public Nan::ObjectWrap { char *filename; int width, height; int naturalWidth, naturalHeight; - static Nan::Persistent constructor; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_GETTER(GetComplete); diff --git a/src/ImageData.cc b/src/ImageData.cc index 668733d39..6a1a3e6b0 100644 --- a/src/ImageData.cc +++ b/src/ImageData.cc @@ -6,8 +6,6 @@ using namespace v8; -Nan::Persistent ImageData::constructor; - /* * Initialize ImageData. */ @@ -18,7 +16,6 @@ ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(ImageData::New); - constructor.Reset(ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); ctor->SetClassName(Nan::New("ImageData").ToLocalChecked()); diff --git a/src/ImageData.h b/src/ImageData.h index 4832b37b2..e93bc121d 100644 --- a/src/ImageData.h +++ b/src/ImageData.h @@ -8,7 +8,6 @@ class ImageData: public Nan::ObjectWrap { public: - static Nan::Persistent constructor; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_GETTER(GetWidth); diff --git a/src/Util.h b/src/Util.h index dba6883a2..56c654bc3 100644 --- a/src/Util.h +++ b/src/Util.h @@ -32,3 +32,13 @@ inline bool streq_casein(std::string& str1, std::string& str2) { return c1 == c2 || std::toupper(c1) == std::toupper(c2); }); } + +inline v8::Local getFromExports(const char* key) +{ + v8::Local exports = Nan::Get( + Nan::GetCurrentContext()->Global(), + Nan::New("__node_canvas").ToLocalChecked()) + .ToLocalChecked().As(); + + return Nan::Get(exports, Nan::New(key).ToLocalChecked()).ToLocalChecked(); +} \ No newline at end of file diff --git a/src/init.cc b/src/init.cc index 816ba5837..49860d2cf 100644 --- a/src/init.cc +++ b/src/init.cc @@ -89,4 +89,11 @@ NAN_MODULE_INIT(init) { Nan::Set(target, Nan::New("freetypeVersion").ToLocalChecked(), Nan::New(freetype_version).ToLocalChecked()).Check(); } -NODE_MODULE(canvas, init); +NODE_MODULE_INIT() +{ + Local js_global = context->Global(); + + Nan::Set(js_global, Nan::New("__node_canvas").ToLocalChecked(), exports).Check(); + + init(exports); +} From d41ec5396ce6457e6465388e6db6a216e0a6da0d Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Wed, 2 Feb 2022 20:36:50 +0800 Subject: [PATCH 02/10] fix misplaced args --- src/CanvasRenderingContext2d.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 584939d13..0a2c3764b 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -719,7 +719,7 @@ NAN_METHOD(Context2d::SaveExternalModules) { Local DOMMatrixName = Nan::New("CanvasRenderingContext2D_DOMMatrix").ToLocalChecked(); Local parseFontName = Nan::New("CanvasRenderingContext2D_parseFont").ToLocalChecked(); Nan::Set(exports, DOMMatrixName, Nan::To(info[0]).ToLocalChecked()); - Nan::Set(exports, parseFontName, Nan::To(info[0]).ToLocalChecked()); + Nan::Set(exports, parseFontName, Nan::To(info[1]).ToLocalChecked()); } /* From 5c4c8b5be67d989cad541bc126b53d150b475a25 Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Wed, 2 Feb 2022 23:48:27 +0800 Subject: [PATCH 03/10] update changelog & rearrange code --- CHANGELOG.md | 1 + src/Canvas.cc | 6 ++-- src/Canvas.h | 1 + src/CanvasGradient.cc | 6 ++-- src/CanvasGradient.h | 1 + src/CanvasPattern.cc | 12 ++++---- src/CanvasPattern.h | 2 ++ src/CanvasRenderingContext2d.cc | 50 ++++++++++++++++++--------------- src/CanvasRenderingContext2d.h | 3 ++ src/Image.cc | 8 ++++-- src/Image.h | 1 + src/ImageData.cc | 6 ++-- src/ImageData.h | 1 + 13 files changed, 61 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 84f155f0d..d28663661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ project adheres to [Semantic Versioning](http://semver.org/). ================== ### Changed ### Added +* support nodejs worker ### Fixed * Stringify CanvasGradient, CanvasPattern and ImageData like browsers do. (#1639, #1646) * Add missing include for `toupper`. diff --git a/src/Canvas.cc b/src/Canvas.cc index b0161ea55..7445e223b 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -38,6 +38,8 @@ using namespace v8; using namespace std; +const char *Canvas::ctor_name = "Canvas"; + std::vector font_face_list; /* @@ -51,7 +53,7 @@ Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Canvas::New); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("Canvas").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -80,7 +82,7 @@ Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { Local ctx = Nan::GetCurrentContext(); Nan::Set(target, - Nan::New("Canvas").ToLocalChecked(), + Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); } diff --git a/src/Canvas.h b/src/Canvas.h index 06aa213bc..ec2816d99 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -37,6 +37,7 @@ class FontFace { class Canvas: public Nan::ObjectWrap { public: + static const char *ctor_name; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(ToBuffer); diff --git a/src/CanvasGradient.cc b/src/CanvasGradient.cc index 12cf489f8..a9b6e911c 100644 --- a/src/CanvasGradient.cc +++ b/src/CanvasGradient.cc @@ -7,6 +7,8 @@ using namespace v8; +const char *Gradient::ctor_name = "CanvasGradient"; + /* * Initialize CanvasGradient. */ @@ -18,13 +20,13 @@ Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Gradient::New); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); // Prototype Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop); Local ctx = Nan::GetCurrentContext(); Nan::Set(target, - Nan::New("CanvasGradient").ToLocalChecked(), + Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); } diff --git a/src/CanvasGradient.h b/src/CanvasGradient.h index c5f01c054..94a1e710d 100644 --- a/src/CanvasGradient.h +++ b/src/CanvasGradient.h @@ -9,6 +9,7 @@ class Gradient: public Nan::ObjectWrap { public: + static const char *ctor_name; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(AddColorStop); diff --git a/src/CanvasPattern.cc b/src/CanvasPattern.cc index cc5d721a8..acd3dcc0d 100644 --- a/src/CanvasPattern.cc +++ b/src/CanvasPattern.cc @@ -9,6 +9,8 @@ using namespace v8; const cairo_user_data_key_t *pattern_repeat_key; +const char *Pattern::ctor_name = "CanvasPattern"; +const char *Pattern::dom_matrix_name = "CanvasPattern_DOMMatrix"; /* * Initialize CanvasPattern. @@ -21,12 +23,12 @@ Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Pattern::New); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::SetPrototypeMethod(ctor, "setTransform", SetTransform); // Prototype Local ctx = Nan::GetCurrentContext(); - Nan::Set(target, Nan::New("CanvasPattern").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); + Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); Nan::Set(target, Nan::New("CanvasPatternInit").ToLocalChecked(), Nan::New(SaveExternalModules)); } @@ -56,8 +58,8 @@ NAN_METHOD(Pattern::New) { cairo_surface_t *surface; Local obj = Nan::To(info[0]).ToLocalChecked(); - Local canvas_ctor = getFromExports("Canvas").As(); - Local image_ctor = getFromExports("Image").As(); + Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); + Local image_ctor = getFromExports(Image::ctor_name).As(); // Image if (obj->InstanceOf(Nan::GetCurrentContext(), image_ctor).FromJust()) { @@ -97,7 +99,7 @@ NAN_METHOD(Pattern::SetTransform) { Local mat = Nan::To(info[0]).ToLocalChecked(); #if NODE_MAJOR_VERSION >= 8 - Local _DOMMatrix = getFromExports("CanvasPattern_DOMMatrix").As(); + Local _DOMMatrix = getFromExports(dom_matrix_name).As(); if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } diff --git a/src/CanvasPattern.h b/src/CanvasPattern.h index 86d5f8f8f..26d5c7a9d 100644 --- a/src/CanvasPattern.h +++ b/src/CanvasPattern.h @@ -21,6 +21,8 @@ extern const cairo_user_data_key_t *pattern_repeat_key; class Pattern: public Nan::ObjectWrap { public: + static const char *ctor_name; + static const char *dom_matrix_name; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_METHOD(SaveExternalModules); diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 0a2c3764b..1cc406794 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -21,6 +21,10 @@ using namespace v8; +const char *Context2d::ctor_name = "CanvasRenderingContext2d"; +const char *Context2d::dom_matrix_name = "CanvasRenderingContext2D_DOMMatrix"; +const char *Context2d::parse_font_name = "CanvasRenderingContext2D_parseFont"; + /* * Rectangle arg assertions. */ @@ -90,7 +94,7 @@ Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(Context2d::New); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("CanvasRenderingContext2D").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -157,7 +161,7 @@ Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { SetProtoAccessor(proto, Nan::New("textBaseline").ToLocalChecked(), GetTextBaseline, SetTextBaseline, ctor); SetProtoAccessor(proto, Nan::New("textAlign").ToLocalChecked(), GetTextAlign, SetTextAlign, ctor); Local ctx = Nan::GetCurrentContext(); - Nan::Set(target, Nan::New("CanvasRenderingContext2d").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); + Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); Nan::Set(target, Nan::New("CanvasRenderingContext2dInit").ToLocalChecked(), Nan::New(SaveExternalModules)); } @@ -669,7 +673,7 @@ NAN_METHOD(Context2d::New) { if (!info[0]->IsObject()) return Nan::ThrowTypeError("Canvas expected"); Local obj = Nan::To(info[0]).ToLocalChecked(); - Local canvas_ctor = getFromExports("Canvas").As(); + Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); if (!obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) return Nan::ThrowTypeError("Canvas expected"); Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); @@ -716,10 +720,10 @@ NAN_METHOD(Context2d::SaveExternalModules) { Local exports = Nan::Get(Nan::GetCurrentContext()->Global(), Nan::New("__node_canvas").ToLocalChecked()) .ToLocalChecked() .As(); - Local DOMMatrixName = Nan::New("CanvasRenderingContext2D_DOMMatrix").ToLocalChecked(); - Local parseFontName = Nan::New("CanvasRenderingContext2D_parseFont").ToLocalChecked(); - Nan::Set(exports, DOMMatrixName, Nan::To(info[0]).ToLocalChecked()); - Nan::Set(exports, parseFontName, Nan::To(info[1]).ToLocalChecked()); + Local DOMMatrixNameKey = Nan::New(dom_matrix_name).ToLocalChecked(); + Local parseFontNameKey = Nan::New(parse_font_name).ToLocalChecked(); + Nan::Set(exports, DOMMatrixNameKey, Nan::To(info[0]).ToLocalChecked()); + Nan::Set(exports, parseFontNameKey, Nan::To(info[1]).ToLocalChecked()); } /* @@ -773,7 +777,7 @@ NAN_METHOD(Context2d::PutImageData) { if (!info[0]->IsObject()) return Nan::ThrowTypeError("ImageData expected"); Local obj = Nan::To(info[0]).ToLocalChecked(); - Local image_data_ctor = getFromExports("ImageData").As(); + Local image_data_ctor = getFromExports(ImageData::ctor_name).As(); if (!obj->InstanceOf(Nan::GetCurrentContext(), image_data_ctor).FromJust()) return Nan::ThrowTypeError("ImageData expected"); @@ -1122,7 +1126,7 @@ NAN_METHOD(Context2d::GetImageData) { Local shHandle = Nan::New(sh); Local argv[argc] = { dataArray, swHandle, shHandle }; - Local ctor = getFromExports("ImageData").As(); + Local ctor = getFromExports(ImageData::ctor_name).As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -1163,7 +1167,7 @@ NAN_METHOD(Context2d::CreateImageData){ const int argc = 3; Local argv[argc] = { arr, Nan::New(width), Nan::New(height) }; - Local ctor = getFromExports("ImageData").As(); + Local ctor = getFromExports(ImageData::ctor_name).As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -1218,8 +1222,8 @@ NAN_METHOD(Context2d::DrawImage) { cairo_surface_t *surface; Local obj = Nan::To(info[0]).ToLocalChecked(); - Local canvas_ctor = getFromExports("Canvas").As(); - Local image_ctor = getFromExports("Image").As(); + Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); + Local image_ctor = getFromExports(Image::ctor_name).As(); // Image if (obj->InstanceOf(Nan::GetCurrentContext(), image_ctor).FromJust()) { @@ -1764,7 +1768,7 @@ get_current_transform(Context2d *context) { const int argc = 1; Local argv[argc] = { arr }; - Local _DOMMatrix = getFromExports("CanvasRenderingContext2D_DOMMatrix").As(); + Local _DOMMatrix = getFromExports(Context2d::dom_matrix_name).As(); return Nan::NewInstance(_DOMMatrix, argc, argv).ToLocalChecked(); } @@ -1803,7 +1807,7 @@ NAN_SETTER(Context2d::SetCurrentTransform) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Local ctx = Nan::GetCurrentContext(); Local mat = Nan::To(value).ToLocalChecked(); - Local _DOMMatrix = getFromExports("CanvasRenderingContext2D_DOMMatrix").As(); + Local _DOMMatrix = getFromExports(dom_matrix_name).As(); #if NODE_MAJOR_VERSION >= 8 if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { @@ -1848,8 +1852,8 @@ NAN_SETTER(Context2d::SetFillStyle) { context->_fillStyle.Reset(); context->_setFillColor(str); } else if (value->IsObject()) { - Local canvas_ctor = getFromExports("Canvas").As(); - Local pattern_ctor = getFromExports("CanvasPattern").As(); + Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); + Local pattern_ctor = getFromExports(Pattern::ctor_name).As(); Local obj = Nan::To(value).ToLocalChecked(); if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { context->_fillStyle.Reset(value); @@ -1894,8 +1898,8 @@ NAN_SETTER(Context2d::SetStrokeStyle) { context->_setStrokeColor(str); } else if (value->IsObject()) { Local obj = Nan::To(value).ToLocalChecked(); - Local pattern_ctor = getFromExports("CanvasPattern").As(); - Local gradient_ctor = getFromExports("CanvasGradient").As(); + Local pattern_ctor = getFromExports(Pattern::ctor_name).As(); + Local gradient_ctor = getFromExports(Gradient::ctor_name).As(); if (obj->InstanceOf(Nan::GetCurrentContext(), gradient_ctor).FromJust()) { context->_strokeStyle.Reset(value); Gradient *grad = Nan::ObjectWrap::Unwrap(obj); @@ -2112,7 +2116,7 @@ NAN_METHOD(Context2d::CreatePattern) { const int argc = 2; Local argv[argc] = { image, repetition }; - Local ctor = getFromExports("CanvasPattern").As(); + Local ctor = getFromExports(Pattern::ctor_name).As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2121,7 +2125,7 @@ NAN_METHOD(Context2d::CreatePattern) { NAN_METHOD(Context2d::CreateLinearGradient) { const int argc = 4; Local argv[argc] = { info[0], info[1], info[2], info[3] }; - Local ctor = getFromExports("CanvasGradient").As(); + Local ctor = getFromExports(Gradient::ctor_name).As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); @@ -2132,7 +2136,7 @@ NAN_METHOD(Context2d::CreateRadialGradient) { const int argc = 6; Local argv[argc] = { info[0], info[1], info[2], info[3], info[4], info[5] }; - Local ctor = getFromExports("CanvasGradient").As(); + Local ctor = getFromExports(Gradient::ctor_name).As(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2291,7 +2295,7 @@ NAN_METHOD(Context2d::SetTransform) { #if NODE_MAJOR_VERSION >= 8 Local ctx = Nan::GetCurrentContext(); - Local _DOMMatrix = getFromExports("CanvasRenderingContext2D_DOMMatrix").As(); + Local _DOMMatrix = getFromExports(dom_matrix_name).As(); if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } @@ -2557,7 +2561,7 @@ NAN_SETTER(Context2d::SetFont) { const int argc = 1; Local argv[argc] = { value }; - Local _parseFont = getFromExports("CanvasRenderingContext2D_parseFont").As(); + Local _parseFont = getFromExports(parse_font_name).As(); Local mparsed = Nan::Call(_parseFont, ctx->Global(), argc, argv).ToLocalChecked(); // parseFont returns undefined for invalid CSS font strings diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index de41cdafc..306c843e6 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -62,6 +62,9 @@ class Context2d: public Nan::ObjectWrap { canvas_state_t *states[CANVAS_MAX_STATES]; canvas_state_t *state; Context2d(Canvas *canvas); + static const char *ctor_name; + static const char *dom_matrix_name; + static const char *parse_font_name; // static Nan::Persistent _DOMMatrix; // static Nan::Persistent _parseFont; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); diff --git a/src/Image.cc b/src/Image.cc index e32aae2be..5a3e4e0d2 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -43,6 +43,8 @@ typedef struct { using namespace v8; +const char *Image::ctor_name = "Image"; + /* * Initialize Image. */ @@ -53,7 +55,7 @@ Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { Local ctor = Nan::New(Image::New); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("Image").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -183,7 +185,7 @@ NAN_SETTER(Image::SetHeight) { */ NAN_METHOD(Image::GetSource){ - Local ctor = getFromExports("Image").As(); + Local ctor = getFromExports(ctor_name).As(); if (!info.This()->InstanceOf(Nan::GetCurrentContext(), ctor).FromJust()) { // #1534 Nan::ThrowTypeError("Method Image.GetSource called on incompatible receiver"); @@ -229,7 +231,7 @@ Image::clearData() { */ NAN_METHOD(Image::SetSource){ - Local ctor = getFromExports("Image").As(); + Local ctor = getFromExports(ctor_name).As(); if (!info.This()->InstanceOf(Nan::GetCurrentContext(), ctor).FromJust()) { // #1534 Nan::ThrowTypeError("Method Image.SetSource called on incompatible receiver"); diff --git a/src/Image.h b/src/Image.h index edd8625b6..c4522cb77 100644 --- a/src/Image.h +++ b/src/Image.h @@ -39,6 +39,7 @@ class Image: public Nan::ObjectWrap { char *filename; int width, height; int naturalWidth, naturalHeight; + static const char *ctor_name; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_GETTER(GetComplete); diff --git a/src/ImageData.cc b/src/ImageData.cc index 6a1a3e6b0..e765f3e62 100644 --- a/src/ImageData.cc +++ b/src/ImageData.cc @@ -6,6 +6,8 @@ using namespace v8; +const char *ImageData::ctor_name = "ImageData"; + /* * Initialize ImageData. */ @@ -17,14 +19,14 @@ ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Constructor Local ctor = Nan::New(ImageData::New); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("ImageData").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); // Prototype Local proto = ctor->PrototypeTemplate(); SetProtoAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, NULL, ctor); SetProtoAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, NULL, ctor); Local ctx = Nan::GetCurrentContext(); - Nan::Set(target, Nan::New("ImageData").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); + Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); } /* diff --git a/src/ImageData.h b/src/ImageData.h index e93bc121d..ec2018dcf 100644 --- a/src/ImageData.h +++ b/src/ImageData.h @@ -8,6 +8,7 @@ class ImageData: public Nan::ObjectWrap { public: + static const char *ctor_name; static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); static NAN_METHOD(New); static NAN_GETTER(GetWidth); From 2e06b2fdcbc58cd5cc2226f96a832df5f0934a8a Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Thu, 3 Feb 2022 00:07:04 +0800 Subject: [PATCH 04/10] context aware backends --- src/Canvas.cc | 16 +++++++++++++--- src/backend/ImageBackend.cc | 8 ++++---- src/backend/ImageBackend.h | 2 +- src/backend/PdfBackend.cc | 8 ++++---- src/backend/PdfBackend.h | 2 +- src/backend/SvgBackend.cc | 8 ++++---- src/backend/SvgBackend.h | 2 +- 7 files changed, 28 insertions(+), 18 deletions(-) diff --git a/src/Canvas.cc b/src/Canvas.cc index 7445e223b..65b417912 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -113,9 +113,19 @@ NAN_METHOD(Canvas::New) { backend = new ImageBackend(width, height); } else if (info[0]->IsObject()) { - if (Nan::New(ImageBackend::constructor)->HasInstance(info[0]) || - Nan::New(PdfBackend::constructor)->HasInstance(info[0]) || - Nan::New(SvgBackend::constructor)->HasInstance(info[0])) { + Local backends_obj = getFromExports("Backends").As(); + Local image_backend = Nan::Get(Nan::GetCurrentContext(), Nan::New(ImageBackend::ctor_name).ToLocalChecked()) + .ToLocalChecked() + .As(); + Local pdf_backend = Nan::Get(Nan::GetCurrentContext(), Nan::New(PdfBackend::ctor_name).ToLocalChecked()) + .ToLocalChecked() + .As(); + Local svg_backend = Nan::Get(Nan::GetCurrentContext(), Nan::New(SvgBackend::ctor_name).ToLocalChecked()) + .ToLocalChecked() + .As(); + if (info[0]->InstanceOf(Nan::GetCurrentContext(), image_backend).FromJust() || + info[0]->InstanceOf(Nan::GetCurrentContext(), pdf_backend).FromJust() || + info[0]->InstanceOf(Nan::GetCurrentContext(), svg_backend).FromJust()) { backend = Nan::ObjectWrap::Unwrap(Nan::To(info[0]).ToLocalChecked()); }else{ return Nan::ThrowTypeError("Invalid arguments"); diff --git a/src/backend/ImageBackend.cc b/src/backend/ImageBackend.cc index d354d92cc..9bec667e7 100644 --- a/src/backend/ImageBackend.cc +++ b/src/backend/ImageBackend.cc @@ -55,17 +55,17 @@ void ImageBackend::setFormat(cairo_format_t _format) { this->format = _format; } -Nan::Persistent ImageBackend::constructor; +const char *ImageBackend::ctor_name = "ImageBackend"; void ImageBackend::Initialize(Local target) { Nan::HandleScope scope; Local ctor = Nan::New(ImageBackend::New); - ImageBackend::constructor.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("ImageBackend").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::Set(target, - Nan::New("ImageBackend").ToLocalChecked(), + Nan::New(ctor_name).ToLocalChecked(), Nan::GetFunction(ctor).ToLocalChecked()).Check(); } diff --git a/src/backend/ImageBackend.h b/src/backend/ImageBackend.h index f68dacfdb..eec702279 100644 --- a/src/backend/ImageBackend.h +++ b/src/backend/ImageBackend.h @@ -19,7 +19,7 @@ class ImageBackend : public Backend int32_t approxBytesPerPixel(); - static Nan::Persistent constructor; + static const char *ctor_name; static void Initialize(v8::Local target); static NAN_METHOD(New); const static cairo_format_t DEFAULT_FORMAT = CAIRO_FORMAT_ARGB32; diff --git a/src/backend/PdfBackend.cc b/src/backend/PdfBackend.cc index d8bd23422..113ef5af8 100644 --- a/src/backend/PdfBackend.cc +++ b/src/backend/PdfBackend.cc @@ -34,17 +34,17 @@ cairo_surface_t* PdfBackend::recreateSurface() { } -Nan::Persistent PdfBackend::constructor; +const char *PdfBackend::ctor_name = "PdfBackend"; void PdfBackend::Initialize(Local target) { Nan::HandleScope scope; Local ctor = Nan::New(PdfBackend::New); - PdfBackend::constructor.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("PdfBackend").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::Set(target, - Nan::New("PdfBackend").ToLocalChecked(), + Nan::New(ctor_name).ToLocalChecked(), Nan::GetFunction(ctor).ToLocalChecked()).Check(); } diff --git a/src/backend/PdfBackend.h b/src/backend/PdfBackend.h index 03656f500..5f53e1f7c 100644 --- a/src/backend/PdfBackend.h +++ b/src/backend/PdfBackend.h @@ -18,7 +18,7 @@ class PdfBackend : public Backend ~PdfBackend(); static Backend *construct(int width, int height); - static Nan::Persistent constructor; + static const char* ctor_name; static void Initialize(v8::Local target); static NAN_METHOD(New); }; diff --git a/src/backend/SvgBackend.cc b/src/backend/SvgBackend.cc index 10bf4caa7..65e133960 100644 --- a/src/backend/SvgBackend.cc +++ b/src/backend/SvgBackend.cc @@ -42,17 +42,17 @@ cairo_surface_t* SvgBackend::recreateSurface() { } -Nan::Persistent SvgBackend::constructor; +const char *SvgBackend::ctor_name = "SvgBackend"; void SvgBackend::Initialize(Local target) { Nan::HandleScope scope; Local ctor = Nan::New(SvgBackend::New); - SvgBackend::constructor.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New("SvgBackend").ToLocalChecked()); + ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::Set(target, - Nan::New("SvgBackend").ToLocalChecked(), + Nan::New(ctor_name).ToLocalChecked(), Nan::GetFunction(ctor).ToLocalChecked()).Check(); } diff --git a/src/backend/SvgBackend.h b/src/backend/SvgBackend.h index 6377b438b..ed5433119 100644 --- a/src/backend/SvgBackend.h +++ b/src/backend/SvgBackend.h @@ -18,7 +18,7 @@ class SvgBackend : public Backend ~SvgBackend(); static Backend *construct(int width, int height); - static Nan::Persistent constructor; + static const char *ctor_name; static void Initialize(v8::Local target); static NAN_METHOD(New); }; From 6a60f69dd3de8324168d161ca09c75a3e9dcf58f Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Thu, 3 Feb 2022 00:09:34 +0800 Subject: [PATCH 05/10] fix misplaced target --- src/Canvas.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Canvas.cc b/src/Canvas.cc index 65b417912..af87e456f 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -114,13 +114,13 @@ NAN_METHOD(Canvas::New) { } else if (info[0]->IsObject()) { Local backends_obj = getFromExports("Backends").As(); - Local image_backend = Nan::Get(Nan::GetCurrentContext(), Nan::New(ImageBackend::ctor_name).ToLocalChecked()) + Local image_backend = Nan::Get(backends_obj, Nan::New(ImageBackend::ctor_name).ToLocalChecked()) .ToLocalChecked() - .As(); - Local pdf_backend = Nan::Get(Nan::GetCurrentContext(), Nan::New(PdfBackend::ctor_name).ToLocalChecked()) + .As(); + Local pdf_backend = Nan::Get(backends_obj, Nan::New(PdfBackend::ctor_name).ToLocalChecked()) .ToLocalChecked() .As(); - Local svg_backend = Nan::Get(Nan::GetCurrentContext(), Nan::New(SvgBackend::ctor_name).ToLocalChecked()) + Local svg_backend = Nan::Get(backends_obj, Nan::New(SvgBackend::ctor_name).ToLocalChecked()) .ToLocalChecked() .As(); if (info[0]->InstanceOf(Nan::GetCurrentContext(), image_backend).FromJust() || From 3f9c41e00735911fb60152cd1feee606c201dd16 Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Fri, 4 Feb 2022 15:15:56 +0800 Subject: [PATCH 06/10] passing addon from top instead --- binding.gyp | 1 + src/AddonData.cc | 25 ++++++++ src/AddonData.h | 37 ++++++++++++ src/Backends.cc | 8 +-- src/Backends.h | 3 +- src/Canvas.cc | 47 +++++++-------- src/Canvas.h | 15 +---- src/CanvasGradient.cc | 9 ++- src/CanvasGradient.h | 3 +- src/CanvasPattern.cc | 31 +++++----- src/CanvasPattern.h | 3 +- src/CanvasRenderingContext2d.cc | 102 ++++++++++++++++++-------------- src/CanvasRenderingContext2d.h | 8 +-- src/Image.cc | 19 +++--- src/Image.h | 3 +- src/ImageData.cc | 9 ++- src/ImageData.h | 3 +- src/Util.h | 15 ++--- src/backend/Backend.cc | 1 + src/backend/ImageBackend.cc | 5 +- src/backend/ImageBackend.h | 3 +- src/backend/PdfBackend.cc | 8 ++- src/backend/PdfBackend.h | 3 +- src/backend/SvgBackend.cc | 5 +- src/backend/SvgBackend.h | 3 +- src/init.cc | 21 +++---- 26 files changed, 235 insertions(+), 155 deletions(-) create mode 100644 src/AddonData.cc create mode 100644 src/AddonData.h diff --git a/binding.gyp b/binding.gyp index 57f14ab8c..94ac3c989 100644 --- a/binding.gyp +++ b/binding.gyp @@ -59,6 +59,7 @@ 'target_name': 'canvas', 'include_dirs': ["(ins); + data->canvas_ctor_tpl.Reset(); + data->context2d_ctor_tpl.Reset(); + data->context2d_dom_matrix.Reset(); + data->context2d_parse_font.Reset(); + data->gradient_ctor_tpl.Reset(); + data->image_ctor_tpl.Reset(); + data->image_data_ctor_tpl.Reset(); + data->image_backend_ctor_tpl.Reset(); + data->pdf_backend_ctor_tpl.Reset(); + data->svg_backend_ctor_tpl.Reset(); + data->pattern_ctor_tpl.Reset(); + data->pattern_dom_matrix.Reset(); + + delete data; +} \ No newline at end of file diff --git a/src/AddonData.h b/src/AddonData.h new file mode 100644 index 000000000..13dc6eadb --- /dev/null +++ b/src/AddonData.h @@ -0,0 +1,37 @@ +#pragma once + +#include +#include +#include + +/* + * FontFace describes a font file in terms of one PangoFontDescription that + * will resolve to it and one that the user describes it as (like @font-face) + */ +class FontFace { + public: + PangoFontDescription *sys_desc = nullptr; + PangoFontDescription *user_desc = nullptr; + unsigned char file_path[1024]; +}; + +class AddonData { + public: + Nan::Persistent canvas_ctor_tpl; + Nan::Persistent gradient_ctor_tpl; + Nan::Persistent context2d_ctor_tpl; + Nan::Persistent image_data_ctor_tpl; + Nan::Persistent image_ctor_tpl; + Nan::Persistent pattern_ctor_tpl; + Nan::Persistent image_backend_ctor_tpl; + Nan::Persistent pdf_backend_ctor_tpl; + Nan::Persistent svg_backend_ctor_tpl; + Nan::Persistent context2d_dom_matrix; + Nan::Persistent context2d_parse_font; + Nan::Persistent pattern_dom_matrix; + std::vector font_face_list; + + AddonData(); + + static void Dispose(void*); +}; diff --git a/src/Backends.cc b/src/Backends.cc index 2256c32b6..903ea6fd5 100644 --- a/src/Backends.cc +++ b/src/Backends.cc @@ -6,13 +6,13 @@ using namespace v8; -void Backends::Initialize(Local target) { +void Backends::Initialize(Local target, AddonData* data) { Nan::HandleScope scope; Local obj = Nan::New(); - ImageBackend::Initialize(obj); - PdfBackend::Initialize(obj); - SvgBackend::Initialize(obj); + ImageBackend::Initialize(obj, data); + PdfBackend::Initialize(obj, data); + SvgBackend::Initialize(obj, data); Nan::Set(target, Nan::New("Backends").ToLocalChecked(), obj).Check(); } diff --git a/src/Backends.h b/src/Backends.h index dbea053ce..056b17405 100644 --- a/src/Backends.h +++ b/src/Backends.h @@ -3,8 +3,9 @@ #include "backend/Backend.h" #include #include +#include "AddonData.h" class Backends : public Nan::ObjectWrap { public: - static void Initialize(v8::Local target); + static void Initialize(v8::Local target, AddonData*); }; diff --git a/src/Canvas.cc b/src/Canvas.cc index af87e456f..0b3258e46 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -40,20 +40,20 @@ using namespace std; const char *Canvas::ctor_name = "Canvas"; -std::vector font_face_list; - /* * Initialize Canvas. */ void -Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { +Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData* addon_data) { Nan::HandleScope scope; + Local data_holder = Nan::New(addon_data); // Constructor - Local ctor = Nan::New(Canvas::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + Local ctor = Nan::New(Canvas::New, data_holder); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); + addon_data->canvas_ctor_tpl.Reset(ctor); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -95,6 +95,7 @@ NAN_METHOD(Canvas::New) { return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'"); } + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); Backend* backend = NULL; if (info[0]->IsNumber()) { int width = Nan::To(info[0]).FromMaybe(0), height = 0; @@ -113,19 +114,12 @@ NAN_METHOD(Canvas::New) { backend = new ImageBackend(width, height); } else if (info[0]->IsObject()) { - Local backends_obj = getFromExports("Backends").As(); - Local image_backend = Nan::Get(backends_obj, Nan::New(ImageBackend::ctor_name).ToLocalChecked()) - .ToLocalChecked() - .As(); - Local pdf_backend = Nan::Get(backends_obj, Nan::New(PdfBackend::ctor_name).ToLocalChecked()) - .ToLocalChecked() - .As(); - Local svg_backend = Nan::Get(backends_obj, Nan::New(SvgBackend::ctor_name).ToLocalChecked()) - .ToLocalChecked() - .As(); - if (info[0]->InstanceOf(Nan::GetCurrentContext(), image_backend).FromJust() || - info[0]->InstanceOf(Nan::GetCurrentContext(), pdf_backend).FromJust() || - info[0]->InstanceOf(Nan::GetCurrentContext(), svg_backend).FromJust()) { + Local image_backend = Nan::New(addon_data->image_backend_ctor_tpl); + Local pdf_backend = Nan::New(addon_data->pdf_backend_ctor_tpl); + Local svg_backend = Nan::New(addon_data->svg_backend_ctor_tpl); + if (image_backend->HasInstance(info[0]) || + pdf_backend->HasInstance(info[0]) || + svg_backend->HasInstance(info[0])) { backend = Nan::ObjectWrap::Unwrap(Nan::To(info[0]).ToLocalChecked()); }else{ return Nan::ThrowTypeError("Invalid arguments"); @@ -142,6 +136,7 @@ NAN_METHOD(Canvas::New) { Canvas* canvas = new Canvas(backend); canvas->Wrap(info.This()); + info.This()->SetInternalField(1, info.Data()); backend->setCanvas(canvas); @@ -724,6 +719,7 @@ str_value(Local val, const char *fallback, bool can_be_number) { } NAN_METHOD(Canvas::RegisterFont) { + AddonData *addon_data = get_data_from_if1(info.This()); if (!info[0]->IsString()) { return Nan::ThrowError("Wrong argument type"); } else if (!info[1]->IsObject()) { @@ -752,11 +748,11 @@ NAN_METHOD(Canvas::RegisterFont) { pango_font_description_set_style(user_desc, Canvas::GetStyleFromCSSString(style)); pango_font_description_set_family(user_desc, family); - auto found = std::find_if(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) { + auto found = std::find_if(addon_data->font_face_list.begin(), addon_data->font_face_list.end(), [&](FontFace& f) { return pango_font_description_equal(f.sys_desc, sys_desc); }); - if (found != font_face_list.end()) { + if (found != addon_data->font_face_list.end()) { pango_font_description_free(found->user_desc); found->user_desc = user_desc; } else if (register_font((unsigned char *) *filePath)) { @@ -764,7 +760,7 @@ NAN_METHOD(Canvas::RegisterFont) { face.user_desc = user_desc; face.sys_desc = sys_desc; strncpy((char *)face.file_path, (char *) *filePath, 1023); - font_face_list.push_back(face); + addon_data->font_face_list.push_back(face); } else { pango_font_description_free(user_desc); Nan::ThrowError("Could not load font to the system's font host"); @@ -782,14 +778,15 @@ NAN_METHOD(Canvas::RegisterFont) { NAN_METHOD(Canvas::DeregisterAllFonts) { // Unload all fonts from pango to free up memory bool success = true; + AddonData* addon_data = get_data_from_if1(info.This()); - std::for_each(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) { + std::for_each(addon_data->font_face_list.begin(), addon_data->font_face_list.end(), [&](FontFace& f) { if (!deregister_font( (unsigned char *)f.file_path )) success = false; pango_font_description_free(f.user_desc); pango_font_description_free(f.sys_desc); }); - font_face_list.clear(); + addon_data->font_face_list.clear(); if (!success) Nan::ThrowError("Could not deregister one or more fonts"); } @@ -871,7 +868,7 @@ Canvas::GetWeightFromCSSString(const char *weight) { */ PangoFontDescription * -Canvas::ResolveFontDescription(const PangoFontDescription *desc) { +Canvas::ResolveFontDescription(const PangoFontDescription *desc, AddonData *addon_data) { // One of the user-specified families could map to multiple SFNT family names // if someone registered two different fonts under the same family name. // https://drafts.csswg.org/css-fonts-3/#font-style-matching @@ -883,7 +880,7 @@ Canvas::ResolveFontDescription(const PangoFontDescription *desc) { for (string family; getline(families, family, ','); ) { string renamed_families; - for (auto& ff : font_face_list) { + for (auto& ff : addon_data->font_face_list) { string pangofamily = string(pango_font_description_get_family(ff.user_desc)); if (streq_casein(family, pangofamily)) { const char* sys_desc_family_name = pango_font_description_get_family(ff.sys_desc); diff --git a/src/Canvas.h b/src/Canvas.h index ec2816d99..2858d5066 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -10,6 +10,7 @@ #include #include #include +#include "AddonData.h" /* * Maxmimum states per context. @@ -20,16 +21,6 @@ #define CANVAS_MAX_STATES 64 #endif -/* - * FontFace describes a font file in terms of one PangoFontDescription that - * will resolve to it and one that the user describes it as (like @font-face) - */ -class FontFace { - public: - PangoFontDescription *sys_desc = nullptr; - PangoFontDescription *user_desc = nullptr; - unsigned char file_path[1024]; -}; /* * Canvas. @@ -38,7 +29,7 @@ class FontFace { class Canvas: public Nan::ObjectWrap { public: static const char *ctor_name; - static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); + static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData*); static NAN_METHOD(New); static NAN_METHOD(ToBuffer); static NAN_GETTER(GetType); @@ -58,7 +49,7 @@ class Canvas: public Nan::ObjectWrap { static void ToBufferAsyncAfter(uv_work_t *req); static PangoWeight GetWeightFromCSSString(const char *weight); static PangoStyle GetStyleFromCSSString(const char *style); - static PangoFontDescription *ResolveFontDescription(const PangoFontDescription *desc); + static PangoFontDescription *ResolveFontDescription(const PangoFontDescription *desc, AddonData*); DLL_PUBLIC inline Backend* backend() { return _backend; } DLL_PUBLIC inline cairo_surface_t* surface(){ return backend()->getSurface(); } diff --git a/src/CanvasGradient.cc b/src/CanvasGradient.cc index a9b6e911c..0a32254d2 100644 --- a/src/CanvasGradient.cc +++ b/src/CanvasGradient.cc @@ -14,13 +14,15 @@ const char *Gradient::ctor_name = "CanvasGradient"; */ void -Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { +Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData *addon_data) { Nan::HandleScope scope; + Local data_holder = Nan::New(addon_data); // Constructor - Local ctor = Nan::New(Gradient::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + Local ctor = Nan::New(Gradient::New, data_holder); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); + addon_data->gradient_ctor_tpl.Reset(ctor); // Prototype Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop); @@ -39,6 +41,7 @@ NAN_METHOD(Gradient::New) { return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'"); } + info.This()->SetInternalField(1, info.Data()); // Linear if (4 == info.Length()) { Gradient *grad = new Gradient( diff --git a/src/CanvasGradient.h b/src/CanvasGradient.h index 94a1e710d..ae1f2a722 100644 --- a/src/CanvasGradient.h +++ b/src/CanvasGradient.h @@ -6,11 +6,12 @@ #include #include #include +#include "AddonData.h" class Gradient: public Nan::ObjectWrap { public: static const char *ctor_name; - static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); + static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData*); static NAN_METHOD(New); static NAN_METHOD(AddColorStop); Gradient(double x0, double y0, double x1, double y1); diff --git a/src/CanvasPattern.cc b/src/CanvasPattern.cc index acd3dcc0d..5a91d7140 100644 --- a/src/CanvasPattern.cc +++ b/src/CanvasPattern.cc @@ -17,19 +17,21 @@ const char *Pattern::dom_matrix_name = "CanvasPattern_DOMMatrix"; */ void -Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { +Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData *addon_data) { Nan::HandleScope scope; + Local data_holder = Nan::New(addon_data); // Constructor - Local ctor = Nan::New(Pattern::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + Local ctor = Nan::New(Pattern::New, data_holder); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); + addon_data->pattern_ctor_tpl.Reset(ctor); Nan::SetPrototypeMethod(ctor, "setTransform", SetTransform); // Prototype Local ctx = Nan::GetCurrentContext(); Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); - Nan::Set(target, Nan::New("CanvasPatternInit").ToLocalChecked(), Nan::New(SaveExternalModules)); + Nan::Set(target, Nan::New("CanvasPatternInit").ToLocalChecked(), Nan::New(SaveExternalModules, data_holder)); } /* @@ -37,13 +39,9 @@ Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { */ NAN_METHOD(Pattern::SaveExternalModules) { - Local DOMMatrixName = Nan::New("CanvasPattern_DOMMatrix").ToLocalChecked(); - Local exports = Nan::Get(Nan::GetCurrentContext()->Global(), Nan::New("__node_canvas").ToLocalChecked()) - .ToLocalChecked() - .As(); + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); - Nan::Set(exports, DOMMatrixName, Nan::To(info[0]).ToLocalChecked()); - // _DOMMatrix.Reset(Nan::To(info[0]).ToLocalChecked()); + addon_data->pattern_dom_matrix.Reset(Nan::To(info[0]).ToLocalChecked()); } /* @@ -56,13 +54,14 @@ NAN_METHOD(Pattern::New) { } cairo_surface_t *surface; + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); Local obj = Nan::To(info[0]).ToLocalChecked(); - Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); - Local image_ctor = getFromExports(Image::ctor_name).As(); + Local canvas_ctor_tpl = Nan::New(addon_data->canvas_ctor_tpl); + Local image_ctor_tpl = Nan::New(addon_data->image_ctor_tpl); // Image - if (obj->InstanceOf(Nan::GetCurrentContext(), image_ctor).FromJust()) { + if (image_ctor_tpl->HasInstance(obj)) { Image *img = Nan::ObjectWrap::Unwrap(obj); if (!img->isComplete()) { return Nan::ThrowError("Image given has not completed loading"); @@ -70,7 +69,7 @@ NAN_METHOD(Pattern::New) { surface = img->surface(); // Canvas - } else if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { + } else if (canvas_ctor_tpl->HasInstance(obj)) { Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); surface = canvas->surface(); // Invalid @@ -87,6 +86,7 @@ NAN_METHOD(Pattern::New) { } Pattern *pattern = new Pattern(surface, repeat); pattern->Wrap(info.This()); + info.This()->SetInternalField(1, info.Data()); info.GetReturnValue().Set(info.This()); } @@ -94,12 +94,13 @@ NAN_METHOD(Pattern::New) { * Set the pattern-space to user-space transform. */ NAN_METHOD(Pattern::SetTransform) { + AddonData *addon_data = get_data_from_if1(info.This()); Pattern *pattern = Nan::ObjectWrap::Unwrap(info.This()); Local ctx = Nan::GetCurrentContext(); Local mat = Nan::To(info[0]).ToLocalChecked(); #if NODE_MAJOR_VERSION >= 8 - Local _DOMMatrix = getFromExports(dom_matrix_name).As(); + Local _DOMMatrix = Nan::New(addon_data->context2d_dom_matrix); if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } diff --git a/src/CanvasPattern.h b/src/CanvasPattern.h index 26d5c7a9d..8d4f3cb89 100644 --- a/src/CanvasPattern.h +++ b/src/CanvasPattern.h @@ -5,6 +5,7 @@ #include #include #include +#include "AddonData.h" /* * Canvas types. @@ -23,7 +24,7 @@ class Pattern: public Nan::ObjectWrap { public: static const char *ctor_name; static const char *dom_matrix_name; - static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); + static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData*); static NAN_METHOD(New); static NAN_METHOD(SaveExternalModules); static NAN_METHOD(SetTransform); diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 1cc406794..22a46758f 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -21,10 +21,6 @@ using namespace v8; -const char *Context2d::ctor_name = "CanvasRenderingContext2d"; -const char *Context2d::dom_matrix_name = "CanvasRenderingContext2D_DOMMatrix"; -const char *Context2d::parse_font_name = "CanvasRenderingContext2D_parseFont"; - /* * Rectangle arg assertions. */ @@ -88,13 +84,15 @@ inline static bool checkArgs(const Nan::FunctionCallbackInfo &info, doubl */ void -Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { +Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData* addon_data) { Nan::HandleScope scope; + Local data_holder = Nan::New(addon_data); // Constructor - Local ctor = Nan::New(Context2d::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); + Local ctor = Nan::New(Context2d::New, data_holder); + ctor->InstanceTemplate()->SetInternalFieldCount(2); + ctor->SetClassName(Nan::New("CanvasRenderingContext2D").ToLocalChecked()); + addon_data->context2d_ctor_tpl.Reset(ctor); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -161,8 +159,8 @@ Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { SetProtoAccessor(proto, Nan::New("textBaseline").ToLocalChecked(), GetTextBaseline, SetTextBaseline, ctor); SetProtoAccessor(proto, Nan::New("textAlign").ToLocalChecked(), GetTextAlign, SetTextAlign, ctor); Local ctx = Nan::GetCurrentContext(); - Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); - Nan::Set(target, Nan::New("CanvasRenderingContext2dInit").ToLocalChecked(), Nan::New(SaveExternalModules)); + Nan::Set(target, Nan::New("CanvasRenderingContext2d").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); + Nan::Set(target, Nan::New("CanvasRenderingContext2dInit").ToLocalChecked(), Nan::New(SaveExternalModules, data_holder)); } /* @@ -672,9 +670,10 @@ NAN_METHOD(Context2d::New) { if (!info[0]->IsObject()) return Nan::ThrowTypeError("Canvas expected"); + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); Local obj = Nan::To(info[0]).ToLocalChecked(); - Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); - if (!obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) + Local canvas_ctor = Nan::New(addon_data->canvas_ctor_tpl); + if (!canvas_ctor->HasInstance(obj)) return Nan::ThrowTypeError("Canvas expected"); Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); @@ -709,6 +708,7 @@ NAN_METHOD(Context2d::New) { Context2d *context = new Context2d(canvas); context->Wrap(info.This()); + info.This()->SetInternalField(1, info.Data()); info.GetReturnValue().Set(info.This()); } @@ -717,13 +717,9 @@ NAN_METHOD(Context2d::New) { */ NAN_METHOD(Context2d::SaveExternalModules) { - Local exports = Nan::Get(Nan::GetCurrentContext()->Global(), Nan::New("__node_canvas").ToLocalChecked()) - .ToLocalChecked() - .As(); - Local DOMMatrixNameKey = Nan::New(dom_matrix_name).ToLocalChecked(); - Local parseFontNameKey = Nan::New(parse_font_name).ToLocalChecked(); - Nan::Set(exports, DOMMatrixNameKey, Nan::To(info[0]).ToLocalChecked()); - Nan::Set(exports, parseFontNameKey, Nan::To(info[1]).ToLocalChecked()); + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); + addon_data->context2d_dom_matrix.Reset(Nan::To(info[0]).ToLocalChecked()); + addon_data->context2d_parse_font.Reset(Nan::To(info[1]).ToLocalChecked()); } /* @@ -777,8 +773,9 @@ NAN_METHOD(Context2d::PutImageData) { if (!info[0]->IsObject()) return Nan::ThrowTypeError("ImageData expected"); Local obj = Nan::To(info[0]).ToLocalChecked(); - Local image_data_ctor = getFromExports(ImageData::ctor_name).As(); - if (!obj->InstanceOf(Nan::GetCurrentContext(), image_data_ctor).FromJust()) + AddonData *addon_data = get_data_from_if1(info.This()); + Local image_data_ctor_tpl = Nan::New(addon_data->image_data_ctor_tpl); + if (!image_data_ctor_tpl->HasInstance(obj)) return Nan::ThrowTypeError("ImageData expected"); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); @@ -1126,7 +1123,8 @@ NAN_METHOD(Context2d::GetImageData) { Local shHandle = Nan::New(sh); Local argv[argc] = { dataArray, swHandle, shHandle }; - Local ctor = getFromExports(ImageData::ctor_name).As(); + AddonData *addon_data = get_data_from_if1(info.This()); + Local ctor = Nan::GetFunction(Nan::New(addon_data->image_data_ctor_tpl)).ToLocalChecked(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -1167,7 +1165,8 @@ NAN_METHOD(Context2d::CreateImageData){ const int argc = 3; Local argv[argc] = { arr, Nan::New(width), Nan::New(height) }; - Local ctor = getFromExports(ImageData::ctor_name).As(); + AddonData *addon_data = get_data_from_if1(info.This()); + Local ctor = Nan::GetFunction(Nan::New(addon_data->image_data_ctor_tpl)).ToLocalChecked(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -1221,12 +1220,13 @@ NAN_METHOD(Context2d::DrawImage) { cairo_surface_t *surface; + AddonData *addon_data = get_data_from_if1(info.This()); Local obj = Nan::To(info[0]).ToLocalChecked(); - Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); - Local image_ctor = getFromExports(Image::ctor_name).As(); + Local canvas_ctor_tpl = Nan::New(addon_data->canvas_ctor_tpl); + Local image_ctor_tpl = Nan::New(addon_data->image_ctor_tpl); // Image - if (obj->InstanceOf(Nan::GetCurrentContext(), image_ctor).FromJust()) { + if (image_ctor_tpl->HasInstance(obj)) { Image *img = Nan::ObjectWrap::Unwrap(obj); if (!img->isComplete()) { return Nan::ThrowError("Image given has not completed loading"); @@ -1236,7 +1236,7 @@ NAN_METHOD(Context2d::DrawImage) { surface = img->surface(); // Canvas - } else if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { + } else if (canvas_ctor_tpl->HasInstance(obj)) { Canvas *canvas = Nan::ObjectWrap::Unwrap(obj); source_w = sw = canvas->getWidth(); source_h = sh = canvas->getHeight(); @@ -1752,7 +1752,7 @@ NAN_SETTER(Context2d::SetQuality) { */ Local -get_current_transform(Context2d *context) { +get_current_transform(Context2d *context, AddonData *addon_data) { Isolate *iso = Isolate::GetCurrent(); Local arr = Float64Array::New(ArrayBuffer::New(iso, 48), 0, 6); @@ -1768,7 +1768,7 @@ get_current_transform(Context2d *context) { const int argc = 1; Local argv[argc] = { arr }; - Local _DOMMatrix = getFromExports(Context2d::dom_matrix_name).As(); + Local _DOMMatrix = Nan::New(addon_data->context2d_dom_matrix); return Nan::NewInstance(_DOMMatrix, argc, argv).ToLocalChecked(); } @@ -1793,8 +1793,9 @@ void parse_matrix_from_object(cairo_matrix_t &matrix, Local mat) { */ NAN_GETTER(Context2d::GetCurrentTransform) { + AddonData *addon_data = get_data_from_if1(info.This()); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); - Local instance = get_current_transform(context); + Local instance = get_current_transform(context, addon_data); info.GetReturnValue().Set(instance); } @@ -1804,10 +1805,11 @@ NAN_GETTER(Context2d::GetCurrentTransform) { */ NAN_SETTER(Context2d::SetCurrentTransform) { + AddonData *addon_data = get_data_from_if1(info.This()); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Local ctx = Nan::GetCurrentContext(); Local mat = Nan::To(value).ToLocalChecked(); - Local _DOMMatrix = getFromExports(dom_matrix_name).As(); + Local _DOMMatrix = Nan::New(addon_data->context2d_dom_matrix); #if NODE_MAJOR_VERSION >= 8 if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { @@ -1844,6 +1846,7 @@ NAN_GETTER(Context2d::GetFillStyle) { NAN_SETTER(Context2d::SetFillStyle) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); + AddonData *addon_data = get_data_from_if1(info.This()); if (value->IsString()) { MaybeLocal mstr = Nan::To(value); @@ -1852,14 +1855,14 @@ NAN_SETTER(Context2d::SetFillStyle) { context->_fillStyle.Reset(); context->_setFillColor(str); } else if (value->IsObject()) { - Local canvas_ctor = getFromExports(Canvas::ctor_name).As(); - Local pattern_ctor = getFromExports(Pattern::ctor_name).As(); + Local canvas_ctor_tpl = Nan::New(addon_data->canvas_ctor_tpl); + Local pattern_ctor_tpl = Nan::New(addon_data->pattern_ctor_tpl); Local obj = Nan::To(value).ToLocalChecked(); - if (obj->InstanceOf(Nan::GetCurrentContext(), canvas_ctor).FromJust()) { + if (canvas_ctor_tpl->HasInstance(obj)) { context->_fillStyle.Reset(value); Gradient *grad = Nan::ObjectWrap::Unwrap(obj); context->state->fillGradient = grad->pattern(); - } else if (obj->InstanceOf(Nan::GetCurrentContext(), pattern_ctor).FromJust()) { + } else if (pattern_ctor_tpl->HasInstance(obj)) { context->_fillStyle.Reset(value); Pattern *pattern = Nan::ObjectWrap::Unwrap(obj); context->state->fillPattern = pattern->pattern(); @@ -1889,6 +1892,7 @@ NAN_GETTER(Context2d::GetStrokeStyle) { NAN_SETTER(Context2d::SetStrokeStyle) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); + AddonData *addon_data = get_data_from_if1(info.This()); if (value->IsString()) { MaybeLocal mstr = Nan::To(value); @@ -1898,13 +1902,13 @@ NAN_SETTER(Context2d::SetStrokeStyle) { context->_setStrokeColor(str); } else if (value->IsObject()) { Local obj = Nan::To(value).ToLocalChecked(); - Local pattern_ctor = getFromExports(Pattern::ctor_name).As(); - Local gradient_ctor = getFromExports(Gradient::ctor_name).As(); - if (obj->InstanceOf(Nan::GetCurrentContext(), gradient_ctor).FromJust()) { + Local pattern_ctor_tpl = Nan::New(addon_data->pattern_ctor_tpl); + Local gradient_ctor_tpl = Nan::New(addon_data->gradient_ctor_tpl); + if (gradient_ctor_tpl->HasInstance(obj)) { context->_strokeStyle.Reset(value); Gradient *grad = Nan::ObjectWrap::Unwrap(obj); context->state->strokeGradient = grad->pattern(); - } else if (obj->InstanceOf(Nan::GetCurrentContext(), pattern_ctor).FromJust()) { + } else if (pattern_ctor_tpl->HasInstance(obj)) { context->_strokeStyle.Reset(value); Pattern *pattern = Nan::ObjectWrap::Unwrap(obj); context->state->strokePattern = pattern->pattern(); @@ -2107,6 +2111,7 @@ Local Context2d::_getStrokeColor() { } NAN_METHOD(Context2d::CreatePattern) { + AddonData *addon_data = get_data_from_if1(info.This()); Local image = info[0]; Local repetition = info[1]; @@ -2116,7 +2121,7 @@ NAN_METHOD(Context2d::CreatePattern) { const int argc = 2; Local argv[argc] = { image, repetition }; - Local ctor = getFromExports(Pattern::ctor_name).As(); + Local ctor = Nan::GetFunction(Nan::New(addon_data->pattern_ctor_tpl)).ToLocalChecked(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2124,8 +2129,9 @@ NAN_METHOD(Context2d::CreatePattern) { NAN_METHOD(Context2d::CreateLinearGradient) { const int argc = 4; + AddonData *addon_data = get_data_from_if1(info.This()); Local argv[argc] = { info[0], info[1], info[2], info[3] }; - Local ctor = getFromExports(Gradient::ctor_name).As(); + Local ctor = Nan::GetFunction(Nan::New(addon_data->gradient_ctor_tpl)).ToLocalChecked(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); @@ -2134,9 +2140,10 @@ NAN_METHOD(Context2d::CreateLinearGradient) { NAN_METHOD(Context2d::CreateRadialGradient) { const int argc = 6; + AddonData *addon_data = get_data_from_if1(info.This()); Local argv[argc] = { info[0], info[1], info[2], info[3], info[4], info[5] }; - Local ctor = getFromExports(Gradient::ctor_name).As(); + Local ctor = Nan::GetFunction(Nan::New(addon_data->gradient_ctor_tpl)).ToLocalChecked(); Local instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked(); info.GetReturnValue().Set(instance); @@ -2269,8 +2276,9 @@ NAN_METHOD(Context2d::Transform) { */ NAN_METHOD(Context2d::GetTransform) { + AddonData *addon_data = get_data_from_if1(info.This()); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); - Local instance = get_current_transform(context); + Local instance = get_current_transform(context, addon_data); info.GetReturnValue().Set(instance); } @@ -2290,12 +2298,13 @@ NAN_METHOD(Context2d::ResetTransform) { NAN_METHOD(Context2d::SetTransform) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); + AddonData *addon_data = get_data_from_if1(info.This()); if (info.Length() == 1) { Local mat = Nan::To(info[0]).ToLocalChecked(); #if NODE_MAJOR_VERSION >= 8 Local ctx = Nan::GetCurrentContext(); - Local _DOMMatrix = getFromExports(dom_matrix_name).As(); + Local _DOMMatrix = Nan::New(addon_data->context2d_dom_matrix); if (!mat->InstanceOf(ctx, _DOMMatrix).ToChecked()) { return Nan::ThrowTypeError("Expected DOMMatrix"); } @@ -2560,8 +2569,9 @@ NAN_SETTER(Context2d::SetFont) { if (!str->Length()) return; const int argc = 1; + AddonData *addon_data = get_data_from_if1(info.This()); Local argv[argc] = { value }; - Local _parseFont = getFromExports(parse_font_name).As(); + Local _parseFont = Nan::New(addon_data->context2d_parse_font); Local mparsed = Nan::Call(_parseFont, ctx->Global(), argc, argv).ToLocalChecked(); // parseFont returns undefined for invalid CSS font strings @@ -2593,7 +2603,7 @@ NAN_SETTER(Context2d::SetFont) { } } - PangoFontDescription *sys_desc = Canvas::ResolveFontDescription(desc); + PangoFontDescription *sys_desc = Canvas::ResolveFontDescription(desc, addon_data); pango_font_description_free(desc); if (size > 0) pango_font_description_set_absolute_size(sys_desc, size * PANGO_SCALE); diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 306c843e6..09f547f7f 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -7,6 +7,7 @@ #include "color.h" #include "nan.h" #include +#include "AddonData.h" typedef enum { TEXT_DRAW_PATHS, @@ -62,12 +63,7 @@ class Context2d: public Nan::ObjectWrap { canvas_state_t *states[CANVAS_MAX_STATES]; canvas_state_t *state; Context2d(Canvas *canvas); - static const char *ctor_name; - static const char *dom_matrix_name; - static const char *parse_font_name; - // static Nan::Persistent _DOMMatrix; - // static Nan::Persistent _parseFont; - static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); + static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData*); static NAN_METHOD(New); static NAN_METHOD(SaveExternalModules); static NAN_METHOD(DrawImage); diff --git a/src/Image.cc b/src/Image.cc index 5a3e4e0d2..200630925 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -50,12 +50,14 @@ const char *Image::ctor_name = "Image"; */ void -Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { +Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData *addon_data) { Nan::HandleScope scope; - Local ctor = Nan::New(Image::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + Local data_holder = Nan::New(addon_data); + Local ctor = Nan::New(Image::New, data_holder); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); + addon_data->image_ctor_tpl.Reset(ctor); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -89,6 +91,7 @@ NAN_METHOD(Image::New) { Image *img = new Image; img->data_mode = DATA_IMAGE; img->Wrap(info.This()); + info.This()->SetInternalField(1, info.Data()); Nan::Set(info.This(), Nan::New("onload").ToLocalChecked(), Nan::Null()).Check(); Nan::Set(info.This(), Nan::New("onerror").ToLocalChecked(), Nan::Null()).Check(); info.GetReturnValue().Set(info.This()); @@ -185,8 +188,9 @@ NAN_SETTER(Image::SetHeight) { */ NAN_METHOD(Image::GetSource){ - Local ctor = getFromExports(ctor_name).As(); - if (!info.This()->InstanceOf(Nan::GetCurrentContext(), ctor).FromJust()) { + AddonData *addon_data = get_data_from_if1(info.This()); + Local ctor_tpl = Nan::New(addon_data->image_ctor_tpl); + if (!ctor_tpl->HasInstance(info.This())) { // #1534 Nan::ThrowTypeError("Method Image.GetSource called on incompatible receiver"); return; @@ -231,8 +235,9 @@ Image::clearData() { */ NAN_METHOD(Image::SetSource){ - Local ctor = getFromExports(ctor_name).As(); - if (!info.This()->InstanceOf(Nan::GetCurrentContext(), ctor).FromJust()) { + AddonData *addon_data = get_data_from_if1(info.This()); + Local ctor_tpl = Nan::New(addon_data->image_ctor_tpl); + if (!ctor_tpl->HasInstance(info.This())) { // #1534 Nan::ThrowTypeError("Method Image.SetSource called on incompatible receiver"); return; diff --git a/src/Image.h b/src/Image.h index c4522cb77..8b99f11b6 100644 --- a/src/Image.h +++ b/src/Image.h @@ -8,6 +8,7 @@ #include #include // node < 7 uses libstdc++ on macOS which lacks complete c++11 #include +#include "AddonData.h" #ifdef HAVE_JPEG #include @@ -40,7 +41,7 @@ class Image: public Nan::ObjectWrap { int width, height; int naturalWidth, naturalHeight; static const char *ctor_name; - static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); + static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData*); static NAN_METHOD(New); static NAN_GETTER(GetComplete); static NAN_GETTER(GetWidth); diff --git a/src/ImageData.cc b/src/ImageData.cc index e765f3e62..097141708 100644 --- a/src/ImageData.cc +++ b/src/ImageData.cc @@ -13,13 +13,15 @@ const char *ImageData::ctor_name = "ImageData"; */ void -ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { +ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData *addon_data) { Nan::HandleScope scope; + Local data_holder = Nan::New(addon_data); // Constructor - Local ctor = Nan::New(ImageData::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + Local ctor = Nan::New(ImageData::New, data_holder); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); + addon_data->image_data_ctor_tpl.Reset(ctor); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -116,6 +118,7 @@ NAN_METHOD(ImageData::New) { ImageData *imageData = new ImageData(reinterpret_cast(*dataPtr), width, height); imageData->Wrap(info.This()); + info.This()->SetInternalField(1, info.Data()); Nan::Set(info.This(), Nan::New("data").ToLocalChecked(), dataArray).Check(); info.GetReturnValue().Set(info.This()); } diff --git a/src/ImageData.h b/src/ImageData.h index ec2018dcf..887d19a60 100644 --- a/src/ImageData.h +++ b/src/ImageData.h @@ -5,11 +5,12 @@ #include #include // node < 7 uses libstdc++ on macOS which lacks complete c++11 #include +#include "AddonData.h" class ImageData: public Nan::ObjectWrap { public: static const char *ctor_name; - static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target); + static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData*); static NAN_METHOD(New); static NAN_GETTER(GetWidth); static NAN_GETTER(GetHeight); diff --git a/src/Util.h b/src/Util.h index 56c654bc3..fb77f3203 100644 --- a/src/Util.h +++ b/src/Util.h @@ -3,6 +3,7 @@ #include #include #include +#include "AddonData.h" // Wrapper around Nan::SetAccessor that makes it easier to change the last // argument (signature). Getters/setters must be accessed only when there is @@ -33,12 +34,12 @@ inline bool streq_casein(std::string& str1, std::string& str2) { }); } -inline v8::Local getFromExports(const char* key) +inline AddonData* get_data_from_if1(v8::Local obj) { - v8::Local exports = Nan::Get( - Nan::GetCurrentContext()->Global(), - Nan::New("__node_canvas").ToLocalChecked()) - .ToLocalChecked().As(); - - return Nan::Get(exports, Nan::New(key).ToLocalChecked()).ToLocalChecked(); + if (obj->InternalFieldCount() < 2) + return nullptr; + if (!obj->GetInternalField(1)->IsExternal()) + return nullptr; + + return reinterpret_cast(obj->GetInternalField(1).As()->Value()); } \ No newline at end of file diff --git a/src/backend/Backend.cc b/src/backend/Backend.cc index 528f61a08..32670cefd 100644 --- a/src/backend/Backend.cc +++ b/src/backend/Backend.cc @@ -21,6 +21,7 @@ void Backend::init(const Nan::FunctionCallbackInfo &info) { Backend *backend = construct(width, height); backend->Wrap(info.This()); + info.This()->SetInternalField(1, info.Data()); info.GetReturnValue().Set(info.This()); } diff --git a/src/backend/ImageBackend.cc b/src/backend/ImageBackend.cc index 9bec667e7..c83fa0d25 100644 --- a/src/backend/ImageBackend.cc +++ b/src/backend/ImageBackend.cc @@ -57,12 +57,13 @@ void ImageBackend::setFormat(cairo_format_t _format) { const char *ImageBackend::ctor_name = "ImageBackend"; -void ImageBackend::Initialize(Local target) { +void ImageBackend::Initialize(Local target, AddonData *addon_data) { Nan::HandleScope scope; Local ctor = Nan::New(ImageBackend::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + addon_data->image_backend_ctor_tpl.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), diff --git a/src/backend/ImageBackend.h b/src/backend/ImageBackend.h index eec702279..b89f8787f 100644 --- a/src/backend/ImageBackend.h +++ b/src/backend/ImageBackend.h @@ -1,6 +1,7 @@ #pragma once #include "Backend.h" +#include "../AddonData.h" #include class ImageBackend : public Backend @@ -20,7 +21,7 @@ class ImageBackend : public Backend int32_t approxBytesPerPixel(); static const char *ctor_name; - static void Initialize(v8::Local target); + static void Initialize(v8::Local target, AddonData*); static NAN_METHOD(New); const static cairo_format_t DEFAULT_FORMAT = CAIRO_FORMAT_ARGB32; }; diff --git a/src/backend/PdfBackend.cc b/src/backend/PdfBackend.cc index 113ef5af8..83d80d07a 100644 --- a/src/backend/PdfBackend.cc +++ b/src/backend/PdfBackend.cc @@ -36,12 +36,14 @@ cairo_surface_t* PdfBackend::recreateSurface() { const char *PdfBackend::ctor_name = "PdfBackend"; -void PdfBackend::Initialize(Local target) { +void PdfBackend::Initialize(Local target, AddonData *addon_data) { Nan::HandleScope scope; - Local ctor = Nan::New(PdfBackend::New); + Local data_holder = Nan::New(addon_data); + Local ctor = Nan::New(PdfBackend::New, data_holder); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + addon_data->pdf_backend_ctor_tpl.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), diff --git a/src/backend/PdfBackend.h b/src/backend/PdfBackend.h index 5f53e1f7c..942794fb3 100644 --- a/src/backend/PdfBackend.h +++ b/src/backend/PdfBackend.h @@ -2,6 +2,7 @@ #include "Backend.h" #include "../closure.h" +#include "../AddonData.h" #include class PdfBackend : public Backend @@ -19,6 +20,6 @@ class PdfBackend : public Backend static Backend *construct(int width, int height); static const char* ctor_name; - static void Initialize(v8::Local target); + static void Initialize(v8::Local target, AddonData*); static NAN_METHOD(New); }; diff --git a/src/backend/SvgBackend.cc b/src/backend/SvgBackend.cc index 65e133960..2e6cde1c9 100644 --- a/src/backend/SvgBackend.cc +++ b/src/backend/SvgBackend.cc @@ -44,12 +44,13 @@ cairo_surface_t* SvgBackend::recreateSurface() { const char *SvgBackend::ctor_name = "SvgBackend"; -void SvgBackend::Initialize(Local target) { +void SvgBackend::Initialize(Local target, AddonData *addon_data) { Nan::HandleScope scope; Local ctor = Nan::New(SvgBackend::New); - ctor->InstanceTemplate()->SetInternalFieldCount(1); + addon_data->svg_backend_ctor_tpl.Reset(ctor); + ctor->InstanceTemplate()->SetInternalFieldCount(2); ctor->SetClassName(Nan::New(ctor_name).ToLocalChecked()); Nan::Set(target, Nan::New(ctor_name).ToLocalChecked(), diff --git a/src/backend/SvgBackend.h b/src/backend/SvgBackend.h index ed5433119..65754830c 100644 --- a/src/backend/SvgBackend.h +++ b/src/backend/SvgBackend.h @@ -2,6 +2,7 @@ #include "Backend.h" #include "../closure.h" +#include "../AddonData.h" #include class SvgBackend : public Backend @@ -19,6 +20,6 @@ class SvgBackend : public Backend static Backend *construct(int width, int height); static const char *ctor_name; - static void Initialize(v8::Local target); + static void Initialize(v8::Local target, AddonData*); static NAN_METHOD(New); }; diff --git a/src/init.cc b/src/init.cc index 49860d2cf..a0593d86d 100644 --- a/src/init.cc +++ b/src/init.cc @@ -33,13 +33,14 @@ using namespace v8; #endif NAN_MODULE_INIT(init) { - Backends::Initialize(target); - Canvas::Initialize(target); - Image::Initialize(target); - ImageData::Initialize(target); - Context2d::Initialize(target); - Gradient::Initialize(target); - Pattern::Initialize(target); + AddonData *data = new AddonData(); + Backends::Initialize(target, data); + Canvas::Initialize(target, data); + Image::Initialize(target, data); + ImageData::Initialize(target, data); + Context2d::Initialize(target, data); + Gradient::Initialize(target, data); + Pattern::Initialize(target, data); Nan::Set(target, Nan::New("cairoVersion").ToLocalChecked(), Nan::New(cairo_version_string()).ToLocalChecked()).Check(); #ifdef HAVE_JPEG @@ -90,10 +91,6 @@ NAN_MODULE_INIT(init) { } NODE_MODULE_INIT() -{ - Local js_global = context->Global(); - - Nan::Set(js_global, Nan::New("__node_canvas").ToLocalChecked(), exports).Check(); - +{ init(exports); } From a24fd67dc7ba0f8a283ee045a0e1c26014980c58 Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Fri, 4 Feb 2022 15:41:28 +0800 Subject: [PATCH 07/10] fix possible segmentation fault --- src/Canvas.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Canvas.cc b/src/Canvas.cc index 0b3258e46..fb5080f82 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -77,8 +77,8 @@ Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target, AddonData* add Nan::SetTemplate(proto, "PNG_ALL_FILTERS", Nan::New(PNG_ALL_FILTERS)); // Class methods - Nan::SetMethod(ctor, "_registerFont", RegisterFont); - Nan::SetMethod(ctor, "_deregisterAllFonts", DeregisterAllFonts); + Nan::SetMethod(ctor, "_registerFont", RegisterFont, data_holder); + Nan::SetMethod(ctor, "_deregisterAllFonts", DeregisterAllFonts, data_holder); Local ctx = Nan::GetCurrentContext(); Nan::Set(target, @@ -719,7 +719,7 @@ str_value(Local val, const char *fallback, bool can_be_number) { } NAN_METHOD(Canvas::RegisterFont) { - AddonData *addon_data = get_data_from_if1(info.This()); + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); if (!info[0]->IsString()) { return Nan::ThrowError("Wrong argument type"); } else if (!info[1]->IsObject()) { @@ -778,7 +778,7 @@ NAN_METHOD(Canvas::RegisterFont) { NAN_METHOD(Canvas::DeregisterAllFonts) { // Unload all fonts from pango to free up memory bool success = true; - AddonData* addon_data = get_data_from_if1(info.This()); + AddonData* addon_data = reinterpret_cast(info.Data().As()->Value()); std::for_each(addon_data->font_face_list.begin(), addon_data->font_face_list.end(), [&](FontFace& f) { if (!deregister_font( (unsigned char *)f.file_path )) success = false; From c9bfc6a4f12aa728d6b3b6c050ad0a6820fdce93 Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Fri, 4 Feb 2022 23:15:48 +0800 Subject: [PATCH 08/10] fix miss used constructor tpl --- src/CanvasRenderingContext2d.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 22a46758f..6e02b14bf 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -1855,10 +1855,10 @@ NAN_SETTER(Context2d::SetFillStyle) { context->_fillStyle.Reset(); context->_setFillColor(str); } else if (value->IsObject()) { - Local canvas_ctor_tpl = Nan::New(addon_data->canvas_ctor_tpl); + Local gradient_ctor_tpl = Nan::New(addon_data->gradient_ctor_tpl); Local pattern_ctor_tpl = Nan::New(addon_data->pattern_ctor_tpl); Local obj = Nan::To(value).ToLocalChecked(); - if (canvas_ctor_tpl->HasInstance(obj)) { + if (gradient_ctor_tpl->HasInstance(obj)) { context->_fillStyle.Reset(value); Gradient *grad = Nan::ObjectWrap::Unwrap(obj); context->state->fillGradient = grad->pattern(); From a9e3fffb5fb2c8c6fdcfc3c47f83ae8e07815f98 Mon Sep 17 00:00:00 2001 From: niyan-ly Date: Mon, 7 Feb 2022 22:13:00 +0800 Subject: [PATCH 09/10] add some basic test cases for worker env --- package.json | 1 + src/Canvas.cc | 2 +- test/worker.js | 47 +++++++++++++++++++++++++++++ test/worker.test.js | 73 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 test/worker.js create mode 100644 test/worker.test.js diff --git a/package.json b/package.json index b833e7168..b385be25c 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "dtslint": "^4.0.7", "express": "^4.16.3", "mocha": "^5.2.0", + "piscina": "^3.2.0", "pixelmatch": "^4.0.2", "standard": "^12.0.1", "typescript": "^4.2.2" diff --git a/src/Canvas.cc b/src/Canvas.cc index fb5080f82..827e9675b 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -719,7 +719,6 @@ str_value(Local val, const char *fallback, bool can_be_number) { } NAN_METHOD(Canvas::RegisterFont) { - AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); if (!info[0]->IsString()) { return Nan::ThrowError("Wrong argument type"); } else if (!info[1]->IsObject()) { @@ -731,6 +730,7 @@ NAN_METHOD(Canvas::RegisterFont) { if (!sys_desc) return Nan::ThrowError("Could not parse font file"); + AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); PangoFontDescription *user_desc = pango_font_description_new(); // now check the attrs, there are many ways to be wrong diff --git a/test/worker.js b/test/worker.js new file mode 100644 index 000000000..bfd54da6c --- /dev/null +++ b/test/worker.js @@ -0,0 +1,47 @@ +const { resolve } = require("path"); +const { createCanvas, registerFont } = require("../"); + +function create({ width, height } = { width: 800, height: 600 }) { + let canvas, context; + canvas = createCanvas(width, height); + context = canvas.getContext("2d"); + + return { + canvas, + context, + }; +} + +exports.getCanvasSize = ({ width, height }) => { + const { canvas, context } = create({ + width, + height, + }); + + return { + width: canvas.width, + height: canvas.height, + }; +}; + +exports.updateContext = (options) => { + const { canvas, context } = create(); + + for (const key in options) { + context[key] = options[key]; + } + + return Object.keys(options).reduce( + (acm, cur) => ({ + ...acm, + [cur]: context[cur], + }), + {} + ); +}; + +exports.registerFont = (options) => { + registerFont(options.path, { + family: options.fontFamily, + }); +}; diff --git a/test/worker.test.js b/test/worker.test.js new file mode 100644 index 000000000..73e0b0d5e --- /dev/null +++ b/test/worker.test.js @@ -0,0 +1,73 @@ +const assert = require("assert"); +const { resolve } = require("path"); +const Piscina = require("piscina"); + +const filename = resolve(__dirname, "./worker.js"); + +describe("worker:Canvas", () => { + it("create success", async () => { + const pool = new Piscina({ + filename, + }); + + const first = await pool.run( + { width: 800, height: 600 }, + { name: "getCanvasSize" } + ); + + const second = await pool.run( + { width: 900, height: 500 }, + { name: "getCanvasSize" } + ); + + assert( + first.width == 800 && first.height == 600, + "invalid first canvas size" + ); + assert( + second.width == 900 && second.height == 500, + "invalid second canvas size" + ); + }); + + it("context are independent", async () => { + const pool = new Piscina({ + filename, + }); + const ctx1 = { + font: "20px Helvetica", + fill: "red", + }; + const ctx2 = { + fill: "green", + }; + const ctxResult1 = await pool.run(ctx1, { + name: "updateContext", + }); + const ctxResult2 = await pool.run(ctx2, { name: "updateContext" }); + + assert(ctxResult1.font === ctx1.font, "ctx1 font didn't match"); + assert(ctxResult1.fill === ctx1.fill, "ctx1 fill did't match"); + assert(ctxResult2.fill === ctx2.fill, "ctx2 fill did't match"); + }); + + it("register font", async () => { + const pool = new Piscina({ + filename, + }); + pool.run( + { + path: resolve(__dirname, "../examples/pfennigFont/Pfennig.ttf"), + fontFamily: "pfenning", + }, + { name: "registerFont" } + ); + pool.run( + { + path: resolve(__dirname, "../examples/pfennigFont/PfennigItalic.sfd"), + fontFamily: "pfenning_italic", + }, + { name: "registerFont" } + ); + }); +}); From d987d4666a32c4b8644b5b1a2341680eec008875 Mon Sep 17 00:00:00 2001 From: niyan_ly Date: Sun, 13 Feb 2022 15:30:40 +0800 Subject: [PATCH 10/10] feat: thread safe font_face_list --- binding.gyp | 1 + src/AddonData.h | 1 - src/Canvas.cc | 34 ++++++++++++++++++------- src/lock.cc | 61 +++++++++++++++++++++++++++++++++++++++++++++ src/lock.h | 34 +++++++++++++++++++++++++ test/worker.test.js | 2 +- 6 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 src/lock.cc create mode 100644 src/lock.h diff --git a/binding.gyp b/binding.gyp index 94ac3c989..ac125d621 100644 --- a/binding.gyp +++ b/binding.gyp @@ -60,6 +60,7 @@ 'include_dirs': [" context2d_dom_matrix; Nan::Persistent context2d_parse_font; Nan::Persistent pattern_dom_matrix; - std::vector font_face_list; AddonData(); diff --git a/src/Canvas.cc b/src/Canvas.cc index 827e9675b..93e538125 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -21,6 +21,7 @@ #include "Util.h" #include #include "node_buffer.h" +#include "lock.h" #ifdef HAVE_JPEG #include "JPEGStream.h" @@ -40,6 +41,10 @@ using namespace std; const char *Canvas::ctor_name = "Canvas"; +// these variables are protected by uv_rwlock; +UVLockHandle rwlock_handle; +std::vector font_face_list; + /* * Initialize Canvas. */ @@ -730,7 +735,6 @@ NAN_METHOD(Canvas::RegisterFont) { if (!sys_desc) return Nan::ThrowError("Could not parse font file"); - AddonData *addon_data = reinterpret_cast(info.Data().As()->Value()); PangoFontDescription *user_desc = pango_font_description_new(); // now check the attrs, there are many ways to be wrong @@ -748,11 +752,13 @@ NAN_METHOD(Canvas::RegisterFont) { pango_font_description_set_style(user_desc, Canvas::GetStyleFromCSSString(style)); pango_font_description_set_family(user_desc, family); - auto found = std::find_if(addon_data->font_face_list.begin(), addon_data->font_face_list.end(), [&](FontFace& f) { + UVLocker locker(rwlock_handle, UVLocker::LockerType::mutex); + + auto found = std::find_if(font_face_list.begin(), font_face_list.end(), [&](FontFace& f) { return pango_font_description_equal(f.sys_desc, sys_desc); }); - if (found != addon_data->font_face_list.end()) { + if (found != font_face_list.end()) { pango_font_description_free(found->user_desc); found->user_desc = user_desc; } else if (register_font((unsigned char *) *filePath)) { @@ -760,11 +766,13 @@ NAN_METHOD(Canvas::RegisterFont) { face.user_desc = user_desc; face.sys_desc = sys_desc; strncpy((char *)face.file_path, (char *) *filePath, 1023); - addon_data->font_face_list.push_back(face); + font_face_list.push_back(face); } else { pango_font_description_free(user_desc); Nan::ThrowError("Could not load font to the system's font host"); } + + locker.clean(); } else { pango_font_description_free(user_desc); Nan::ThrowError(GENERIC_FACE_ERROR); @@ -778,15 +786,21 @@ NAN_METHOD(Canvas::RegisterFont) { NAN_METHOD(Canvas::DeregisterAllFonts) { // Unload all fonts from pango to free up memory bool success = true; - AddonData* addon_data = reinterpret_cast(info.Data().As()->Value()); + + UVLocker locker(rwlock_handle, UVLocker::LockerType::rd); + auto begin = font_face_list.begin(); + auto end = font_face_list.end(); + locker.clean(); - std::for_each(addon_data->font_face_list.begin(), addon_data->font_face_list.end(), [&](FontFace& f) { + std::for_each(begin, end, [&](FontFace& f) { if (!deregister_font( (unsigned char *)f.file_path )) success = false; pango_font_description_free(f.user_desc); pango_font_description_free(f.sys_desc); }); - - addon_data->font_face_list.clear(); + + locker = UVLocker(rwlock_handle, UVLocker::LockerType::wr); + font_face_list.clear(); + locker.clean(); if (!success) Nan::ThrowError("Could not deregister one or more fonts"); } @@ -880,7 +894,8 @@ Canvas::ResolveFontDescription(const PangoFontDescription *desc, AddonData *addo for (string family; getline(families, family, ','); ) { string renamed_families; - for (auto& ff : addon_data->font_face_list) { + UVLocker locker(rwlock_handle, UVLocker::LockerType::rd); + for (auto& ff : font_face_list) { string pangofamily = string(pango_font_description_get_family(ff.user_desc)); if (streq_casein(family, pangofamily)) { const char* sys_desc_family_name = pango_font_description_get_family(ff.sys_desc); @@ -899,6 +914,7 @@ Canvas::ResolveFontDescription(const PangoFontDescription *desc, AddonData *addo } } } + locker.clean(); if (resolved_families.size()) resolved_families += ','; resolved_families += renamed_families.size() ? renamed_families : family; diff --git a/src/lock.cc b/src/lock.cc new file mode 100644 index 000000000..dbb877b93 --- /dev/null +++ b/src/lock.cc @@ -0,0 +1,61 @@ +#include "lock.h" + +UVLockHandle::UVLockHandle() +{ + uv_rwlock_init(&rw_lock); + uv_mutex_init(&mutex); +} + +UVLockHandle::~UVLockHandle() +{ + uv_rwlock_destroy(&rw_lock); + uv_mutex_destroy(&mutex); +} + +UVLocker::UVLocker(UVLockHandle &rwlock, LockerType t) : _type{t} +{ + handle = &rwlock; + + switch (t) + { + case rd: + uv_rwlock_rdlock(&handle->rw_lock); + break; + + case wr: + uv_rwlock_wrlock(&handle->rw_lock); + break; + + case mutex: + uv_mutex_lock(&handle->mutex); + break; + } +} + +UVLocker::~UVLocker() +{ + clean(); +} + +void UVLocker::clean() +{ + if (handle == nullptr) + return; + + switch (_type) + { + case rd: + uv_rwlock_rdunlock(&handle->rw_lock); + break; + + case wr: + uv_rwlock_wrunlock(&handle->rw_lock); + break; + + case mutex: + uv_mutex_unlock(&handle->mutex); + break; + } + + handle = nullptr; +} \ No newline at end of file diff --git a/src/lock.h b/src/lock.h new file mode 100644 index 000000000..7b973129e --- /dev/null +++ b/src/lock.h @@ -0,0 +1,34 @@ +#include "uv.h" + +class UVLockHandle +{ +public: + uv_rwlock_t rw_lock; + uv_mutex_t mutex; + UVLockHandle(); + ~UVLockHandle(); +}; + +/** + * [RAII] Promise to unlock when there are exception throw + */ +class UVLocker +{ + +public: + enum LockerType + { + rd = 0, + wr, + mutex + }; + + UVLocker(UVLockHandle &, LockerType); + ~UVLocker(); + + void clean(); + +private: + UVLockHandle *handle; + LockerType _type; +}; \ No newline at end of file diff --git a/test/worker.test.js b/test/worker.test.js index 73e0b0d5e..2610c6325 100644 --- a/test/worker.test.js +++ b/test/worker.test.js @@ -64,7 +64,7 @@ describe("worker:Canvas", () => { ); pool.run( { - path: resolve(__dirname, "../examples/pfennigFont/PfennigItalic.sfd"), + path: resolve(__dirname, "../examples/pfennigFont/PfennigItalic.ttf"), fontFamily: "pfenning_italic", }, { name: "registerFont" }