@shqld/canvas 2.11.2-rc.3 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/Readme.md +86 -32
  2. package/binding.gyp +6 -7
  3. package/browser.js +0 -4
  4. package/{types/index.d.ts → index.d.ts} +34 -11
  5. package/index.js +2 -2
  6. package/lib/DOMMatrix.js +58 -0
  7. package/lib/bindings.js +33 -0
  8. package/lib/context2d.js +0 -3
  9. package/lib/image.js +16 -15
  10. package/lib/pattern.js +0 -2
  11. package/package.json +21 -15
  12. package/src/Backends.h +3 -4
  13. package/src/Canvas.cc +479 -418
  14. package/src/Canvas.h +68 -36
  15. package/src/CanvasError.h +14 -0
  16. package/src/CanvasGradient.cc +59 -69
  17. package/src/CanvasGradient.h +8 -10
  18. package/src/CanvasPattern.cc +65 -72
  19. package/src/CanvasPattern.h +8 -12
  20. package/src/CanvasRenderingContext2d.cc +1146 -979
  21. package/src/CanvasRenderingContext2d.h +126 -113
  22. package/src/CharData.h +233 -0
  23. package/src/FontParser.cc +605 -0
  24. package/src/FontParser.h +115 -0
  25. package/src/Image.cc +473 -188
  26. package/src/Image.h +39 -20
  27. package/src/ImageData.cc +74 -82
  28. package/src/ImageData.h +12 -13
  29. package/src/InstanceData.h +12 -0
  30. package/src/JPEGStream.h +11 -21
  31. package/src/bmp/BMPParser.cc +3 -1
  32. package/src/closure.cc +26 -0
  33. package/src/closure.h +19 -2
  34. package/src/color.cc +23 -6
  35. package/src/init.cc +38 -18
  36. package/src/register_font.cc +8 -64
  37. package/lib/parse-font.js +0 -101
  38. package/src/Backends.cc +0 -18
  39. package/src/backend/Backend.cc +0 -112
  40. package/src/backend/Backend.h +0 -69
  41. package/src/backend/ImageBackend.cc +0 -74
  42. package/src/backend/ImageBackend.h +0 -26
  43. package/src/backend/PdfBackend.cc +0 -53
  44. package/src/backend/PdfBackend.h +0 -24
  45. package/src/backend/SvgBackend.cc +0 -61
  46. package/src/backend/SvgBackend.h +0 -24
package/src/Canvas.h CHANGED
@@ -2,15 +2,28 @@
2
2
 
3
3
  #pragma once
4
4
 
5
- #include "backend/Backend.h"
5
+ struct Closure;
6
+ struct PdfSvgClosure;
7
+
8
+ #include "closure.h"
6
9
  #include <cairo.h>
7
10
  #include "dll_visibility.h"
8
- #include <nan.h>
11
+ #include <napi.h>
9
12
  #include <pango/pangocairo.h>
10
- #include <v8.h>
11
13
  #include <vector>
12
14
  #include <cstddef>
13
15
 
16
+ /*
17
+ * Canvas types.
18
+ */
19
+
20
+ typedef enum {
21
+ CANVAS_TYPE_IMAGE,
22
+ CANVAS_TYPE_PDF,
23
+ CANVAS_TYPE_SVG
24
+ } canvas_type_t;
25
+
26
+
14
27
  /*
15
28
  * FontFace describes a font file in terms of one PangoFontDescription that
16
29
  * will resolve to it and one that the user describes it as (like @font-face)
@@ -35,7 +48,6 @@ enum text_align_t : int8_t {
35
48
  TEXT_ALIGNMENT_LEFT = -1,
36
49
  TEXT_ALIGNMENT_CENTER = 0,
37
50
  TEXT_ALIGNMENT_RIGHT = 1,
38
- // Currently same as LEFT and RIGHT without RTL support:
39
51
  TEXT_ALIGNMENT_START = -2,
40
52
  TEXT_ALIGNMENT_END = 2
41
53
  };
@@ -49,48 +61,68 @@ enum canvas_draw_mode_t : uint8_t {
49
61
  * Canvas.
50
62
  */
51
63
 
