diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 3c92ea1c8..31b7497bc 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node: [10, 12, 14, 16] + node: [10, 12, 14, 16, 18] steps: - uses: actions/setup-node@v3 with: @@ -33,7 +33,7 @@ jobs: runs-on: windows-2019 strategy: matrix: - node: [10, 12, 14, 16] + node: [10, 12, 14, 16, 18] steps: - uses: actions/setup-node@v3 with: @@ -57,7 +57,7 @@ jobs: runs-on: macos-latest strategy: matrix: - node: [10, 12, 14, 16] + node: [10, 12, 14, 16, 18] steps: - uses: actions/setup-node@v3 with: diff --git a/.github/workflows/prebuild.yaml b/.github/workflows/prebuild.yaml index b10cc1522..a112eef87 100644 --- a/.github/workflows/prebuild.yaml +++ b/.github/workflows/prebuild.yaml @@ -24,7 +24,7 @@ jobs: Linux: strategy: matrix: - node: [8, 9, 10, 11, 12, 13, 14] + node: [8, 9, 10, 11, 12, 13, 14, 16, 18] canvas_tag: [] # e.g. "v2.6.1" name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, Linux runs-on: ubuntu-latest @@ -97,7 +97,7 @@ jobs: macOS: strategy: matrix: - node: [8, 9, 10, 11, 12, 13, 14] + node: [8, 9, 10, 11, 12, 13, 14, 16, 18] canvas_tag: [] # e.g. "v2.6.1" name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, macOS runs-on: macos-latest @@ -163,7 +163,7 @@ jobs: Win: strategy: matrix: - node: [8, 9, 10, 11, 12, 13, 14] + node: [8, 9, 10, 11, 12, 13, 14, 16, 18] canvas_tag: [] # e.g. "v2.6.1" name: ${{ matrix.canvas_tag}}, Node.js ${{ matrix.node }}, Windows runs-on: windows-latest diff --git a/CHANGELOG.md b/CHANGELOG.md index 09678e346..a666d5a23 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,14 @@ project adheres to [Semantic Versioning](http://semver.org/). ### Fixed * `textBaseline` and `textAlign` were not saved/restored by `save()`/`restore()`. ([#1936](https://github.com/Automattic/node-canvas/issues/2029)) +2.10.2 +================== +### Fixed +* Fix `Assertion failed: (object->InternalFieldCount() > 0), function Unwrap, file nan_object_wrap.h, line 32.` ([#2025](https://github.com/Automattic/node-canvas/issues/2025)) +### Changed +* Update nan to v2.17.0 to ensure Node.js v18+ support. +* Implement valid `this` checks in all `SetAccessor` methods. + 2.10.1 ================== ### Fixed diff --git a/package.json b/package.json index 034783003..cd6754ea4 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "types": "types/index.d.ts", "dependencies": { "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.15.0", + "nan": "^2.17.0", "simple-get": "^3.0.3" }, "devDependencies": { diff --git a/src/Canvas.cc b/src/Canvas.cc index 3e339f033..a7318ca82 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -64,10 +64,10 @@ Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { #ifdef HAVE_JPEG Nan::SetPrototypeMethod(ctor, "streamJPEGSync", StreamJPEGSync); #endif - SetProtoAccessor(proto, Nan::New("type").ToLocalChecked(), GetType, NULL, ctor); - SetProtoAccessor(proto, Nan::New("stride").ToLocalChecked(), GetStride, NULL, ctor); - SetProtoAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth, ctor); - SetProtoAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight, ctor); + Nan::SetAccessor(proto, Nan::New("type").ToLocalChecked(), GetType); + Nan::SetAccessor(proto, Nan::New("stride").ToLocalChecked(), GetStride); + Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth); + Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight); Nan::SetTemplate(proto, "PNG_NO_FILTERS", Nan::New(PNG_NO_FILTERS)); Nan::SetTemplate(proto, "PNG_FILTER_NONE", Nan::New(PNG_FILTER_NONE)); @@ -144,6 +144,10 @@ NAN_METHOD(Canvas::New) { */ NAN_GETTER(Canvas::GetType) { + if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Canvas.GetType called on incompatible receiver"); + return; + } Canvas *canvas = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(canvas->backend()->getName()).ToLocalChecked()); } @@ -152,6 +156,10 @@ NAN_GETTER(Canvas::GetType) { * Get stride. */ NAN_GETTER(Canvas::GetStride) { + if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Canvas.GetStride called on incompatible receiver"); + return; + } Canvas *canvas = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(canvas->stride())); } @@ -161,6 +169,10 @@ NAN_GETTER(Canvas::GetStride) { */ NAN_GETTER(Canvas::GetWidth) { + if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Canvas.GetWidth called on incompatible receiver"); + return; + } Canvas *canvas = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(canvas->getWidth())); } @@ -170,6 +182,10 @@ NAN_GETTER(Canvas::GetWidth) { */ NAN_SETTER(Canvas::SetWidth) { + if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Canvas.SetWidth called on incompatible receiver"); + return; + } if (value->IsNumber()) { Canvas *canvas = Nan::ObjectWrap::Unwrap(info.This()); canvas->backend()->setWidth(Nan::To(value).FromMaybe(0)); @@ -182,6 +198,10 @@ NAN_SETTER(Canvas::SetWidth) { */ NAN_GETTER(Canvas::GetHeight) { + if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Canvas.GetHeight called on incompatible receiver"); + return; + } Canvas *canvas = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(canvas->getHeight())); } @@ -191,6 +211,10 @@ NAN_GETTER(Canvas::GetHeight) { */ NAN_SETTER(Canvas::SetHeight) { + if (!Canvas::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Canvas.SetHeight called on incompatible receiver"); + return; + } if (value->IsNumber()) { Canvas *canvas = Nan::ObjectWrap::Unwrap(info.This()); canvas->backend()->setHeight(Nan::To(value).FromMaybe(0)); @@ -773,13 +797,13 @@ NAN_METHOD(Canvas::RegisterFont) { NAN_METHOD(Canvas::DeregisterAllFonts) { // Unload all fonts from pango to free up memory bool success = true; - + std::for_each(font_face_list.begin(), 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(); if (!success) Nan::ThrowError("Could not deregister one or more fonts"); } diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 5e37ea257..667e1cf93 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -129,29 +129,29 @@ Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { Nan::SetPrototypeMethod(ctor, "createPattern", CreatePattern); Nan::SetPrototypeMethod(ctor, "createLinearGradient", CreateLinearGradient); Nan::SetPrototypeMethod(ctor, "createRadialGradient", CreateRadialGradient); - SetProtoAccessor(proto, Nan::New("pixelFormat").ToLocalChecked(), GetFormat, NULL, ctor); - SetProtoAccessor(proto, Nan::New("patternQuality").ToLocalChecked(), GetPatternQuality, SetPatternQuality, ctor); - SetProtoAccessor(proto, Nan::New("imageSmoothingEnabled").ToLocalChecked(), GetImageSmoothingEnabled, SetImageSmoothingEnabled, ctor); - SetProtoAccessor(proto, Nan::New("globalCompositeOperation").ToLocalChecked(), GetGlobalCompositeOperation, SetGlobalCompositeOperation, ctor); - SetProtoAccessor(proto, Nan::New("globalAlpha").ToLocalChecked(), GetGlobalAlpha, SetGlobalAlpha, ctor); - SetProtoAccessor(proto, Nan::New("shadowColor").ToLocalChecked(), GetShadowColor, SetShadowColor, ctor); - SetProtoAccessor(proto, Nan::New("miterLimit").ToLocalChecked(), GetMiterLimit, SetMiterLimit, ctor); - SetProtoAccessor(proto, Nan::New("lineWidth").ToLocalChecked(), GetLineWidth, SetLineWidth, ctor); - SetProtoAccessor(proto, Nan::New("lineCap").ToLocalChecked(), GetLineCap, SetLineCap, ctor); - SetProtoAccessor(proto, Nan::New("lineJoin").ToLocalChecked(), GetLineJoin, SetLineJoin, ctor); - SetProtoAccessor(proto, Nan::New("lineDashOffset").ToLocalChecked(), GetLineDashOffset, SetLineDashOffset, ctor); - SetProtoAccessor(proto, Nan::New("shadowOffsetX").ToLocalChecked(), GetShadowOffsetX, SetShadowOffsetX, ctor); - SetProtoAccessor(proto, Nan::New("shadowOffsetY").ToLocalChecked(), GetShadowOffsetY, SetShadowOffsetY, ctor); - SetProtoAccessor(proto, Nan::New("shadowBlur").ToLocalChecked(), GetShadowBlur, SetShadowBlur, ctor); - SetProtoAccessor(proto, Nan::New("antialias").ToLocalChecked(), GetAntiAlias, SetAntiAlias, ctor); - SetProtoAccessor(proto, Nan::New("textDrawingMode").ToLocalChecked(), GetTextDrawingMode, SetTextDrawingMode, ctor); - SetProtoAccessor(proto, Nan::New("quality").ToLocalChecked(), GetQuality, SetQuality, ctor); - SetProtoAccessor(proto, Nan::New("currentTransform").ToLocalChecked(), GetCurrentTransform, SetCurrentTransform, ctor); - SetProtoAccessor(proto, Nan::New("fillStyle").ToLocalChecked(), GetFillStyle, SetFillStyle, ctor); - SetProtoAccessor(proto, Nan::New("strokeStyle").ToLocalChecked(), GetStrokeStyle, SetStrokeStyle, ctor); - SetProtoAccessor(proto, Nan::New("font").ToLocalChecked(), GetFont, SetFont, ctor); - SetProtoAccessor(proto, Nan::New("textBaseline").ToLocalChecked(), GetTextBaseline, SetTextBaseline, ctor); - SetProtoAccessor(proto, Nan::New("textAlign").ToLocalChecked(), GetTextAlign, SetTextAlign, ctor); + Nan::SetAccessor(proto, Nan::New("pixelFormat").ToLocalChecked(), GetFormat); + Nan::SetAccessor(proto, Nan::New("patternQuality").ToLocalChecked(), GetPatternQuality, SetPatternQuality); + Nan::SetAccessor(proto, Nan::New("imageSmoothingEnabled").ToLocalChecked(), GetImageSmoothingEnabled, SetImageSmoothingEnabled); + Nan::SetAccessor(proto, Nan::New("globalCompositeOperation").ToLocalChecked(), GetGlobalCompositeOperation, SetGlobalCompositeOperation); + Nan::SetAccessor(proto, Nan::New("globalAlpha").ToLocalChecked(), GetGlobalAlpha, SetGlobalAlpha); + Nan::SetAccessor(proto, Nan::New("shadowColor").ToLocalChecked(), GetShadowColor, SetShadowColor); + Nan::SetAccessor(proto, Nan::New("miterLimit").ToLocalChecked(), GetMiterLimit, SetMiterLimit); + Nan::SetAccessor(proto, Nan::New("lineWidth").ToLocalChecked(), GetLineWidth, SetLineWidth); + Nan::SetAccessor(proto, Nan::New("lineCap").ToLocalChecked(), GetLineCap, SetLineCap); + Nan::SetAccessor(proto, Nan::New("lineJoin").ToLocalChecked(), GetLineJoin, SetLineJoin); + Nan::SetAccessor(proto, Nan::New("lineDashOffset").ToLocalChecked(), GetLineDashOffset, SetLineDashOffset); + Nan::SetAccessor(proto, Nan::New("shadowOffsetX").ToLocalChecked(), GetShadowOffsetX, SetShadowOffsetX); + Nan::SetAccessor(proto, Nan::New("shadowOffsetY").ToLocalChecked(), GetShadowOffsetY, SetShadowOffsetY); + Nan::SetAccessor(proto, Nan::New("shadowBlur").ToLocalChecked(), GetShadowBlur, SetShadowBlur); + Nan::SetAccessor(proto, Nan::New("antialias").ToLocalChecked(), GetAntiAlias, SetAntiAlias); + Nan::SetAccessor(proto, Nan::New("textDrawingMode").ToLocalChecked(), GetTextDrawingMode, SetTextDrawingMode); + Nan::SetAccessor(proto, Nan::New("quality").ToLocalChecked(), GetQuality, SetQuality); + Nan::SetAccessor(proto, Nan::New("currentTransform").ToLocalChecked(), GetCurrentTransform, SetCurrentTransform); + Nan::SetAccessor(proto, Nan::New("fillStyle").ToLocalChecked(), GetFillStyle, SetFillStyle); + Nan::SetAccessor(proto, Nan::New("strokeStyle").ToLocalChecked(), GetStrokeStyle, SetStrokeStyle); + Nan::SetAccessor(proto, Nan::New("font").ToLocalChecked(), GetFont, SetFont); + Nan::SetAccessor(proto, Nan::New("textBaseline").ToLocalChecked(), GetTextBaseline, SetTextBaseline); + Nan::SetAccessor(proto, Nan::New("textAlign").ToLocalChecked(), GetTextAlign, SetTextAlign); Local ctx = Nan::GetCurrentContext(); Nan::Set(target, Nan::New("CanvasRenderingContext2d").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); Nan::Set(target, Nan::New("CanvasRenderingContext2dInit").ToLocalChecked(), Nan::New(SaveExternalModules)); @@ -713,6 +713,10 @@ NAN_METHOD(Context2d::SaveExternalModules) { */ NAN_GETTER(Context2d::GetFormat) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetFormat called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); std::string pixelFormatString; switch (context->canvas()->backend()->getFormat()) { @@ -1392,6 +1396,10 @@ NAN_METHOD(Context2d::DrawImage) { */ NAN_GETTER(Context2d::GetGlobalAlpha) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetGlobalAlpha called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(context->state->globalAlpha)); } @@ -1401,6 +1409,10 @@ NAN_GETTER(Context2d::GetGlobalAlpha) { */ NAN_SETTER(Context2d::SetGlobalAlpha) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetGlobalAlpha called on incompatible receiver"); + return; + } double n = Nan::To(value).FromMaybe(0); if (n >= 0 && n <= 1) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); @@ -1413,6 +1425,10 @@ NAN_SETTER(Context2d::SetGlobalAlpha) { */ NAN_GETTER(Context2d::GetGlobalCompositeOperation) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetGlobalCompositeOperation called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_t *ctx = context->context(); @@ -1463,6 +1479,10 @@ NAN_GETTER(Context2d::GetGlobalCompositeOperation) { */ NAN_SETTER(Context2d::SetPatternQuality) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetPatternQuality called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Nan::Utf8String quality(Nan::To(value).ToLocalChecked()); if (0 == strcmp("fast", *quality)) { @@ -1483,6 +1503,10 @@ NAN_SETTER(Context2d::SetPatternQuality) { */ NAN_GETTER(Context2d::GetPatternQuality) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetPatternQuality called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char *quality; switch (context->state->patternQuality) { @@ -1500,6 +1524,10 @@ NAN_GETTER(Context2d::GetPatternQuality) { */ NAN_SETTER(Context2d::SetImageSmoothingEnabled) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetImageSmoothingEnabled called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); context->state->imageSmoothingEnabled = Nan::To(value).FromMaybe(false); } @@ -1509,6 +1537,10 @@ NAN_SETTER(Context2d::SetImageSmoothingEnabled) { */ NAN_GETTER(Context2d::GetImageSmoothingEnabled) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetImageSmoothingEnabled called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(context->state->imageSmoothingEnabled)); } @@ -1518,6 +1550,10 @@ NAN_GETTER(Context2d::GetImageSmoothingEnabled) { */ NAN_SETTER(Context2d::SetGlobalCompositeOperation) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetGlobalCompositeOperation called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_t *ctx = context->context(); Nan::Utf8String opStr(Nan::To(value).ToLocalChecked()); // Unlike CSS colors, this *is* case-sensitive @@ -1565,6 +1601,10 @@ NAN_SETTER(Context2d::SetGlobalCompositeOperation) { */ NAN_GETTER(Context2d::GetShadowOffsetX) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetShadowOffsetX called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(context->state->shadowOffsetX)); } @@ -1574,6 +1614,10 @@ NAN_GETTER(Context2d::GetShadowOffsetX) { */ NAN_SETTER(Context2d::SetShadowOffsetX) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetShadowOffsetX called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); context->state->shadowOffsetX = Nan::To(value).FromMaybe(0); } @@ -1583,6 +1627,10 @@ NAN_SETTER(Context2d::SetShadowOffsetX) { */ NAN_GETTER(Context2d::GetShadowOffsetY) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetShadowOffsetY called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(context->state->shadowOffsetY)); } @@ -1592,6 +1640,10 @@ NAN_GETTER(Context2d::GetShadowOffsetY) { */ NAN_SETTER(Context2d::SetShadowOffsetY) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetShadowOffsetY called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); context->state->shadowOffsetY = Nan::To(value).FromMaybe(0); } @@ -1601,6 +1653,10 @@ NAN_SETTER(Context2d::SetShadowOffsetY) { */ NAN_GETTER(Context2d::GetShadowBlur) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetShadowBlur called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(context->state->shadowBlur)); } @@ -1610,6 +1666,10 @@ NAN_GETTER(Context2d::GetShadowBlur) { */ NAN_SETTER(Context2d::SetShadowBlur) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetShadowBlur called on incompatible receiver"); + return; + } int n = Nan::To(value).FromMaybe(0); if (n >= 0) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); @@ -1622,6 +1682,10 @@ NAN_SETTER(Context2d::SetShadowBlur) { */ NAN_GETTER(Context2d::GetAntiAlias) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetAntiAlias called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char *aa; switch (cairo_get_antialias(context->context())) { @@ -1638,6 +1702,10 @@ NAN_GETTER(Context2d::GetAntiAlias) { */ NAN_SETTER(Context2d::SetAntiAlias) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetAntiAlias called on incompatible receiver"); + return; + } Nan::Utf8String str(Nan::To(value).ToLocalChecked()); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_t *ctx = context->context(); @@ -1661,6 +1729,10 @@ NAN_SETTER(Context2d::SetAntiAlias) { */ NAN_GETTER(Context2d::GetTextDrawingMode) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetTextDrawingMode called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char *mode; if (context->state->textDrawingMode == TEXT_DRAW_PATHS) { @@ -1678,6 +1750,10 @@ NAN_GETTER(Context2d::GetTextDrawingMode) { */ NAN_SETTER(Context2d::SetTextDrawingMode) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetTextDrawingMode called on incompatible receiver"); + return; + } Nan::Utf8String str(Nan::To(value).ToLocalChecked()); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); if (0 == strcmp("path", *str)) { @@ -1692,6 +1768,10 @@ NAN_SETTER(Context2d::SetTextDrawingMode) { */ NAN_GETTER(Context2d::GetQuality) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetQuality called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char *filter; switch (cairo_pattern_get_filter(cairo_get_source(context->context()))) { @@ -1709,6 +1789,10 @@ NAN_GETTER(Context2d::GetQuality) { */ NAN_SETTER(Context2d::SetQuality) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetQuality called on incompatible receiver"); + return; + } Nan::Utf8String str(Nan::To(value).ToLocalChecked()); Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_filter_t filter; @@ -1771,6 +1855,10 @@ void parse_matrix_from_object(cairo_matrix_t &matrix, Local mat) { */ NAN_GETTER(Context2d::GetCurrentTransform) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetCurrentTransform called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Local instance = get_current_transform(context); @@ -1782,6 +1870,10 @@ NAN_GETTER(Context2d::GetCurrentTransform) { */ NAN_SETTER(Context2d::SetCurrentTransform) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetCurrentTransform called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Local ctx = Nan::GetCurrentContext(); Local mat = Nan::To(value).ToLocalChecked(); @@ -1803,6 +1895,10 @@ NAN_SETTER(Context2d::SetCurrentTransform) { */ NAN_GETTER(Context2d::GetFillStyle) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetFillStyle called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Isolate *iso = Isolate::GetCurrent(); Local style; @@ -1820,6 +1916,10 @@ NAN_GETTER(Context2d::GetFillStyle) { */ NAN_SETTER(Context2d::SetFillStyle) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetFillStyle called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); if (value->IsString()) { @@ -1847,6 +1947,10 @@ NAN_SETTER(Context2d::SetFillStyle) { */ NAN_GETTER(Context2d::GetStrokeStyle) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetStrokeStyle called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Local style; @@ -1863,6 +1967,10 @@ NAN_GETTER(Context2d::GetStrokeStyle) { */ NAN_SETTER(Context2d::SetStrokeStyle) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetStrokeStyle called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); if (value->IsString()) { @@ -1890,6 +1998,10 @@ NAN_SETTER(Context2d::SetStrokeStyle) { */ NAN_GETTER(Context2d::GetMiterLimit) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetMiterLimit called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(cairo_get_miter_limit(context->context()))); } @@ -1899,6 +2011,10 @@ NAN_GETTER(Context2d::GetMiterLimit) { */ NAN_SETTER(Context2d::SetMiterLimit) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetMiterLimit called on incompatible receiver"); + return; + } double n = Nan::To(value).FromMaybe(0); if (n > 0) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); @@ -1911,6 +2027,10 @@ NAN_SETTER(Context2d::SetMiterLimit) { */ NAN_GETTER(Context2d::GetLineWidth) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetLineWidth called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(cairo_get_line_width(context->context()))); } @@ -1920,6 +2040,10 @@ NAN_GETTER(Context2d::GetLineWidth) { */ NAN_SETTER(Context2d::SetLineWidth) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetLineWidth called on incompatible receiver"); + return; + } double n = Nan::To(value).FromMaybe(0); if (n > 0 && n != std::numeric_limits::infinity()) { Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); @@ -1932,6 +2056,10 @@ NAN_SETTER(Context2d::SetLineWidth) { */ NAN_GETTER(Context2d::GetLineJoin) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetLineJoin called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char *join; switch (cairo_get_line_join(context->context())) { @@ -1947,6 +2075,10 @@ NAN_GETTER(Context2d::GetLineJoin) { */ NAN_SETTER(Context2d::SetLineJoin) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetLineJoin called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_t *ctx = context->context(); Nan::Utf8String type(Nan::To(value).ToLocalChecked()); @@ -1964,6 +2096,10 @@ NAN_SETTER(Context2d::SetLineJoin) { */ NAN_GETTER(Context2d::GetLineCap) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetLineCap called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char *cap; switch (cairo_get_line_cap(context->context())) { @@ -1979,6 +2115,10 @@ NAN_GETTER(Context2d::GetLineCap) { */ NAN_SETTER(Context2d::SetLineCap) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetLineCap called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_t *ctx = context->context(); Nan::Utf8String type(Nan::To(value).ToLocalChecked()); @@ -2013,6 +2153,10 @@ NAN_METHOD(Context2d::IsPointInPath) { */ NAN_SETTER(Context2d::SetShadowColor) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetShadowColor called on incompatible receiver"); + return; + } short ok; Nan::Utf8String str(Nan::To(value).ToLocalChecked()); uint32_t rgba = rgba_from_string(*str, &ok); @@ -2027,6 +2171,10 @@ NAN_SETTER(Context2d::SetShadowColor) { */ NAN_GETTER(Context2d::GetShadowColor) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetShadowColor called on incompatible receiver"); + return; + } char buf[64]; Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); rgba_to_string(context->state->shadow, buf, sizeof(buf)); @@ -2501,6 +2649,10 @@ NAN_METHOD(Context2d::MoveTo) { */ NAN_GETTER(Context2d::GetFont) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetFont called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); Isolate *iso = Isolate::GetCurrent(); Local font; @@ -2523,6 +2675,10 @@ NAN_GETTER(Context2d::GetFont) { */ NAN_SETTER(Context2d::SetFont) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetFont called on incompatible receiver"); + return; + } if (!value->IsString()) return; Isolate *iso = Isolate::GetCurrent(); @@ -2580,6 +2736,10 @@ NAN_SETTER(Context2d::SetFont) { */ NAN_GETTER(Context2d::GetTextBaseline) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetTextBaseline called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char* baseline; switch (context->state->textBaseline) { @@ -2599,6 +2759,10 @@ NAN_GETTER(Context2d::GetTextBaseline) { */ NAN_SETTER(Context2d::SetTextBaseline) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetTextBaseline called on incompatible receiver"); + return; + } if (!value->IsString()) return; Nan::Utf8String opStr(Nan::To(value).ToLocalChecked()); @@ -2622,6 +2786,10 @@ NAN_SETTER(Context2d::SetTextBaseline) { */ NAN_GETTER(Context2d::GetTextAlign) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetTextAlign called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); const char* align; switch (context->state->textAlignment) { @@ -2641,6 +2809,10 @@ NAN_GETTER(Context2d::GetTextAlign) { */ NAN_SETTER(Context2d::SetTextAlign) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetTextAlign called on incompatible receiver"); + return; + } if (!value->IsString()) return; Nan::Utf8String opStr(Nan::To(value).ToLocalChecked()); @@ -2803,6 +2975,10 @@ NAN_METHOD(Context2d::GetLineDash) { * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash */ NAN_SETTER(Context2d::SetLineDashOffset) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.SetLineDashOffset called on incompatible receiver"); + return; + } double offset = Nan::To(value).FromMaybe(0); if (!std::isfinite(offset)) return; @@ -2820,6 +2996,10 @@ NAN_SETTER(Context2d::SetLineDashOffset) { * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash */ NAN_GETTER(Context2d::GetLineDashOffset) { + if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Context2d.GetLineDashOffset called on incompatible receiver"); + return; + } Context2d *context = Nan::ObjectWrap::Unwrap(info.This()); cairo_t *ctx = context->context(); double offset; diff --git a/src/Image.cc b/src/Image.cc index 103b65ee7..35ee7947a 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -8,7 +8,6 @@ #include #include #include -#include "Util.h" /* Cairo limit: * https://lists.cairographics.org/archives/cairo/2010-December/021422.html @@ -60,12 +59,12 @@ Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Prototype Local proto = ctor->PrototypeTemplate(); - SetProtoAccessor(proto, Nan::New("complete").ToLocalChecked(), GetComplete, NULL, ctor); - SetProtoAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth, ctor); - SetProtoAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight, ctor); - SetProtoAccessor(proto, Nan::New("naturalWidth").ToLocalChecked(), GetNaturalWidth, NULL, ctor); - SetProtoAccessor(proto, Nan::New("naturalHeight").ToLocalChecked(), GetNaturalHeight, NULL, ctor); - SetProtoAccessor(proto, Nan::New("dataMode").ToLocalChecked(), GetDataMode, SetDataMode, ctor); + Nan::SetAccessor(proto, Nan::New("complete").ToLocalChecked(), GetComplete); + Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth); + Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight); + Nan::SetAccessor(proto, Nan::New("naturalWidth").ToLocalChecked(), GetNaturalWidth); + Nan::SetAccessor(proto, Nan::New("naturalHeight").ToLocalChecked(), GetNaturalHeight); + Nan::SetAccessor(proto, Nan::New("dataMode").ToLocalChecked(), GetDataMode, SetDataMode); ctor->Set(Nan::New("MODE_IMAGE").ToLocalChecked(), Nan::New(DATA_IMAGE)); ctor->Set(Nan::New("MODE_MIME").ToLocalChecked(), Nan::New(DATA_MIME)); @@ -108,6 +107,10 @@ NAN_GETTER(Image::GetComplete) { */ NAN_GETTER(Image::GetDataMode) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.GetDataMode called on incompatible receiver"); + return; + } Image *img = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(img->data_mode)); } @@ -117,6 +120,10 @@ NAN_GETTER(Image::GetDataMode) { */ NAN_SETTER(Image::SetDataMode) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.SetDataMode called on incompatible receiver"); + return; + } if (value->IsNumber()) { Image *img = Nan::ObjectWrap::Unwrap(info.This()); int mode = Nan::To(value).FromMaybe(0); @@ -129,6 +136,10 @@ NAN_SETTER(Image::SetDataMode) { */ NAN_GETTER(Image::GetNaturalWidth) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.GetNaturalWidth called on incompatible receiver"); + return; + } Image *img = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(img->naturalWidth)); } @@ -138,6 +149,10 @@ NAN_GETTER(Image::GetNaturalWidth) { */ NAN_GETTER(Image::GetWidth) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.GetWidth called on incompatible receiver"); + return; + } Image *img = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(img->width)); } @@ -147,6 +162,10 @@ NAN_GETTER(Image::GetWidth) { */ NAN_SETTER(Image::SetWidth) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.SetWidth called on incompatible receiver"); + return; + } if (value->IsNumber()) { Image *img = Nan::ObjectWrap::Unwrap(info.This()); img->width = Nan::To(value).FromMaybe(0); @@ -158,6 +177,10 @@ NAN_SETTER(Image::SetWidth) { */ NAN_GETTER(Image::GetNaturalHeight) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.GetNaturalHeight called on incompatible receiver"); + return; + } Image *img = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(img->naturalHeight)); } @@ -167,6 +190,10 @@ NAN_GETTER(Image::GetNaturalHeight) { */ NAN_GETTER(Image::GetHeight) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method Image.GetHeight called on incompatible receiver"); + return; + } Image *img = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(img->height)); } @@ -175,6 +202,11 @@ NAN_GETTER(Image::GetHeight) { */ NAN_SETTER(Image::SetHeight) { + if (!Image::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + // #1534 + Nan::ThrowTypeError("Method Image.SetHeight called on incompatible receiver"); + return; + } if (value->IsNumber()) { Image *img = Nan::ObjectWrap::Unwrap(info.This()); img->height = Nan::To(value).FromMaybe(0); diff --git a/src/ImageData.cc b/src/ImageData.cc index 668733d39..03da2e270 100644 --- a/src/ImageData.cc +++ b/src/ImageData.cc @@ -2,8 +2,6 @@ #include "ImageData.h" -#include "Util.h" - using namespace v8; Nan::Persistent ImageData::constructor; @@ -24,8 +22,8 @@ ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) { // Prototype Local proto = ctor->PrototypeTemplate(); - SetProtoAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, NULL, ctor); - SetProtoAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, NULL, ctor); + Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth); + Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight); Local ctx = Nan::GetCurrentContext(); Nan::Set(target, Nan::New("ImageData").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked()); } @@ -126,6 +124,10 @@ NAN_METHOD(ImageData::New) { */ NAN_GETTER(ImageData::GetWidth) { + if (!ImageData::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method ImageData.GetWidth called on incompatible receiver"); + return; + } ImageData *imageData = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(imageData->width())); } @@ -135,6 +137,10 @@ NAN_GETTER(ImageData::GetWidth) { */ NAN_GETTER(ImageData::GetHeight) { + if (!ImageData::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { + Nan::ThrowTypeError("Method ImageData.GetHeight called on incompatible receiver"); + return; + } ImageData *imageData = Nan::ObjectWrap::Unwrap(info.This()); info.GetReturnValue().Set(Nan::New(imageData->height())); } diff --git a/src/Point.h b/src/Point.h index 50c7b711c..a797dc46c 100644 --- a/src/Point.h +++ b/src/Point.h @@ -1,11 +1,17 @@ // Copyright (c) 2010 LearnBoost - #pragma once +#include + template class Point { public: T x, y; Point(T x=0, T y=0): x(x), y(y) {} Point(const Point&) = default; + Point& operator=(Point other) { + std::swap(x, other.x); + std::swap(y, other.y); + return *this; + } }; diff --git a/src/Util.h b/src/Util.h index dba6883a2..0e6d1d89c 100644 --- a/src/Util.h +++ b/src/Util.h @@ -1,32 +1,7 @@ #pragma once -#include -#include #include -// Wrapper around Nan::SetAccessor that makes it easier to change the last -// argument (signature). Getters/setters must be accessed only when there is -// actually an instance, i.e. MyClass.prototype.getter1 should not try to -// unwrap the non-existent 'this'. See #803, #847, #885, nodejs/node#15099, ... -inline void SetProtoAccessor( - v8::Local tpl, - v8::Local name, - Nan::GetterCallback getter, - Nan::SetterCallback setter, - v8::Local ctor - ) { - Nan::SetAccessor( - tpl, - name, - getter, - setter, - v8::Local(), - v8::DEFAULT, - v8::None, - v8::AccessorSignature::New(v8::Isolate::GetCurrent(), ctor) - ); -} - inline bool streq_casein(std::string& str1, std::string& str2) { return str1.size() == str2.size() && std::equal(str1.begin(), str1.end(), str2.begin(), [](char& c1, char& c2) { return c1 == c2 || std::toupper(c1) == std::toupper(c2);