52
- class Canvas: public Nan::ObjectWrap {
64
+ class Canvas : public Napi::ObjectWrap<Canvas> {
53
65
  public:
54
- static Nan::Persistent<v8::FunctionTemplate> constructor;
55
- static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
56
- static NAN_METHOD(New);
57
- static NAN_METHOD(ToBuffer);
58
- static NAN_GETTER(GetType);
59
- static NAN_GETTER(GetStride);
60
- static NAN_GETTER(GetWidth);
61
- static NAN_GETTER(GetHeight);
62
- static NAN_SETTER(SetWidth);
63
- static NAN_SETTER(SetHeight);
64
- static NAN_METHOD(StreamPNGSync);
65
- static NAN_METHOD(StreamPDFSync);
66
- static NAN_METHOD(StreamJPEGSync);
67
- static NAN_METHOD(RegisterFont);
68
- static NAN_METHOD(DeregisterAllFonts);
69
- static v8::Local<v8::Value> Error(cairo_status_t status);
70
- static void ToPngBufferAsync(uv_work_t *req);
71
- static void ToJpegBufferAsync(uv_work_t *req);
72
- static void ToBufferAsyncAfter(uv_work_t *req);
66
+ Canvas(const Napi::CallbackInfo& info);
67
+ ~Canvas();
68
+ static void Initialize(Napi::Env& env, Napi::Object& target);
69
+
70
+ Napi::Value ToBuffer(const Napi::CallbackInfo& info);
71
+ Napi::Value GetType(const Napi::CallbackInfo& info);
72
+ Napi::Value GetStride(const Napi::CallbackInfo& info);
73
+ Napi::Value GetWidth(const Napi::CallbackInfo& info);
74
+ Napi::Value GetHeight(const Napi::CallbackInfo& info);
75
+ void SetWidth(const Napi::CallbackInfo& info, const Napi::Value& value);
76
+ void SetHeight(const Napi::CallbackInfo& info, const Napi::Value& value);
77
+ void StreamPNGSync(const Napi::CallbackInfo& info);
78
+ void StreamPDFSync(const Napi::CallbackInfo& info);
79
+ void StreamJPEGSync(const Napi::CallbackInfo& info);
80
+ static void RegisterFont(const Napi::CallbackInfo& info);
81
+ static void DeregisterAllFonts(const Napi::CallbackInfo& info);
82
+ static Napi::Value ParseFont(const Napi::CallbackInfo& info);
83
+ Napi::Error CairoError(cairo_status_t status);
84
+ static void ToPngBufferAsync(Closure* closure);
85
+ static void ToJpegBufferAsync(Closure* closure);
73
86
  static PangoWeight GetWeightFromCSSString(const char *weight);
74
87
  static PangoStyle GetStyleFromCSSString(const char *style);
75
88
  static PangoFontDescription *ResolveFontDescription(const PangoFontDescription *desc);
76
89
 
77
- DLL_PUBLIC inline Backend* backend() { return _backend; }
78
- DLL_PUBLIC inline cairo_surface_t* surface(){ return backend()->getSurface(); }
90
+ inline bool isPDF() { return type == CANVAS_TYPE_PDF; }
91
+ inline bool isSVG() { return type == CANVAS_TYPE_SVG; }
92
+ inline bool isImage() { return type == CANVAS_TYPE_IMAGE; }
93
+ inline void *closure() { return _closure; }
94
+
79
95
  cairo_t* createCairoContext();
80
96
 
81
- DLL_PUBLIC inline uint8_t *data(){ return cairo_image_surface_get_data(surface()); }
82
- DLL_PUBLIC inline int stride(){ return cairo_image_surface_get_stride(surface()); }
83
- DLL_PUBLIC inline std::size_t nBytes(){
84
- return static_cast<std::size_t>(getHeight()) * stride();
97
+ DLL_PUBLIC inline uint8_t *data() { return cairo_image_surface_get_data(ensureSurface()); }
98
+ DLL_PUBLIC inline int stride() { return cairo_image_surface_get_stride(ensureSurface()); }
99
+ DLL_PUBLIC inline std::size_t nBytes() {
100
+ return static_cast<std::size_t>(height) * stride();
85
101
  }
86
102
 
87
- DLL_PUBLIC inline int getWidth() { return backend()->getWidth(); }
88
- DLL_PUBLIC inline int getHeight() { return backend()->getHeight(); }
103
+ DLL_PUBLIC inline uint16_t getWidth() { return width; }
104
+ DLL_PUBLIC inline uint16_t getHeight() { return height; }
89
105
 
90
- Canvas(Backend* backend);
91
- void resurface(v8::Local<v8::Object> canvas);
106
+ uint8_t approxBytesPerPixel();
107
+ void setFormat(cairo_format_t format);
108
+ cairo_format_t getFormat();
109
+ void resurface(Napi::Object This, uint16_t width, uint16_t height);
110
+ cairo_surface_t *ensureSurface();
111
+ void destroySurface();
112
+
113
+ Napi::Env env;
114
+ static int fontSerial;
92
115
 
93
116
  private:
94
- ~Canvas();
95
- Backend* _backend;
117
+
118
+ cairo_surface_t *_surface;
119
+ PdfSvgClosure *_closure;
120
+
121
+ Napi::FunctionReference ctor;
122
+ static std::vector<FontFace> font_face_list;
123
+
124
+ uint16_t width;
125
+ uint16_t height;
126
+ canvas_type_t type;
127
+ cairo_format_t format;
96
128
  };
package/src/CanvasError.h CHANGED
@@ -1,6 +1,7 @@
1
1
  #pragma once
2
2
 
3
3
  #include <string>
4
+ #include <napi.h>
4
5
 
5
6
  class CanvasError {
6
7
  public:
@@ -20,4 +21,17 @@ class CanvasError {
20
21
  path.clear();
21
22
  cerrno = 0;
22
23
  }
24
+ bool empty() {
25
+ return cerrno == 0 && message.empty();
26
+ }
27
+ Napi::Error toError(Napi::Env env) {
28
+ if (cerrno) {
29
+ Napi::Error err = Napi::Error::New(env, strerror(cerrno));
30
+ if (!syscall.empty()) err.Value().Set("syscall", syscall);
31
+ if (!path.empty()) err.Value().Set("path", path);
32
+ return err;
33
+ } else {
34
+ return Napi::Error::New(env, message);
35
+ }
36
+ }
23
37
  };
@@ -1,123 +1,113 @@
1
1
  // Copyright (c) 2010 LearnBoost <tj@learnboost.com>
2
2
 
3
3
  #include "CanvasGradient.h"
4
+ #include "InstanceData.h"
4
5
 
5
6
  #include "Canvas.h"
6
7
  #include "color.h"
7
8
 
8
- using namespace v8;
9
-
10
- Nan::Persistent<FunctionTemplate> Gradient::constructor;
9
+ using namespace Napi;
11
10
 
12
11
  /*
13
12
  * Initialize CanvasGradient.
14
13
  */
15
14
 
16
15
  void
17
- Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
18
- Nan::HandleScope scope;
19
-
20
- // Constructor
21
- Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Gradient::New);
22
- constructor.Reset(ctor);
23
- ctor->InstanceTemplate()->SetInternalFieldCount(1);
24
- ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked());
25
-
26
- // Prototype
27
- Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop);
28
- Local<Context> ctx = Nan::GetCurrentContext();
29
- Nan::Set(target,
30
- Nan::New("CanvasGradient").ToLocalChecked(),
31
- ctor->GetFunction(ctx).ToLocalChecked());
16
+ Gradient::Initialize(Napi::Env& env, Napi::Object& exports) {
17
+ Napi::HandleScope scope(env);
18
+ InstanceData* data = env.GetInstanceData<InstanceData>();
19
+
20
+ Napi::Function ctor = DefineClass(env, "CanvasGradient", {
21
+ InstanceMethod<&Gradient::AddColorStop>("addColorStop", napi_default_method)
22
+ });
23
+
24
+ exports.Set("CanvasGradient", ctor);
25
+ data->CanvasGradientCtor = Napi::Persistent(ctor);
32
26
  }
33
27
 
34
28
  /*
35
29
  * Initialize a new CanvasGradient.
36
30
  */
37
31
 
38
- NAN_METHOD(Gradient::New) {
39
- if (!info.IsConstructCall()) {
40
- return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
41
- }
42
-
32
+ Gradient::Gradient(const Napi::CallbackInfo& info) : Napi::ObjectWrap<Gradient>(info), env(info.Env()) {
43
33
  // Linear
44
- if (4 == info.Length()) {
45
- Gradient *grad = new Gradient(
46
- Nan::To<double>(info[0]).FromMaybe(0)
47
- , Nan::To<double>(info[1]).FromMaybe(0)
48
- , Nan::To<double>(info[2]).FromMaybe(0)
49
- , Nan::To<double>(info[3]).FromMaybe(0));
50
- grad->Wrap(info.This());
51
- info.GetReturnValue().Set(info.This());
34
+ if (
35
+ 4 == info.Length() &&
36
+ info[0].IsNumber() &&
37
+ info[1].IsNumber() &&
38
+ info[2].IsNumber() &&
39
+ info[3].IsNumber()
40
+ ) {
41
+ double x0 = info[0].As<Napi::Number>().DoubleValue();
42
+ double y0 = info[1].As<Napi::Number>().DoubleValue();
43
+ double x1 = info[2].As<Napi::Number>().DoubleValue();
44
+ double y1 = info[3].As<Napi::Number>().DoubleValue();
45
+ _pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
52
46
  return;
53
47
  }
54
48
 
55
49
  // Radial
56
- if (6 == info.Length()) {
57
- Gradient *grad = new Gradient(
58
- Nan::To<double>(info[0]).FromMaybe(0)
59
- , Nan::To<double>(info[1]).FromMaybe(0)
60
- , Nan::To<double>(info[2]).FromMaybe(0)
61
- , Nan::To<double>(info[3]).FromMaybe(0)
62
- , Nan::To<double>(info[4]).FromMaybe(0)
63
- , Nan::To<double>(info[5]).FromMaybe(0));
64
- grad->Wrap(info.This());
65
- info.GetReturnValue().Set(info.This());
50
+ if (
51
+ 6 == info.Length() &&
52
+ info[0].IsNumber() &&
53
+ info[1].IsNumber() &&
54
+ info[2].IsNumber() &&
55
+ info[3].IsNumber() &&
56
+ info[4].IsNumber() &&
57
+ info[5].IsNumber()
58
+ ) {
59
+ double x0 = info[0].As<Napi::Number>().DoubleValue();
60
+ double y0 = info[1].As<Napi::Number>().DoubleValue();
61
+ double r0 = info[2].As<Napi::Number>().DoubleValue();
62
+ double x1 = info[3].As<Napi::Number>().DoubleValue();
63
+ double y1 = info[4].As<Napi::Number>().DoubleValue();
64
+ double r1 = info[5].As<Napi::Number>().DoubleValue();
65
+ _pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1);
66
66
  return;
67
67
  }
68
68
 
69
- return Nan::ThrowTypeError("invalid arguments");
69
+ Napi::TypeError::New(env, "invalid arguments").ThrowAsJavaScriptException();
70
70
  }
71
71
 
72
72
  /*
73
73
  * Add color stop.
74
74
  */
75
75
 
76
- NAN_METHOD(Gradient::AddColorStop) {
77
- if (!info[0]->IsNumber())
78
- return Nan::ThrowTypeError("offset required");
79
- if (!info[1]->IsString())
80
- return Nan::ThrowTypeError("color string required");
76
+ void
77
+ Gradient::AddColorStop(const Napi::CallbackInfo& info) {
78
+ if (!info[0].IsNumber()) {
79
+ Napi::TypeError::New(env, "offset required").ThrowAsJavaScriptException();
80
+ return;
81
+ }
82
+
83
+ if (!info[1].IsString()) {
84
+ Napi::TypeError::New(env, "color string required").ThrowAsJavaScriptException();
85
+ return;
86
+ }
81
87
 
82
- Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(info.This());
83
88
  short ok;
84
- Nan::Utf8String str(info[1]);
85
- uint32_t rgba = rgba_from_string(*str, &ok);
89
+ std::string str = info[1].As<Napi::String>();
90
+ uint32_t rgba = rgba_from_string(str.c_str(), &ok);
86
91
 
87
92
  if (ok) {
88
93
  rgba_t color = rgba_create(rgba);
89
94
  cairo_pattern_add_color_stop_rgba(
90
- grad->pattern()
91
- , Nan::To<double>(info[0]).FromMaybe(0)
95
+ _pattern
96
+ , info[0].As<Napi::Number>().DoubleValue()
92
97
  , color.r
93
98
  , color.g
94
99
  , color.b
95
100
  , color.a);
96
101
  } else {
97
- return Nan::ThrowTypeError("parse color failed");
102
+ Napi::TypeError::New(env, "parse color failed").ThrowAsJavaScriptException();
98
103
  }
99
104
  }
100
105
 
101
- /*
102
- * Initialize linear gradient.
103
- */
104
-
105
- Gradient::Gradient(double x0, double y0, double x1, double y1) {
106
- _pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
107
- }
108
-
109
- /*
110
- * Initialize radial gradient.
111
- */
112
-
113
- Gradient::Gradient(double x0, double y0, double r0, double x1, double y1, double r1) {
114
- _pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1);
115
- }
116
106
 
117
107
  /*
118
108
  * Destroy the pattern.
119
109
  */
120
110
 
121
111
  Gradient::~Gradient() {
122
- cairo_pattern_destroy(_pattern);
112
+ if (_pattern) cairo_pattern_destroy(_pattern);
123
113
  }
@@ -2,21 +2,19 @@
2
2
 
3
3
  #pragma once
4
4
 
5
- #include <nan.h>
6
- #include <v8.h>
5
+ #include <napi.h>
7
6
  #include <cairo.h>
8
7
 
9
- class Gradient: public Nan::ObjectWrap {
8
+ class Gradient : public Napi::ObjectWrap<Gradient> {
10
9
  public:
11
- static Nan::Persistent<v8::FunctionTemplate> constructor;
12
- static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
13
- static NAN_METHOD(New);
14
- static NAN_METHOD(AddColorStop);
15
- Gradient(double x0, double y0, double x1, double y1);
16
- Gradient(double x0, double y0, double r0, double x1, double y1, double r1);
10
+ static void Initialize(Napi::Env& env, Napi::Object& target);
11
+ Gradient(const Napi::CallbackInfo& info);
12
+ void AddColorStop(const Napi::CallbackInfo& info);
17
13
  inline cairo_pattern_t *pattern(){ return _pattern; }
14
+ ~Gradient();
15
+
16
+ Napi::Env env;
18
17
 
19
18
  private:
20
- ~Gradient();
21
19
  cairo_pattern_t *_pattern;
22
20
  };
@@ -4,122 +4,115 @@
4
4
 
5
5
  #include "Canvas.h"
6
6
  #include "Image.h"
7
+ #include "InstanceData.h"
7
8
 
8
- using namespace v8;
9
+ using namespace Napi;
9
10
 
10
11
  const cairo_user_data_key_t *pattern_repeat_key;
11
12
 
12
- Nan::Persistent<FunctionTemplate> Pattern::constructor;
13
- Nan::Persistent<Function> Pattern::_DOMMatrix;
14
-
15
13
  /*
16
14
  * Initialize CanvasPattern.
17
15
  */
18
16
 
19
17
  void
20
- Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
21
- Nan::HandleScope scope;
18
+ Pattern::Initialize(Napi::Env& env, Napi::Object& exports) {
19
+ Napi::HandleScope scope(env);
20
+ InstanceData* data = env.GetInstanceData<InstanceData>();
22
21
 
23
22
  // Constructor
24
- Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Pattern::New);
25
- constructor.Reset(ctor);
26
- ctor->InstanceTemplate()->SetInternalFieldCount(1);
27
- ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
28
- Nan::SetPrototypeMethod(ctor, "setTransform", SetTransform);
23
+ Napi::Function ctor = DefineClass(env, "CanvasPattern", {
24
+ InstanceMethod<&Pattern::setTransform>("setTransform", napi_default_method)
25
+ });
29
26
 
30
27
  // Prototype
31
- Local<Context> ctx = Nan::GetCurrentContext();
32
- Nan::Set(target, Nan::New("CanvasPattern").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked());
33
- Nan::Set(target, Nan::New("CanvasPatternInit").ToLocalChecked(), Nan::New<Function>(SaveExternalModules));
34
- }
35
-
36
- /*
37
- * Save some external modules as private references.
38
- */
39
-
40
- NAN_METHOD(Pattern::SaveExternalModules) {
41
- _DOMMatrix.Reset(Nan::To<Function>(info[0]).ToLocalChecked());
28
+ exports.Set("CanvasPattern", ctor);
29
+ data->CanvasPatternCtor = Napi::Persistent(ctor);
42
30
  }
43
31
 
44
32
  /*
45
33
  * Initialize a new CanvasPattern.
46
34
  */
47
35
 
48
- NAN_METHOD(Pattern::New) {
49
- if (!info.IsConstructCall()) {
50
- return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
36
+ Pattern::Pattern(const Napi::CallbackInfo& info) : ObjectWrap<Pattern>(info), env(info.Env()) {
37
+ if (!info[0].IsObject()) {
38
+ Napi::TypeError::New(env, "Image or Canvas expected").ThrowAsJavaScriptException();
39
+ return;
51
40
  }
52
41
 
42
+ Napi::Object obj = info[0].As<Napi::Object>();
43
+ InstanceData* data = env.GetInstanceData<InstanceData>();
53
44
  cairo_surface_t *surface;
54
45
 
55
- Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
56
-
57
46
  // Image
58
- if (Nan::New(Image::constructor)->HasInstance(obj)) {
59
- Image *img = Nan::ObjectWrap::Unwrap<Image>(obj);
47
+ if (obj.InstanceOf(data->ImageCtor.Value()).UnwrapOr(false)) {
48
+ Image *img = Image::Unwrap(obj);
60
49
  if (!img->isComplete()) {
61
- return Nan::ThrowError("Image given has not completed loading");
50
+ Napi::Error::New(env, "Image given has not completed loading").ThrowAsJavaScriptException();
51
+ return;
62
52
  }
63
53
  surface = img->surface();
64
54
 
65
55
  // Canvas
66
- } else if (Nan::New(Canvas::constructor)->HasInstance(obj)) {
67
- Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
68
- surface = canvas->surface();
56
+ } else if (obj.InstanceOf(data->CanvasCtor.Value()).UnwrapOr(false)) {
57
+ Canvas *canvas = Canvas::Unwrap(obj);
58
+ surface = canvas->ensureSurface();
69
59
  // Invalid
70
60
  } else {
71
- return Nan::ThrowTypeError("Image or Canvas expected");
61
+ if (!env.IsExceptionPending()) {
62
+ Napi::TypeError::New(env, "Image or Canvas expected").ThrowAsJavaScriptException();
63
+ }
64
+ return;
72
65
  }
73
- repeat_type_t repeat = REPEAT;
74
- if (0 == strcmp("no-repeat", *Nan::Utf8String(info[1]))) {
75
- repeat = NO_REPEAT;
76
- } else if (0 == strcmp("repeat-x", *Nan::Utf8String(info[1]))) {
77
- repeat = REPEAT_X;
78
- } else if (0 == strcmp("repeat-y", *Nan::Utf8String(info[1]))) {
79
- repeat = REPEAT_Y;
66
+ _pattern = cairo_pattern_create_for_surface(surface);
67
+
68
+ if (info[1].IsString()) {
69
+ if ("no-repeat" == info[1].As<Napi::String>().Utf8Value()) {
70
+ _repeat = NO_REPEAT;
71
+ } else if ("repeat-x" == info[1].As<Napi::String>().Utf8Value()) {
72
+ _repeat = REPEAT_X;
73
+ } else if ("repeat-y" == info[1].As<Napi::String>().Utf8Value()) {
74
+ _repeat = REPEAT_Y;
75
+ }
80
76
  }
81
- Pattern *pattern = new Pattern(surface, repeat);
82
- pattern->Wrap(info.This());
83
- info.GetReturnValue().Set(info.This());
77
+
78
+ cairo_pattern_set_user_data(_pattern, pattern_repeat_key, &_repeat, NULL);
84
79
  }
85
80
 
86
81
  /*
87
82
  * Set the pattern-space to user-space transform.
88
83
  */
89
- NAN_METHOD(Pattern::SetTransform) {
90
- Pattern *pattern = Nan::ObjectWrap::Unwrap<Pattern>(info.This());
91
- Local<Context> ctx = Nan::GetCurrentContext();
92
- Local<Object> mat = Nan::To<Object>(info[0]).ToLocalChecked();
93
-
94
- #if NODE_MAJOR_VERSION >= 8
95
- if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) {
96
- return Nan::ThrowTypeError("Expected DOMMatrix");
84
+ void
85
+ Pattern::setTransform(const Napi::CallbackInfo& info) {
86
+ if (!info[0].IsObject()) {
87
+ Napi::TypeError::New(env, "Expected DOMMatrix").ThrowAsJavaScriptException();
88
+ return;
97
89
  }
98
- #endif
90
+
91
+ Napi::Object mat = info[0].As<Napi::Object>();
92
+
93
+ InstanceData* data = env.GetInstanceData<InstanceData>();
94
+ if (!mat.InstanceOf(data->DOMMatrixCtor.Value()).UnwrapOr(false)) {
95
+ if (!env.IsExceptionPending()) {
96
+ Napi::TypeError::New(env, "Expected DOMMatrix").ThrowAsJavaScriptException();
97
+ }
98
+ return;
99
+ }
100
+
101
+ Napi::Value one = Napi::Number::New(env, 1);
102
+ Napi::Value zero = Napi::Number::New(env, 0);
99
103
 
100
104
  cairo_matrix_t matrix;
101
105
  cairo_matrix_init(&matrix,
102
- Nan::To<double>(Nan::Get(mat, Nan::New("a").ToLocalChecked()).ToLocalChecked()).FromMaybe(1),
103
- Nan::To<double>(Nan::Get(mat, Nan::New("b").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
104
- Nan::To<double>(Nan::Get(mat, Nan::New("c").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
105
- Nan::To<double>(Nan::Get(mat, Nan::New("d").ToLocalChecked()).ToLocalChecked()).FromMaybe(1),
106
- Nan::To<double>(Nan::Get(mat, Nan::New("e").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
107
- Nan::To<double>(Nan::Get(mat, Nan::New("f").ToLocalChecked()).ToLocalChecked()).FromMaybe(0)
106
+ mat.Get("a").UnwrapOr(one).As<Napi::Number>().DoubleValue(),
107
+ mat.Get("b").UnwrapOr(zero).As<Napi::Number>().DoubleValue(),
108
+ mat.Get("c").UnwrapOr(zero).As<Napi::Number>().DoubleValue(),
109
+ mat.Get("d").UnwrapOr(one).As<Napi::Number>().DoubleValue(),
110
+ mat.Get("e").UnwrapOr(zero).As<Napi::Number>().DoubleValue(),
111
+ mat.Get("f").UnwrapOr(zero).As<Napi::Number>().DoubleValue()
108
112
  );
109
113
 
110
114
  cairo_matrix_invert(&matrix);
111
- cairo_pattern_set_matrix(pattern->_pattern, &matrix);
112
- }
113
-
114
-
115
- /*
116
- * Initialize pattern.
117
- */
118
-
119
- Pattern::Pattern(cairo_surface_t *surface, repeat_type_t repeat) {
120
- _pattern = cairo_pattern_create_for_surface(surface);
121
- _repeat = repeat;
122
- cairo_pattern_set_user_data(_pattern, pattern_repeat_key, &_repeat, NULL);
115
+ cairo_pattern_set_matrix(_pattern, &matrix);
123
116
  }
124
117
 
125
118
  repeat_type_t Pattern::get_repeat_type_for_cairo_pattern(cairo_pattern_t *pattern) {
@@ -132,5 +125,5 @@ repeat_type_t Pattern::get_repeat_type_for_cairo_pattern(cairo_pattern_t *patter
132
125
  */
133
126
 
134
127
  Pattern::~Pattern() {
135
- cairo_pattern_destroy(_pattern);
128
+ if (_pattern) cairo_pattern_destroy(_pattern);
136
129
  }
@@ -3,8 +3,7 @@
3
3
  #pragma once
4
4
 
5
5
  #include <cairo.h>
6
- #include <nan.h>
7
- #include <v8.h>
6
+ #include <napi.h>
8
7
 
9
8
  /*
10
9
  * Canvas types.
@@ -19,19 +18,16 @@ typedef enum {
19
18
 
20
19
  extern const cairo_user_data_key_t *pattern_repeat_key;
21
20
 
22
- class Pattern: public Nan::ObjectWrap {
21
+ class Pattern : public Napi::ObjectWrap<Pattern> {
23
22
  public:
24
- static Nan::Persistent<v8::FunctionTemplate> constructor;
25
- static Nan::Persistent<v8::Function> _DOMMatrix;
26
- static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
27
- static NAN_METHOD(New);
28
- static NAN_METHOD(SaveExternalModules);
29
- static NAN_METHOD(SetTransform);
23
+ Pattern(const Napi::CallbackInfo& info);
24
+ static void Initialize(Napi::Env& env, Napi::Object& target);
25
+ void setTransform(const Napi::CallbackInfo& info);
30
26
  static repeat_type_t get_repeat_type_for_cairo_pattern(cairo_pattern_t *pattern);
31
- Pattern(cairo_surface_t *surface, repeat_type_t repeat);
32
27
  inline cairo_pattern_t *pattern(){ return _pattern; }
33
- private:
34
28
  ~Pattern();
29
+ Napi::Env env;
30
+ private:
35
31
  cairo_pattern_t *_pattern;
36
- repeat_type_t _repeat;
32
+ repeat_type_t _repeat = REPEAT;
37
33
  };