Przeglądaj źródła

'vendorizing' canvas because it's impossible to install in cloud build. Don't know how it ever worked...

Scott Blumenthal 4 lat temu
rodzic
commit
331461caef
75 zmienionych plików z 11949 dodań i 117 usunięć
  1. 20 26
      audiogram/draw-frames.js
  2. 22 17
      audiogram/initialize-canvas.js
  3. 1 0
      docker-compose.yml
  4. 3 3
      lib/register-fonts.js
  5. 0 1
      package.json
  6. 1 1
      settings/themes.json
  7. 128 69
      test/frame-test.js
  8. 25 0
      vendor/canvas/.github/ISSUE_TEMPLATE.md
  9. 6 0
      vendor/canvas/.npmignore
  10. 23 0
      vendor/canvas/.travis.yml
  11. 634 0
      vendor/canvas/History.md
  12. 368 0
      vendor/canvas/Readme.md
  13. 151 0
      vendor/canvas/binding.gyp
  14. 329 0
      vendor/canvas/build/Makefile
  15. 1 0
      vendor/canvas/build/Release/.deps/Release/canvas-postbuild.node.d
  16. 1 0
      vendor/canvas/build/Release/.deps/Release/canvas.node.d
  17. 1 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d
  18. 1 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas.node.d
  19. 309 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d
  20. 292 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d
  21. 291 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d
  22. 298 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d
  23. 289 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d
  24. 290 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d
  25. 4 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d
  26. 317 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d
  27. 260 0
      vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/register_font.o.d
  28. BIN
      vendor/canvas/build/Release/canvas-postbuild.node
  29. BIN
      vendor/canvas/build/Release/canvas.node
  30. BIN
      vendor/canvas/build/Release/obj.target/canvas-postbuild.node
  31. BIN
      vendor/canvas/build/Release/obj.target/canvas.node
  32. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/Canvas.o
  33. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o
  34. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o
  35. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o
  36. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/Image.o
  37. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/ImageData.o
  38. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/color.o
  39. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/init.o
  40. BIN
      vendor/canvas/build/Release/obj.target/canvas/src/register_font.o
  41. 6 0
      vendor/canvas/build/binding.Makefile
  42. 42 0
      vendor/canvas/build/canvas-postbuild.target.mk
  43. 178 0
      vendor/canvas/build/canvas.target.mk
  44. 160 0
      vendor/canvas/build/config.gypi
  45. 1 0
      vendor/canvas/index.js
  46. 3 0
      vendor/canvas/lib/bindings.js
  47. 288 0
      vendor/canvas/lib/canvas.js
  48. 348 0
      vendor/canvas/lib/context2d.js
  49. 61 0
      vendor/canvas/lib/image.js
  50. 62 0
      vendor/canvas/lib/jpegstream.js
  51. 59 0
      vendor/canvas/lib/pdfstream.js
  52. 61 0
      vendor/canvas/lib/pngstream.js
  53. 124 0
      vendor/canvas/package.json
  54. 842 0
      vendor/canvas/src/Canvas.cc
  55. 111 0
      vendor/canvas/src/Canvas.h
  56. 122 0
      vendor/canvas/src/CanvasGradient.cc
  57. 28 0
      vendor/canvas/src/CanvasGradient.h
  58. 86 0
      vendor/canvas/src/CanvasPattern.cc
  59. 27 0
      vendor/canvas/src/CanvasPattern.h
  60. 2227 0
      vendor/canvas/src/CanvasRenderingContext2d.cc
  61. 164 0
      vendor/canvas/src/CanvasRenderingContext2d.h
  62. 974 0
      vendor/canvas/src/Image.cc
  63. 108 0
      vendor/canvas/src/Image.h
  64. 135 0
      vendor/canvas/src/ImageData.cc
  65. 36 0
      vendor/canvas/src/ImageData.h
  66. 146 0
      vendor/canvas/src/JPEGStream.h
  67. 227 0
      vendor/canvas/src/PNG.h
  68. 19 0
      vendor/canvas/src/Point.h
  69. 65 0
      vendor/canvas/src/closure.h
  70. 744 0
      vendor/canvas/src/color.cc
  71. 40 0
      vendor/canvas/src/color.h
  72. 76 0
      vendor/canvas/src/init.cc
  73. 247 0
      vendor/canvas/src/register_font.cc
  74. 4 0
      vendor/canvas/src/register_font.h
  75. 63 0
      vendor/canvas/util/has_lib.sh

+ 20 - 26
audiogram/draw-frames.js Wyświetl plik

@@ -1,12 +1,11 @@
1 1
 var fs = require("fs"),
2
-    path = require("path"),
3
-    Canvas = require("canvas"),
4
-    queue = require("d3").queue;
2
+  path = require("path"),
3
+  Canvas = require("../vendor/canvas"),
4
+  queue = require("d3").queue;
5 5
 
6 6
 function drawFrames(renderer, options, cb) {
7
-
8 7
   var frameQueue = queue(10),
9
-      canvases = [];
8
+    canvases = [];
10 9
 
11 10
   for (var i = 0; i < 10; i++) {
12 11
     canvases.push(new Canvas(options.width, options.height));
@@ -19,9 +18,8 @@ function drawFrames(renderer, options, cb) {
19 18
   frameQueue.awaitAll(cb);
20 19
 
21 20
   function drawFrame(frameNumber, frameCallback) {
22
-
23 21
     var canvas = canvases.pop(),
24
-        context = canvas.getContext("2d");
22
+      context = canvas.getContext("2d");
25 23
 
26 24
     renderer.drawFrame(context, {
27 25
       caption: options.caption,
@@ -31,36 +29,33 @@ function drawFrames(renderer, options, cb) {
31 29
       frame: frameNumber
32 30
     });
33 31
 
34
-    canvas.toBuffer(function(err, buf){
35
-
32
+    canvas.toBuffer(function(err, buf) {
36 33
       if (err) {
37 34
         return cb(err);
38 35
       }
39 36
 
40
-      fs.writeFile(path.join(options.frameDir, zeropad(frameNumber + 1, 6) + ".png"), buf, function(writeErr) {
41
-
42
-        if (writeErr) {
43
-          return frameCallback(writeErr);
44
-        }
45
-
46
-        if (options.tick) {
47
-          options.tick();
48
-        }
37
+      fs.writeFile(
38
+        path.join(options.frameDir, zeropad(frameNumber + 1, 6) + ".png"),
39
+        buf,
40
+        function(writeErr) {
41
+          if (writeErr) {
42
+            return frameCallback(writeErr);
43
+          }
49 44
 
50
-        canvases.push(canvas);
45
+          if (options.tick) {
46
+            options.tick();
47
+          }
51 48
 
52
-        return frameCallback(null);
53
-
54
-      });
49
+          canvases.push(canvas);
55 50
 
51
+          return frameCallback(null);
52
+        }
53
+      );
56 54
     });
57
-
58 55
   }
59
-
60 56
 }
61 57
 
62 58
 function zeropad(str, len) {
63
-
64 59
   str = str.toString();
65 60
 
66 61
   while (str.length < len) {
@@ -68,7 +63,6 @@ function zeropad(str, len) {
68 63
   }
69 64
 
70 65
   return str;
71
-
72 66
 }
73 67
 
74 68
 module.exports = drawFrames;

+ 22 - 17
audiogram/initialize-canvas.js Wyświetl plik

@@ -1,10 +1,9 @@
1 1
 var fs = require("fs"),
2
-    path = require("path"),
3
-    Canvas = require("canvas"),
4
-    getRenderer = require("../renderer/");
2
+  path = require("path"),
3
+  Canvas = require("../vendor/canvas"),
4
+  getRenderer = require("../renderer/");
5 5
 
6 6
 function initializeCanvas(theme, cb) {
7
-
8 7
   // Fonts pre-registered in bin/worker
9 8
   var renderer = getRenderer(theme);
10 9
 
@@ -13,20 +12,26 @@ function initializeCanvas(theme, cb) {
13 12
   }
14 13
 
15 14
   // Load background image from file (done separately so renderer code can work in browser too)
16
-  fs.readFile(path.join(__dirname, "..", "settings", "backgrounds", theme.backgroundImage), function(err, raw){
17
-
18
-    if (err) {
19
-      return cb(err);
15
+  fs.readFile(
16
+    path.join(
17
+      __dirname,
18
+      "..",
19
+      "settings",
20
+      "backgrounds",
21
+      theme.backgroundImage
22
+    ),
23
+    function(err, raw) {
24
+      if (err) {
25
+        return cb(err);
26
+      }
27
+
28
+      var bg = new Canvas.Image();
29
+      bg.src = raw;
30
+      renderer.backgroundImage(bg);
31
+
32
+      return cb(null, renderer);
20 33
     }
21
-
22
-    var bg = new Canvas.Image;
23
-    bg.src = raw;
24
-    renderer.backgroundImage(bg);
25
-
26
-    return cb(null, renderer);
27
-
28
-  });
29
-
34
+  );
30 35
 }
31 36
 
32 37
 module.exports = initializeCanvas;

+ 1 - 0
docker-compose.yml Wyświetl plik

@@ -8,3 +8,4 @@ services:
8 8
       - "./settings:/usr/src/app/settings/"
9 9
       - "./lib:/usr/src/app/lib/"
10 10
       - "./server:/usr/src/app/server/"
11
+      - "./vendor:/usr/src/app/vendor/"

+ 3 - 3
lib/register-fonts.js Wyświetl plik

@@ -1,10 +1,10 @@
1 1
 var fonts = require("./settings/").fonts,
2
-    _ = require("underscore"),
3
-    Canvas = require("canvas");
2
+  _ = require("underscore"),
3
+  Canvas = require("../vendor/canvas");
4 4
 
5 5
 // Register custom fonts one time
6 6
 if (Array.isArray(fonts)) {
7
-  fonts.forEach(function(font){
7
+  fonts.forEach(function(font) {
8 8
     Canvas.registerFont(font.file, _.pick(font, "family", "weight", "style"));
9 9
   });
10 10
 }

+ 0 - 1
package.json Wyświetl plik

@@ -25,7 +25,6 @@
25 25
   "dependencies": {
26 26
     "aws-sdk": "^2.2.39",
27 27
     "browserify": "^13.0.0",
28
-    "canvas": "git+https://github.com/chearon/node-canvas.git#12971f64a66b",
29 28
     "compression": "^1.6.1",
30 29
     "d3": "^4.1.1",
31 30
     "dotenv": "^2.0.0",

+ 1 - 1
settings/themes.json Wyświetl plik

@@ -74,7 +74,7 @@
74 74
     "labelText": "Dear Sugars"
75 75
   },
76 76
   "The Choice": {
77
-    "waveColor": "rgba(102, 102, 102, 0.25)",
77
+    "waveColor": "rgba(255, 255, 255, 0.50)",
78 78
     "foregroundColor": "#fff",
79 79
     "citationColor": "#fff",
80 80
     "backgroundColor": "#f4d7b9",

+ 128 - 69
test/frame-test.js Wyświetl plik

@@ -1,10 +1,10 @@
1 1
 var tape = require("tape"),
2
-    Canvas = require("canvas"),
3
-    d3 = require("d3"),
4
-    path = require("path"),
5
-    fs = require("fs"),
6
-    initializeCanvas = require("../audiogram/initialize-canvas.js"),
7
-    drawFrames = require("../audiogram/draw-frames.js");
2
+  Canvas = require("../vendor/canvas"),
3
+  d3 = require("d3"),
4
+  path = require("path"),
5
+  fs = require("fs"),
6
+  initializeCanvas = require("../audiogram/initialize-canvas.js"),
7
+  drawFrames = require("../audiogram/draw-frames.js");
8 8
 
9 9
 require("mkdirp").sync(path.join(__dirname, "tmp", "frames"));
10 10
 
@@ -12,102 +12,161 @@ var frameDir = path.join(__dirname, "tmp", "frames");
12 12
 
13 13
 var waveform = [
14 14
   [
15
-    [0, 0], [1, 1], [0, 0]
15
+    [0, 0],
16
+    [1, 1],
17
+    [0, 0]
16 18
   ],
17 19
   [
18
-    [1, 1], [0.1, 0.1], [1, 1]
20
+    [1, 1],
21
+    [0.1, 0.1],
22
+    [1, 1]
19 23
   ]
20 24
 ];
21 25
 
22 26
 function tester(options) {
23
-
24 27
   return function(test) {
25
-
26
-    initializeCanvas(options, function(err, renderer){
27
-
28
+    initializeCanvas(options, function(err, renderer) {
28 29
       test.error(err);
29 30
 
30
-      drawFrames(renderer, {
31
-        numFrames: waveform.length,
32
-        frameDir: frameDir,
33
-        width: options.width,
34
-        height: options.height,
35
-        waveform: waveform
36
-      }, function(err){
37
-        test.error(err);
38
-        checkFrame(test, options);
39
-      });
40
-
31
+      drawFrames(
32
+        renderer,
33
+        {
34
+          numFrames: waveform.length,
35
+          frameDir: frameDir,
36
+          width: options.width,
37
+          height: options.height,
38
+          waveform: waveform
39
+        },
40
+        function(err) {
41
+          test.error(err);
42
+          checkFrame(test, options);
43
+        }
44
+      );
41 45
     });
42
-
43 46
   };
44
-
45 47
 }
46 48
 
47
-tape.test("Draw frame", tester({
48
-  width: 1280,
49
-  height: 720,
50
-  backgroundColor: "#f00",
51
-  foregroundColor: "#fff",
52
-  waveTop: 340,
53
-  waveBottom: 380
54
-}));
55
-
56
-tape.test("Default colors", tester({
57
-  width: 1280,
58
-  height: 720,
59
-  waveTop: 340,
60
-  waveBottom: 380
61
-}));
62
-
63
-tape.test("Square frame", tester({
64
-  width: 720,
65
-  height: 720,
66
-  backgroundColor: "#f00",
67
-  foregroundColor: "#fff",
68
-  waveTop: 340,
69
-  waveBottom: 380
70
-}));
49
+tape.test(
50
+  "Draw frame",
51
+  tester({
52
+    width: 1280,
53
+    height: 720,
54
+    backgroundColor: "#f00",
55
+    foregroundColor: "#fff",
56
+    waveTop: 340,
57
+    waveBottom: 380
58
+  })
59
+);
60
+
61
+tape.test(
62
+  "Default colors",
63
+  tester({
64
+    width: 1280,
65
+    height: 720,
66
+    waveTop: 340,
67
+    waveBottom: 380
68
+  })
69
+);
70
+
71
+tape.test(
72
+  "Square frame",
73
+  tester({
74
+    width: 720,
75
+    height: 720,
76
+    backgroundColor: "#f00",
77
+    foregroundColor: "#fff",
78
+    waveTop: 340,
79
+    waveBottom: 380
80
+  })
81
+);
71 82
 
72 83
 function checkFrame(test, options) {
73
-
74 84
   var testCanvas = new Canvas(options.width, options.height),
75
-      context = testCanvas.getContext("2d");
85
+    context = testCanvas.getContext("2d");
76 86
 
77 87
   d3.queue()
78 88
     .defer(fs.readFile, path.join(frameDir, "000001.png"))
79 89
     .defer(fs.readFile, path.join(frameDir, "000002.png"))
80
-    .await(function(e, f1, f2){
81
-
90
+    .await(function(e, f1, f2) {
82 91
       test.error(e);
83 92
 
84
-      var img = new Canvas.Image;
93
+      var img = new Canvas.Image();
85 94
       img.src = f1;
86 95
 
87 96
       var bg = getColor(options.backgroundColor || "#fff"),
88
-          fg = getColor(options.waveColor || options.foregroundColor || "#000");
97
+        fg = getColor(options.waveColor || options.foregroundColor || "#000");
89 98
 
90 99
       context.drawImage(img, 0, 0, options.width, options.height);
91 100
       test.deepEqual(getColor(context.getImageData(0, 0, 1, 1)), bg);
92
-      test.deepEqual(getColor(context.getImageData(options.width - 1, options.height - 1, 1, 1)), bg);
93
-      test.deepEqual(getColor(context.getImageData(0, options.height / 2 - 10, 1, 1)), bg);
94
-      test.deepEqual(getColor(context.getImageData(options.width - 1, options.height / 2 + 10, 1, 1)), bg);
95
-      test.deepEqual(getColor(context.getImageData(options.width / 2, options.height / 2, 1, 1)), fg);
96
-      test.deepEqual(getColor(context.getImageData(options.width / 2, options.height / 2 - 10, 1, 1)), fg);
97
-      test.deepEqual(getColor(context.getImageData(options.width / 2, options.height / 2 + 10, 1, 1)), fg);
101
+      test.deepEqual(
102
+        getColor(
103
+          context.getImageData(options.width - 1, options.height - 1, 1, 1)
104
+        ),
105
+        bg
106
+      );
107
+      test.deepEqual(
108
+        getColor(context.getImageData(0, options.height / 2 - 10, 1, 1)),
109
+        bg
110
+      );
111
+      test.deepEqual(
112
+        getColor(
113
+          context.getImageData(options.width - 1, options.height / 2 + 10, 1, 1)
114
+        ),
115
+        bg
116
+      );
117
+      test.deepEqual(
118
+        getColor(
119
+          context.getImageData(options.width / 2, options.height / 2, 1, 1)
120
+        ),
121
+        fg
122
+      );
123
+      test.deepEqual(
124
+        getColor(
125
+          context.getImageData(options.width / 2, options.height / 2 - 10, 1, 1)
126
+        ),
127
+        fg
128
+      );
129
+      test.deepEqual(
130
+        getColor(
131
+          context.getImageData(options.width / 2, options.height / 2 + 10, 1, 1)
132
+        ),
133
+        fg
134
+      );
98 135
 
99 136
       img.src = f2;
100 137
 
101 138
       context.drawImage(img, 10, 0, options.width, options.height);
102
-      test.deepEqual(getColor(context.getImageData(options.width / 2, options.height / 2, 1, 1)), fg);
103
-      test.deepEqual(getColor(context.getImageData(options.width / 2 - 10, options.height / 2 - 10, 1, 1)), bg);
104
-      test.deepEqual(getColor(context.getImageData(options.width / 2 - 10, options.height / 2 + 10, 1, 1)), bg);
105
-
139
+      test.deepEqual(
140
+        getColor(
141
+          context.getImageData(options.width / 2, options.height / 2, 1, 1)
142
+        ),
143
+        fg
144
+      );
145
+      test.deepEqual(
146
+        getColor(
147
+          context.getImageData(
148
+            options.width / 2 - 10,
149
+            options.height / 2 - 10,
150
+            1,
151
+            1
152
+          )
153
+        ),
154
+        bg
155
+      );
156
+      test.deepEqual(
157
+        getColor(
158
+          context.getImageData(
159
+            options.width / 2 - 10,
160
+            options.height / 2 + 10,
161
+            1,
162
+            1
163
+          )
164
+        ),
165
+        bg
166
+      );
106 167
 
107 168
       test.end();
108
-
109 169
     });
110
-
111 170
 }
112 171
 
113 172
 function getColor(c) {
@@ -120,8 +179,8 @@ function getColor(c) {
120 179
 }
121 180
 
122 181
 // Cleanup
123
-tape.onFinish(function(){
124
-  require("rimraf")(path.join(__dirname, "tmp"), function(err){
182
+tape.onFinish(function() {
183
+  require("rimraf")(path.join(__dirname, "tmp"), function(err) {
125 184
     if (err) {
126 185
       throw err;
127 186
     }

+ 25 - 0
vendor/canvas/.github/ISSUE_TEMPLATE.md Wyświetl plik

@@ -0,0 +1,25 @@
1
+<!----------------------------------- STOP! ----------------------------------->
2
+<!---
3
+Having trouble installing node-canvas? Please make sure you have read
4
+the installation instructions located here before asking for help:
5
+https://github.com/Automattic/node-canvas#installation
6
+Still having problems, found a bug or want a feature? Fill out the form below.
7
+-->
8
+
9
+<!--- Provide a general summary of the issue in the Title above -->
10
+
11
+## Issue or Feature
12
+<!--- Provide info about the bug or feature. -->
13
+
14
+## Steps to Reproduce
15
+<!--- For bugs, provide a short, complete code example to reproduce the issue. -->
16
+```js
17
+var Canvas = require('canvas');
18
+var canvas = new Canvas(200, 200);
19
+var ctx = canvas.getContext('2d');
20
+// etc.
21
+```
22
+
23
+## Your Environment
24
+* Version of node-canvas (e.g. 1.4.0):
25
+* Environment (e.g. node 4.2.0 on Mac OS X 10.8):

+ 6 - 0
vendor/canvas/.npmignore Wyświetl plik

@@ -0,0 +1,6 @@
1
+testing
2
+build
3
+benchmarks
4
+examples
5
+support
6
+test

+ 23 - 0
vendor/canvas/.travis.yml Wyświetl plik

@@ -0,0 +1,23 @@
1
+language: node_js
2
+node_js:
3
+  - '6'
4
+  - '4'
5
+  - '0.12'
6
+  - '0.10'
7
+  - '0.8'
8
+addons:
9
+  apt:
10
+    sources:
11
+      - ubuntu-toolchain-r-test
12
+    packages:
13
+      - libcairo2-dev
14
+      - libjpeg8-dev
15
+      - libpango1.0-dev
16
+      - libgif-dev
17
+      - g++-4.9
18
+env:
19
+  - CXX=g++-4.9
20
+before_install:
21
+  - if [[ $TRAVIS_NODE_VERSION == 0.8 ]]; then npm install -g npm@1.4.28; fi
22
+  - npm explore npm -g -- npm install node-gyp@latest
23
+sudo: false

+ 634 - 0
vendor/canvas/History.md Wyświetl plik

@@ -0,0 +1,634 @@
1
+1.6.0 / 2016-10-16
2
+==================
3
+
4
+ * Support canvas.getBuffer('raw') (#819)
5
+
6
+1.5.0 / 2016-09-11
7
+==================
8
+
9
+ * Crude PDF stream implementation (#781)
10
+ * Update CI settings (#797)
11
+ * Reduce some of the install warnings (#794)
12
+ * Fix lineDash browser tests never finishing (#793)
13
+ * Add issue template (#791)
14
+
15
+1.4.0 / 2016-06-03
16
+==================
17
+
18
+ * Add support for evenodd fill rule (#762)
19
+
20
+1.3.17 / 2016-06-03
21
+===================
22
+
23
+ * Removing redundant duplicate calls (#769)
24
+ * Cleanup examples (#776)
25
+ * Fix CanvasRenderingContext2D class name (#777)
26
+
27
+1.3.16 / 2016-05-29
28
+===================
29
+
30
+  * Fix leak of data when streaming JPEG (#774)
31
+
32
+1.3.15 / 2016-05-09
33
+===================
34
+
35
+  * Fix segfault in putImageData (#750)
36
+
37
+1.3.14 / 2016-05-05
38
+===================
39
+
40
+  * Clamp JPEG buffer size (#739)
41
+
42
+1.3.13 / 2016-05-01
43
+===================
44
+
45
+  * Bumb NAN version (#759)
46
+
47
+1.3.12 / 2016-03-01
48
+===================
49
+
50
+  * Expose freetype version (#718)
51
+  * Require new in constructor (#717)
52
+
53
+1.3.11 / 2016-03-01
54
+===================
55
+
56
+  * Properly clamp quality in toDataURL (#728)
57
+  * Strict mode (#719)
58
+
59
+1.3.10 / 2016-02-07
60
+===================
61
+
62
+  * Fix segfault on node 0.10.x (#712)
63
+
64
+1.3.9 / 2016-01-27
65
+==================
66
+
67
+  * Allow to unbind onload/onerror callback handlers (#706)
68
+
69
+1.3.8 / 2016-01-22
70
+==================
71
+
72
+  * Cleanup build scripts and fix pangocairo detection (#701)
73
+
74
+1.3.7 / 2016-01-13
75
+==================
76
+
77
+  * Don't unbind onload/onerror callbacks after invoking them (#615)
78
+
79
+1.3.6 / 2016-01-06
80
+==================
81
+
82
+  * Allow optional arguments in `toDataURL` to be `undefined` and improve `toDataURL`'s spec compliance (#690)
83
+
84
+1.3.5 / 2015-12-07
85
+==================
86
+
87
+  * Add image/jpeg support to `toDataUrl` (#685)
88
+
89
+1.3.4 / 2015-11-21
90
+==================
91
+
92
+  * Upgrade nan to 2.1.0 (#671)
93
+
94
+1.3.3 / 2015-11-21
95
+==================
96
+
97
+  * Fix compilation on Visual Studio 2015 (#670)
98
+
99
+1.3.2 / 2015-11-18
100
+==================
101
+
102
+  * Fix incorrect Y offset and scaling for shadows (#669)
103
+
104
+1.3.1 / 2015-11-09
105
+==================
106
+
107
+  * Wrap std::min calls in paranthesis to prevent macro expansion on windows (#660)
108
+
109
+1.3.0 / 2015-10-26
110
+==================
111
+
112
+  * Expose ImageData constructor and make it more spec-compliant (#569)
113
+
114
+1.2.11 / 2015-10-20
115
+===================
116
+
117
+  * Implement blur on images (#648)
118
+
119
+1.2.10 / 2015-10-12
120
+===================
121
+
122
+  * Fix segfault in Canvas#jpegStream (#629)
123
+
124
+1.2.9 / 2015-09-14
125
+==================
126
+
127
+  * Upgrade to Nan 2.x with support for iojs 3.x and Node.js 4.x (#622)
128
+
129
+1.2.8 / 2015-08-30
130
+==================
131
+
132
+  * Clean up the tests (#612)
133
+  * Replace CanvasPixelArray with Uint8ClampedArray to be API-compliant (#604)
134
+  * Specify travis iojs versions (#611)
135
+
136
+1.2.7 / 2015-07-29
137
+==================
138
+
139
+  * Avoid future reserved keyword (#592)
140
+
141
+1.2.6 / 2015-07-29
142
+==================
143
+
144
+  * Fix the build on windows (#589)
145
+
146
+1.2.5 / 2015-07-28
147
+==================
148
+
149
+  * Another npm release, since 1.2.4 was botched (see #596)
150
+
151
+1.2.4 / 2015-07-23
152
+==================
153
+
154
+  * Point `homepage` and `repository` links to [`github.com/Automattic/node-canvas`][repo]
155
+  * Fix Travis builds and Cairo include paths (thanks, Linus Unnebäck!)
156
+
157
+1.2.3 / 2015-05-21
158
+==================
159
+
160
+  * Update TJ Holowaychuk's username in the readme
161
+  * Fix segmentation fault in `Image::loadFromBuffer` when buffer is empty
162
+  * Optimize getImageData()
163
+  * package: add "license" attribute
164
+  * package: update "nan" to v1.8.4
165
+  * package: append `.git` to "repository" URL
166
+
167
+1.2.2 / 2015-04-18
168
+==================
169
+
170
+  * Now works on io.js
171
+  * Fix 'drawImage' scaling (the dimensions of the region that gets clipped also needs to be scaled).
172
+  * Fix bug in StreamPNGSync
173
+
174
+1.2.1 / 2015-02-10
175
+==================
176
+
177
+  * Use non-cairo 1.12 API for shadow blur
178
+
179
+1.2.0 / 2015-01-31
180
+==================
181
+
182
+  * travis: drop support for node v0.6
183
+  * Merge pull request #507 from salzhrani/iojs
184
+  * io.js compatibility
185
+  * Merge pull request #505 from woodcoder/shadow-blur
186
+  * Fix issue with line width not being correct in stroked shadows.
187
+  * Add another shadow/transform test.
188
+  * Refactor setSourceRGBA to allow the context to be supplied.
189
+  * Simple image shadow (no blurring or handling current transforms) based on image's alpha channel.
190
+  * Test showing issue #133, that images don't have shadows.
191
+  * The +1 on the offset seems to match the browser's output better, but I can't work out why it would be needed (unless it's pixel alignment related).
192
+  * Make the shadow radius more accurately match the browser's, making use of sigma scale as used in SKIA: https://github.com/google/skia/blob/master/src/effects/SkBlurMask.cpp#L26.
193
+  * Create a new image surface to render blurred shadows to, this means that vector formats like PDF will now render blurs.
194
+  * Add recommended calls to flush and dirty buffer, as per http://www.cairographics.org/manual/cairo-Image-Surfaces.html#cairo-image-surface-get-data.
195
+  * Add PDF button to test page to easily generate PDF version of the test image.
196
+  * Fix to ensure shadowOffset is unaffected by the current transform.
197
+  * New test illustrating that canvas implementation doesn't translate the shadowOffset.
198
+  * Merge pull request #490 from AllYearbooks/master
199
+  * Merge pull request #501 from motiz88/hsl-color
200
+  * Code style + attribution. Also removed parseClipped() and commented out wrapInt (now wrap_int).
201
+  * Added visual tests for hsl() and hsla() color parsing.
202
+  * Fixed <number> handling in hsl/hsla color parser. parseNumber() was erroring out on numbers with long fractional parts.
203
+  * hsl/hsla color parsing + rebeccapurple hsl() and hsla() color values are now supported, with corresponding unit tests. Also added rebeccapurple (from CSS Color Level 4) to the named color list.
204
+  * float rather than int for drawImage arguments
205
+  * with_pango to true and use fontconfig to load fonts
206
+  * Merge pull request #399 from nulltask/fix/lighten
207
+  * Merge pull request #465 from espadrine/master
208
+  * Merge pull request #470 from tonylukasavage/patch-1
209
+  * Add one-liner MacPorts install to docs
210
+  * Offer SVG output.
211
+  * Readme update: node-gyp.
212
+  * Readme: fix subheading size
213
+  * Readme: remove Gemnasium badge, use SVG for npm badge
214
+  * Readme: add Travis-CI badge
215
+  * change operator lighter to lighten
216
+
217
+1.1.6 / 2014-08-01
218
+==================
219
+
220
+  * export canvas.CanvasPixelArray instead of canvas.PixelArray which is undefined
221
+  * Glib version test into giflib exists test
222
+  * Giflib 5.1
223
+  * install: use an even older version of giflib (v4.1.6)
224
+  * install: use an older version of giflib (v4.2.3)
225
+  * install: install `giflib`
226
+  * install: use more compatible sh syntax
227
+  * travis: attempt to run the ./install script before testintg
228
+  * travis: test node v0.6, v0.8, v0.10, and v0.11
229
+  * Distinguish between 'add' and 'lighter'
230
+
231
+1.1.5 / 2014-06-26
232
+==================
233
+
234
+  * Readme: remove Contributors section
235
+  * Readme: update copyright
236
+  * On Windows, copy required DLLs next to ".node" file (#442 @pandell)
237
+  * Duplicate "msvc_settings" for "Debug" configuration
238
+  * Remove unneeded #include <nan.h>
239
+  * Use float constants to prevent double->float conversion warning
240
+  * Ignore Visual C++ 2013 warnings (#441 @pandell)
241
+  * Add algorithm include to CanvasRenderingContext2d.cc for std::min (#435 @kkoopa)
242
+  * Updated NAN to 1.2.0 (#434 @kkoopa)
243
+
244
+1.1.4 / 2014-06-08
245
+==================
246
+
247
+  * Fix compile error with Visual C++
248
+  * Add support for the lineDash API
249
+  * Update NAN
250
+  * New V8 compatibility
251
+  * Correctly limit bounds in PutImageData to prevent segment fault
252
+  * Fix segfault when onload and onerror are not function
253
+  * Add support for Node 0.11.9
254
+
255
+1.1.3 / 2014-01-08
256
+==================
257
+
258
+  * Add CAIRO_FORMAT_INVALID
259
+  * Readjust the amount of allocated memory
260
+  * Fix argument index for filter parameter
261
+  * Make has_lib.sh work properly on Debian 64bit
262
+
263
+1.1.2 / 2013-10-31
264
+==================
265
+
266
+  * NAN dep upgrade, full node@<=0.11.8 compatibility
267
+  * Use node::MakeCallback() instead of v8::Function::Call()
268
+  * Improve nan location discovery
269
+  * Fix enabling gif/jpeg options on Ubuntu 13.04
270
+
271
+1.1.1 / 2013-10-09
272
+==================
273
+
274
+  * add better support for outdated versions of Cairo
275
+
276
+1.1.0 / 2013-08-01
277
+==================
278
+
279
+  * add png compression options
280
+  * add jpeg stream progressive mode option
281
+  * fix resource leaks on read errors
282
+
283
+1.0.4 / 2013-07-23
284
+==================
285
+
286
+  * 0.11.4+ compatibility using NAN
287
+  * fix typo in context2d for imageSmoothingEnabled
288
+
289
+1.0.3 / 2013-06-04
290
+==================
291
+
292
+  * add "nearest" and "bilinear" to patternQuality
293
+  * fix fread() retval check (items not bytes)
294
+  * removed unneeded private fields
295
+
296
+1.0.2 / 2013-03-22
297
+==================
298
+
299
+  * add Context2d#imageSmoothingEnabled=
300
+
301
+1.0.1 / 2013-02-25
302
+==================
303
+
304
+  * travis: test modern node versions
305
+  * change the node-gyp build to use pkg-config
306
+
307
+1.0.0 / 2013-01-16
308
+==================
309
+
310
+  * add conditional pango font support [Julian Viereck]
311
+  * add `Canvas#{png,jpeg}Stream()` alias of create* legacy methods
312
+  * add support for grayscale JPEGs
313
+  * fix: explicitly cast the after work callback function to "uv_after_work_cb"
314
+  * fix test server for express 3.x
315
+  * fix: call cairo_surface_finish in ~Canvas when pdf
316
+  * remove old 0.4.x binding support. Closes #197
317
+
318
+0.13.1 / 2012-08-20
319
+==================
320
+
321
+  * fix cases where GIF_LIB_VERSION is not defined
322
+  * fix auto-detection of optional libraries for OS X
323
+  * fix Context2d::SetFont for pango when setting normal weight/style
324
+
325
+0.13.0 / 2012-08-12
326
+==================
327
+
328
+  * add pango support [c-spencer]
329
+  * add pango / png / jpeg gyp auto-detection [c-spencer]
330
+  * add `.gifVersion` [tootallnate]
331
+  * add `.jpegVersion` [tootallnate]
332
+  * add moar gyp stuff [tootallnate]
333
+  * remove wscript
334
+  * fix `closure_destroy()` with cast for `AdjustAmountOfExternalAllocatedMemory()`
335
+
336
+0.12.1 / 2012-06-29
337
+==================
338
+
339
+  * fix jpeg malloc Image issue. Closes #160 [c-spencer]
340
+  * Improve Image mode API
341
+  * Add clearData method to handle reassignment of src, and clean up mime data memory handling.
342
+  * Improve how _data_len is managed and use to adjust memory, hide more of mime API behind cairo version conditional.
343
+  * Add optional mime-data tracking to Image.
344
+  * Refactor JPEG decoding into decodeJPEGIntoSurface
345
+
346
+0.12.0 / 2012-05-02
347
+==================
348
+
349
+  * Added `textDrawingMode` context property [c-spencer]
350
+  * Added additional TextMetrics properties [c-spencer]
351
+
352
+0.11.3 / 2012-04-25
353
+==================
354
+
355
+  * Fixed `Image` memory leak. Closes #150
356
+  * Fixed Context2d::hasShadow()
357
+
358
+0.11.2 / 2012-04-12
359
+==================
360
+
361
+  * Fixed: pdf memory leak, free closure and surface in ~Canvas
362
+
363
+0.11.1 / 2012-04-10
364
+==================
365
+
366
+  * Changed: renamed .nextPage() to .addPage()
367
+
368
+0.11.0 / 2012-04-10
369
+==================
370
+
371
+  * Added quick PDF support
372
+  * Added `Canvas#type` getter
373
+  * Added ./examples/pdf-images.js
374
+  * Added ./examples/multiple-page-pdf.js
375
+  * Added ./examples/small-pdf.js
376
+
377
+0.10.3 / 2012-02-27
378
+==================
379
+
380
+  * Fixed quadratic curve starting point for undefined path. Closes #155
381
+
382
+0.10.2 / 2012-02-06
383
+==================
384
+
385
+  * Fixed: Context2d setters with invalid values ignored
386
+  * Changed: replaced seek with `fstat()`
387
+
388
+0.10.1 / 2012-01-31
389
+==================
390
+
391
+  * Added _/opt/local/lib_ to wscript [obarthel]
392
+  * Added bounds checking to `rgba_to_string()` [obarthel]
393
+  * Fixed cleanup in JPEG Image loading [obarthel]
394
+  * Fixed missing CSS color table values [obarthel]
395
+
396
+0.10.0 / 2012-01-18
397
+==================
398
+
399
+  * Added `ctx.createPattern()` [slaskis]
400
+
401
+0.9.0 / 2012-01-13
402
+==================
403
+
404
+  * Added `createJPEGStream()` [Elijah Hamovitz]
405
+
406
+0.8.3 / 2012-01-04
407
+==================
408
+
409
+  * Added support for libjpeg62-dev or libjpeg8-dev [wwlinx]
410
+
411
+0.8.2 / 2011-12-14
412
+==================
413
+
414
+  * Fixed two memory leaks in context2d [Tharit]
415
+  * Fixed `make test-server`
416
+
417
+0.8.1 / 2011-10-31
418
+==================
419
+
420
+  * Added 0.5.x support [TooTallNate]
421
+  * Fixed `measureText().width`. Closes #126
422
+
423
+0.8.0 / 2011-10-28
424
+==================
425
+
426
+  * Added data uri support. Closes #49
427
+
428
+0.7.3 / 2011-09-14
429
+==================
430
+
431
+  * Added better lineTo() / moveTo() exception messages
432
+
433
+0.7.2 / 2011-08-30
434
+==================
435
+
436
+  * Changed: prefix some private methods with _
437
+
438
+0.7.1 / 2011-08-25
439
+==================
440
+
441
+  * Added better image format detection
442
+  * Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD
443
+
444
+0.7.0 / 2011-07-12
445
+==================
446
+
447
+  * Added GIF support [Brian McKinney]
448
+
449
+0.6.0 / 2011-06-04
450
+==================
451
+
452
+  * Added `Image#src=Buffer` support. Closes #91
453
+  * Added `devDependencies`
454
+  * Added `source-atop` test
455
+  * Added _image-src.js_ example
456
+  * Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()`
457
+  * Fixed v8 memory hint when resizing canvas [atomizer]
458
+
459
+0.5.4 / 2011-04-20
460
+==================
461
+
462
+  * Added; special case of zero-width rectangle [atomizer]
463
+  * Fixed; do not clamp arguments to integer values [atomizer]
464
+  * Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer]
465
+  * Fixed; `restorePath()`: clear current path before appending [atomizer]
466
+
467
+0.5.3 / 2011-04-11
468
+==================
469
+
470
+  * Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte]
471
+
472
+0.5.2 / 2011-04-09
473
+==================
474
+
475
+  * Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte]
476
+
477
+0.5.1 / 2011-03-16
478
+==================
479
+
480
+  * Fixed (kinda) `img.src=` error handling
481
+  * Fixed; move closure.h down for malloc ref. Closes #80
482
+
483
+0.5.0 / 2011-03-14
484
+==================
485
+
486
+  * Added several more operators (color-dodge, color-burn, difference, etc)
487
+  * Performance; no longer re-allocating `closure->data` for each png write
488
+  * Fixed freeing of `Context2d` states
489
+  * Fixed text alignment / baseline [Olaf]
490
+  * Fixed HandleScopes [Olaf]
491
+  * Fixed small misc memory leaks
492
+  * Fixed `Buffer` usage for node 0.4.x
493
+
494
+0.4.3 / 2011-01-11
495
+==================
496
+
497
+  * Fixed font family dereferencing. Closes #72
498
+  * Fixed; stripping of quotes from font-family before applying
499
+  * Fixed duplicate textAlign getter
500
+  * Removed sans-serif default of _Arial_
501
+
502
+0.4.2 / 2010-12-28
503
+==================
504
+
505
+  * Fixed font size growing issue after successive calls. Closes #70
506
+
507
+0.4.1 / 2010-12-18
508
+==================
509
+
510
+  * Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68
511
+
512
+0.4.0 / 2010-12-12
513
+==================
514
+
515
+  * Added `drawImage()` with `Canvas` instance support. Closes #67
516
+
517
+0.3.3 / 2010-11-30
518
+==================
519
+
520
+  * Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_
521
+  * Fixed; pre-multiply `putImageData()` components
522
+  * Fixed; `PixelArray` data is not premultiplied
523
+
524
+0.3.2 / 2010-11-26
525
+==================
526
+
527
+  * Added --profile option to config
528
+  * Fixed `eio_custom` segfault(s). Closes #46
529
+  * Fixed two named colors. Closes #62 [thanks noonat]
530
+  * Fixed a few warnings
531
+  * Fixed; freeing data in `Image::loadJPEG()` on failure
532
+  * Fixed; include _jpeglib_ only when __HAVE_JPEG__
533
+  * Fixed; using `strstr()` instead of `strnstr()`
534
+
535
+0.3.1 / 2010-11-24
536
+==================
537
+
538
+  * Fixed; `Image` loading is sync until race-condition is resolved
539
+  * Fixed; `Image::loadJPEG()` return status based on errno
540
+
541
+0.3.0 / 2010-11-24
542
+==================
543
+
544
+  * Added arcTo(). Closes #11
545
+  * Added c color parser, _./examples/ray.js_ is now twice as fast
546
+  * Fixed `putImageData()` bug messing up rgba channels
547
+
548
+0.2.1 / 2010-11-19
549
+==================
550
+
551
+  * Added image _resize_ example
552
+  * Fixed canvas resizing via `{width,height}=`. Closes #57
553
+  * Fixed `Canvas#getContext()`, caching the CanvasRenderingContext
554
+  * Fixed async image loading (test server still messed)
555
+
556
+0.2.0 / 2010-11-18
557
+==================
558
+
559
+  * Added jpeg `Image` support (when libjpeg is available)
560
+  * Added _hsl_ / _hsla_ color support. [Tom Carden]
561
+
562
+0.1.0 / 2010-11-17
563
+==================
564
+
565
+  * Added `Image`
566
+  * Added `ImageData`
567
+  * Added `PixelArray`
568
+  * Added `CanvasRenderingContext2d#drawImage()`
569
+  * Added `CanvasRenderingContext2d#getImageData()`
570
+  * Added `CanvasRenderingContext2d#createImageData()`
571
+  * Added kraken blur benchmark example
572
+  * Added several new tests
573
+  * Fixed instanceof checks for many c++ methods
574
+  * Fixed test runner in firefox [Don Park]
575
+
576
+0.0.8 / 2010-11-12
577
+==================
578
+
579
+  * Added `CanvasRenderingContext2d#drawImage()`
580
+  * Fixed `free()` call missing stdlib
581
+  * Fixed Image#{width,height} initialization to 0
582
+  * Fixed; load image on non-LOADING state
583
+
584
+0.0.7 / 2010-11-12
585
+==================
586
+
587
+  * Fixed _lighter_ for older versions of cairo
588
+
589
+0.0.6 / 2010-11-12
590
+==================
591
+
592
+  * Added `Image`
593
+  * Added conditional support for cairo 1.10.0 operators
594
+
595
+0.0.5 / 2010-11-10
596
+==================
597
+
598
+  * Added custom port support to _test/server.js_
599
+  * Added more global composite operator support
600
+  * Added `Context2d#antialias=`
601
+  * Added _voronoi_ example
602
+  * Added -D__NDEBUG__ to default build
603
+  * Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park]
604
+  * Fixed getter bug preventing patterns from being returned via `fillStyle` etc
605
+
606
+  * Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc()
607
+  * Fixed; free `Canvas::ToBuffer()` closure data
608
+
609
+0.0.4 / 2010-11-09
610
+==================
611
+
612
+  * Bump to fix npm engine cache bug...
613
+
614
+0.0.3 / 2010-11-09
615
+==================
616
+
617
+  * Added async `toDataURL()` support
618
+  * Added async `toBuffer()` support
619
+  * Removed buffer utils
620
+
621
+0.0.2 / 2010-11-08
622
+==================
623
+
624
+  * Added shadow support (faster/better gaussian blur to come)
625
+  * Added node v0.3 support [Don Park]
626
+  * Added -O3 to build
627
+  * Removed `Canvas#savePNG()` use `Canvas#createPNGStream()`
628
+
629
+0.0.1 / 2010-11-04
630
+==================
631
+
632
+  * Initial release
633
+
634
+[repo]: https://github.com/Automattic/node-canvas

+ 368 - 0
vendor/canvas/Readme.md Wyświetl plik

@@ -0,0 +1,368 @@
1
+node-canvas
2
+===========
3
+### Canvas graphics API backed by Cairo
4
+[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas)
5
+[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas)
6
+
7
+  node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org).
8
+
9
+## Authors
10
+
11
+  - TJ Holowaychuk ([tj](http://github.com/tj))
12
+  - Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate))
13
+  - Rod Vagg ([rvagg](http://github.com/rvagg))
14
+  - Juriy Zaytsev ([kangax](http://github.com/kangax))
15
+
16
+## Installation
17
+
18
+```bash
19
+$ npm install canvas
20
+```
21
+
22
+Unless previously installed you'll _need_ __Cairo__ and __Pango__. For system-specific installation view the [Wiki](https://github.com/Automattic/node-canvas/wiki/_pages).
23
+
24
+You can quickly install the dependencies by using the command for your OS:
25
+
26
+OS | Command
27
+----- | -----
28
+OS X | `brew install pkg-config cairo pango libpng jpeg giflib`
29
+Ubuntu | `sudo apt-get install libcairo2-dev libjpeg8-dev libpango1.0-dev libgif-dev build-essential g++`
30
+Fedora | `sudo yum install cairo cairo-devel cairomm-devel libjpeg-turbo-devel pango pango-devel pangomm pangomm-devel giflib-devel`
31
+Solaris | `pkgin install cairo pango pkg-config xproto renderproto kbproto xextproto`
32
+Windows | [Instructions on our wiki](https://github.com/Automattic/node-canvas/wiki/Installation---Windows)
33
+
34
+**El Capitan users:** If you have recently updated to El Capitan and are experiencing trouble when compiling, run the following command: `xcode-select --install`. Read more about the problem [on Stack Overflow](http://stackoverflow.com/a/32929012/148072).
35
+
36
+## Screencasts
37
+
38
+  - [Introduction](http://screenr.com/CTk)
39
+
40
+## Example
41
+
42
+```javascript
43
+var Canvas = require('canvas')
44
+  , Image = Canvas.Image
45
+  , canvas = new Canvas(200, 200)
46
+  , ctx = canvas.getContext('2d');
47
+
48
+ctx.font = '30px Impact';
49
+ctx.rotate(.1);
50
+ctx.fillText("Awesome!", 50, 100);
51
+
52
+var te = ctx.measureText('Awesome!');
53
+ctx.strokeStyle = 'rgba(0,0,0,0.5)';
54
+ctx.beginPath();
55
+ctx.lineTo(50, 102);
56
+ctx.lineTo(50 + te.width, 102);
57
+ctx.stroke();
58
+
59
+console.log('<img src="' + canvas.toDataURL() + '" />');
60
+```
61
+
62
+## Non-Standard API
63
+
64
+ node-canvas extends the canvas API to provide interfacing with node, for example streaming PNG data, converting to a `Buffer` instance, etc. Among the interfacing API, in some cases the drawing API has been extended for SSJS image manipulation / creation usage, however keep in mind these additions may fail to render properly within browsers.
65
+
66
+### Image#src=Buffer
67
+
68
+ node-canvas adds `Image#src=Buffer` support, allowing you to read images from disc, redis, etc and apply them via `ctx.drawImage()`. Below we draw scaled down squid png by reading it from the disk with node's I/O.
69
+
70
+```javascript
71
+fs.readFile(__dirname + '/images/squid.png', function(err, squid){
72
+  if (err) throw err;
73
+  img = new Image;
74
+  img.src = squid;
75
+  ctx.drawImage(img, 0, 0, img.width / 4, img.height / 4);
76
+});
77
+```
78
+
79
+ Below is an example of a canvas drawing it-self as the source several time:
80
+
81
+```javascript
82
+var img = new Image;
83
+img.src = canvas.toBuffer();
84
+ctx.drawImage(img, 0, 0, 50, 50);
85
+ctx.drawImage(img, 50, 0, 50, 50);
86
+ctx.drawImage(img, 100, 0, 50, 50);
87
+```
88
+
89
+### Image#dataMode
90
+
91
+node-canvas adds `Image#dataMode` support, which can be used to opt-in to mime data tracking of images (currently only JPEGs).
92
+
93
+When mime data is tracked, in PDF mode JPEGs can be embedded directly into the output, rather than being re-encoded into PNG. This can drastically reduce filesize, and speed up rendering.
94
+
95
+```javascript
96
+var img = new Image;
97
+img.dataMode = Image.MODE_IMAGE; // Only image data tracked
98
+img.dataMode = Image.MODE_MIME; // Only mime data tracked
99
+img.dataMode = Image.MODE_MIME | Image.MODE_IMAGE; // Both are tracked
100
+```
101
+
102
+If image data is not tracked, and the Image is drawn to an image rather than a PDF canvas, the output will be junk. Enabling mime data tracking has no benefits (only a slow down) unless you are generating a PDF.
103
+
104
+### Canvas#pngStream()
105
+
106
+  To create a `PNGStream` simply call `canvas.pngStream()`, and the stream will start to emit _data_ events, finally emitting _end_ when finished. If an exception occurs the _error_ event is emitted.
107
+
108
+```javascript
109
+var fs = require('fs')
110
+  , out = fs.createWriteStream(__dirname + '/text.png')
111
+  , stream = canvas.pngStream();
112
+
113
+stream.on('data', function(chunk){
114
+  out.write(chunk);
115
+});
116
+
117
+stream.on('end', function(){
118
+  console.log('saved png');
119
+});
120
+```
121
+
122
+Currently _only_ sync streaming is supported, however we plan on supporting async streaming as well (of course :) ). Until then the `Canvas#toBuffer(callback)` alternative is async utilizing `eio_custom()`.
123
+
124
+### Canvas#jpegStream() and Canvas#syncJPEGStream()
125
+
126
+You can likewise create a `JPEGStream` by calling `canvas.jpegStream()` with
127
+some optional parameters; functionality is otherwise identical to
128
+`pngStream()`. See `examples/crop.js` for an example.
129
+
130
+_Note: At the moment, `jpegStream()` is the same as `syncJPEGStream()`, both
131
+are synchronous_
132
+
133
+```javascript
134
+var stream = canvas.jpegStream({
135
+    bufsize: 4096 // output buffer size in bytes, default: 4096
136
+  , quality: 75 // JPEG quality (0-100) default: 75
137
+  , progressive: false // true for progressive compression, default: false
138
+});
139
+```
140
+
141
+### Canvas#toBuffer()
142
+
143
+A call to `Canvas#toBuffer()` will return a node `Buffer` instance containing image data.
144
+
145
+```javascript
146
+// PNG Buffer, default settings
147
+var buf = canvas.toBuffer();
148
+
149
+// PNG Buffer, zlib compression level 3 (from 0-9), faster but bigger
150
+var buf2 = canvas.toBuffer(undefined, 3, canvas.PNG_FILTER_NONE);
151
+
152
+// ARGB32 Buffer, native-endian
153
+var buf3 = canvas.toBuffer('raw');
154
+var stride = canvas.stride;
155
+// In memory, this is `canvas.height * canvas.stride` bytes long.
156
+// The top row of pixels, in ARGB order, left-to-right, is:
157
+var topPixelsARGBLeftToRight = buf3.slice(0, canvas.width * 4);
158
+var row3 = buf3.slice(2 * canvas.stride, 2 * canvas.stride + canvas.width * 4);
159
+```
160
+
161
+### Canvas#toBuffer() async
162
+
163
+Optionally we may pass a callback function to `Canvas#toBuffer()`, and this process will be performed asynchronously, and will `callback(err, buf)`.
164
+
165
+```javascript
166
+canvas.toBuffer(function(err, buf){
167
+
168
+});
169
+```
170
+
171
+### Canvas#toDataURL() sync and async
172
+
173
+The following syntax patterns are supported:
174
+
175
+```javascript
176
+var dataUrl = canvas.toDataURL(); // defaults to PNG
177
+var dataUrl = canvas.toDataURL('image/png');
178
+canvas.toDataURL(function(err, png){ }); // defaults to PNG
179
+canvas.toDataURL('image/png', function(err, png){ });
180
+canvas.toDataURL('image/jpeg', function(err, jpeg){ }); // sync JPEG is not supported
181
+canvas.toDataURL('image/jpeg', {opts...}, function(err, jpeg){ }); // see Canvas#jpegStream for valid options
182
+canvas.toDataURL('image/jpeg', quality, function(err, jpeg){ }); // spec-following; quality from 0 to 1
183
+```
184
+
185
+### Canvas.registerFont for bundled fonts
186
+
187
+It can be useful to use a custom font file if you are distributing code that uses node-canvas and a specific font. Or perhaps you are using it to do automated tests and you want the renderings to be the same across operating systems regardless of what fonts are installed.
188
+
189
+To do that, you should use `Canvas.registerFont`.
190
+
191
+**You need to call it before the Canvas is created**
192
+
193
+```javascript
194
+Canvas.registerFont('comicsans.ttf', {family: 'Comic Sans'});
195
+
196
+var canvas = new Canvas(500, 500),
197
+  ctx = canvas.getContext('2d');
198
+
199
+ctx.font = '12px "Comic Sans"';
200
+ctx.fillText(250, 10, 'Everyone hates this font :(');
201
+```
202
+
203
+The second argument is an object with properties that resemble the CSS properties that are specified in `@font-face` rules. You must specify at least `family`. `weight`, and `style` are optional (and default to "normal").
204
+
205
+### CanvasRenderingContext2D#patternQuality
206
+
207
+Given one of the values below will alter pattern (gradients, images, etc) render quality, defaults to _good_.
208
+
209
+  - fast
210
+  - good
211
+  - best
212
+  - nearest
213
+  - bilinear
214
+
215
+### CanvasRenderingContext2D#textDrawingMode
216
+
217
+Can be either `path` or `glyph`. Using `glyph` is much faster than `path` for drawing, and when using a PDF context will embed the text natively, so will be selectable and lower filesize. The downside is that cairo does not have any subpixel precision for `glyph`, so this will be noticeably lower quality for text positioning in cases such as rotated text. Also, strokeText in `glyph` will act the same as fillText, except using the stroke style for the fill.
218
+
219
+Defaults to _path_.
220
+
221
+This property is tracked as part of the canvas state in save/restore.
222
+
223
+### CanvasRenderingContext2D#filter
224
+
225
+Like `patternQuality`, but applies to transformations effecting more than just patterns. Defaults to _good_.
226
+
227
+  - fast
228
+  - good
229
+  - best
230
+  - nearest
231
+  - bilinear
232
+
233
+### Global Composite Operations
234
+
235
+In addition to those specified and commonly implemented by browsers, the following have been added:
236
+
237
+  - multiply
238
+  - screen
239
+  - overlay
240
+  - hard-light
241
+  - soft-light
242
+  - hsl-hue
243
+  - hsl-saturation
244
+  - hsl-color
245
+  - hsl-luminosity
246
+
247
+## Anti-Aliasing
248
+
249
+ Set anti-aliasing mode
250
+
251
+ - default
252
+ - none
253
+ - gray
254
+ - subpixel
255
+
256
+ For example:
257
+
258
+```javascript
259
+ctx.antialias = 'none';
260
+```
261
+
262
+## PDF Support
263
+
264
+  Basic PDF support was added in 0.11.0. Make sure to install cairo with `--enable-pdf=yes` for the PDF backend. node-canvas must know that it is creating
265
+  a PDF on initialization, using the "pdf" string:
266
+
267
+```js
268
+var canvas = new Canvas(200, 500, 'pdf');
269
+```
270
+
271
+ An additional method `.addPage()` is then available to create
272
+ multiple page PDFs:
273
+
274
+```js
275
+ctx.font = '22px Helvetica';
276
+ctx.fillText('Hello World', 50, 80);
277
+ctx.addPage();
278
+
279
+ctx.font = '22px Helvetica';
280
+ctx.fillText('Hello World 2', 50, 80);
281
+ctx.addPage();
282
+
283
+ctx.font = '22px Helvetica';
284
+ctx.fillText('Hello World 3', 50, 80);
285
+ctx.addPage();
286
+```
287
+
288
+## SVG support
289
+
290
+ Just like PDF support, make sure to install cairo with `--enable-svg=yes`.
291
+ You also need to tell node-canvas that it is working on SVG upon its initialization:
292
+
293
+```js
294
+var canvas = new Canvas(200, 500, 'svg');
295
+// Use the normal primitives.
296
+fs.writeFile('out.svg', canvas.toBuffer());
297
+```
298
+
299
+## Benchmarks
300
+
301
+ Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself.
302
+
303
+## Contribute
304
+
305
+ Want to contribute to node-canvas? patches for features, bug fixes, documentation, examples and others are certainly welcome. Take a look at the [issue queue](https://github.com/Automattic/node-canvas/issues) for existing issues.
306
+
307
+## Examples
308
+
309
+ Examples are placed in _./examples_, be sure to check them out! most produce a png image of the same name, and others such as _live-clock.js_ launch an http server to be viewed in the browser.
310
+
311
+## Testing
312
+
313
+If you have not previously, init git submodules:
314
+
315
+    $ git submodule update --init
316
+
317
+Install the node modules:
318
+
319
+    $ npm install
320
+
321
+Build node-canvas:
322
+
323
+    $ node-gyp rebuild
324
+
325
+Unit tests:
326
+
327
+    $ make test
328
+
329
+Visual tests:
330
+
331
+    $ make test-server
332
+
333
+## Versions
334
+
335
+Tested with and designed for:
336
+
337
+  - node 0.4.2
338
+  - cairo 1.8.6
339
+
340
+For node 0.2.x `node-canvas` <= 0.4.3 may be used,
341
+0.5.0 and above are designed for node 0.4.x only.
342
+
343
+## License
344
+
345
+(The MIT License)
346
+
347
+Copyright (c) 2010 LearnBoost, and contributors &lt;dev@learnboost.com&gt;
348
+
349
+Copyright (c) 2014 Automattic, Inc and contributors &lt;dev@automattic.com&gt;
350
+
351
+Permission is hereby granted, free of charge, to any person obtaining
352
+a copy of this software and associated documentation files (the
353
+'Software'), to deal in the Software without restriction, including
354
+without limitation the rights to use, copy, modify, merge, publish,
355
+distribute, sublicense, and/or sell copies of the Software, and to
356
+permit persons to whom the Software is furnished to do so, subject to
357
+the following conditions:
358
+
359
+The above copyright notice and this permission notice shall be
360
+included in all copies or substantial portions of the Software.
361
+
362
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
363
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
364
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
365
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
366
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
367
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
368
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 151 - 0
vendor/canvas/binding.gyp Wyświetl plik

@@ -0,0 +1,151 @@
1
+{
2
+  'conditions': [
3
+    ['OS=="win"', {
4
+      'variables': {
5
+        'GTK_Root%': 'C:/GTK', # Set the location of GTK all-in-one bundle
6
+        'with_jpeg%': 'false',
7
+        'with_gif%': 'false'
8
+      }
9
+    }, { # 'OS!="win"'
10
+      'variables': {
11
+        'with_jpeg%': '<!(./util/has_lib.sh jpeg)',
12
+        'with_gif%': '<!(./util/has_lib.sh gif)'
13
+      }
14
+    }]
15
+  ],
16
+  'targets': [
17
+    {
18
+      'target_name': 'canvas-postbuild',
19
+      'dependencies': ['canvas'],
20
+      'conditions': [
21
+        ['OS=="win"', {
22
+          'copies': [{
23
+            'destination': '<(PRODUCT_DIR)',
24
+            'files': [
25
+              '<(GTK_Root)/bin/zlib1.dll',
26
+              '<(GTK_Root)/bin/libintl-8.dll',
27
+              '<(GTK_Root)/bin/libpng14-14.dll',
28
+              '<(GTK_Root)/bin/libpangocairo-1.0-0.dll',
29
+              '<(GTK_Root)/bin/libpango-1.0-0.dll',
30
+              '<(GTK_Root)/bin/libpangoft2-1.0-0.dll',
31
+              '<(GTK_Root)/bin/libpangowin32-1.0-0.dll',
32
+              '<(GTK_Root)/bin/libcairo-2.dll',
33
+              '<(GTK_Root)/bin/libfontconfig-1.dll',
34
+              '<(GTK_Root)/bin/libfreetype-6.dll',
35
+              '<(GTK_Root)/bin/libglib-2.0-0.dll',
36
+              '<(GTK_Root)/bin/libgobject-2.0-0.dll',
37
+              '<(GTK_Root)/bin/libgmodule-2.0-0.dll',
38
+              '<(GTK_Root)/bin/libgthread-2.0-0.dll',
39
+              '<(GTK_Root)/bin/libexpat-1.dll'
40
+            ]
41
+          }]
42
+        }]
43
+      ]
44
+    },
45
+    {
46
+      'target_name': 'canvas',
47
+      'include_dirs': ["<!(node -e \"require('nan')\")"],
48
+      'sources': [
49
+        'src/Canvas.cc',
50
+        'src/CanvasGradient.cc',
51
+        'src/CanvasPattern.cc',
52
+        'src/CanvasRenderingContext2d.cc',
53
+        'src/color.cc',
54
+        'src/Image.cc',
55
+        'src/ImageData.cc',
56
+        'src/register_font.cc',
57
+        'src/init.cc'
58
+      ],
59
+      'conditions': [
60
+        ['OS=="win"', {
61
+          'libraries': [
62
+            '-l<(GTK_Root)/lib/cairo.lib',
63
+            '-l<(GTK_Root)/lib/libpng.lib',
64
+            '-l<(GTK_Root)/lib/pangocairo-1.0.lib',
65
+            '-l<(GTK_Root)/lib/pango-1.0.lib',
66
+            '-l<(GTK_Root)/lib/freetype.lib',
67
+            '-l<(GTK_Root)/lib/glib-2.0.lib',
68
+            '-l<(GTK_Root)/lib/gobject-2.0.lib'
69
+          ],
70
+          'include_dirs': [
71
+            '<(GTK_Root)/include',
72
+            '<(GTK_Root)/include/cairo',
73
+            '<(GTK_Root)/include/pango-1.0',
74
+            '<(GTK_Root)/include/glib-2.0',
75
+            '<(GTK_Root)/include/freetype2',
76
+            '<(GTK_Root)/lib/glib-2.0/include'
77
+          ],
78
+          'defines': [
79
+            '_USE_MATH_DEFINES' # for M_PI
80
+          ],
81
+          'configurations': {
82
+            'Debug': {
83
+              'msvs_settings': {
84
+                'VCCLCompilerTool': {
85
+                  'WarningLevel': 4,
86
+                  'ExceptionHandling': 1,
87
+                  'DisableSpecificWarnings': [4100, 4127, 4201, 4244, 4267, 4506, 4611, 4714, 4512]
88
+                }
89
+              }
90
+            },
91
+            'Release': {
92
+              'msvs_settings': {
93
+                'VCCLCompilerTool': {
94
+                  'WarningLevel': 4,
95
+                  'ExceptionHandling': 1,
96
+                  'DisableSpecificWarnings': [4100, 4127, 4201, 4244, 4267, 4506, 4611, 4714, 4512]
97
+                }
98
+              }
99
+            }
100
+          }
101
+        }, { # 'OS!="win"'
102
+          'libraries': [
103
+            '<!@(pkg-config pixman-1 --libs)',
104
+            '<!@(pkg-config cairo --libs)',
105
+            '<!@(pkg-config libpng --libs)',
106
+            '<!@(pkg-config pangocairo --libs)',
107
+            '<!@(pkg-config freetype2 --libs)'
108
+          ],
109
+          'include_dirs': [
110
+            '<!@(pkg-config cairo --cflags-only-I | sed s/-I//g)',
111
+            '<!@(pkg-config libpng --cflags-only-I | sed s/-I//g)',
112
+            '<!@(pkg-config pangocairo --cflags-only-I | sed s/-I//g)',
113
+            '<!@(pkg-config freetype2 --cflags-only-I | sed s/-I//g)'
114
+          ]
115
+        }],
116
+        ['with_jpeg=="true"', {
117
+          'defines': [
118
+            'HAVE_JPEG'
119
+          ],
120
+          'conditions': [
121
+            ['OS=="win"', {
122
+              'libraries': [
123
+                '-l<(GTK_Root)/lib/jpeg.lib'
124
+              ]
125
+            }, {
126
+              'libraries': [
127
+                '-ljpeg'
128
+              ]
129
+            }]
130
+          ]
131
+        }],
132
+        ['with_gif=="true"', {
133
+          'defines': [
134
+            'HAVE_GIF'
135
+          ],
136
+          'conditions': [
137
+            ['OS=="win"', {
138
+              'libraries': [
139
+                '-l<(GTK_Root)/lib/gif.lib'
140
+              ]
141
+            }, {
142
+              'libraries': [
143
+                '-lgif'
144
+              ]
145
+            }]
146
+          ]
147
+        }]
148
+      ]
149
+    }
150
+  ]
151
+}

Plik diff jest za duży
+ 329 - 0
vendor/canvas/build/Makefile


+ 1 - 0
vendor/canvas/build/Release/.deps/Release/canvas-postbuild.node.d Wyświetl plik

@@ -0,0 +1 @@
1
+cmd_Release/canvas-postbuild.node := rm -rf "Release/canvas-postbuild.node" && cp -af "Release/obj.target/canvas-postbuild.node" "Release/canvas-postbuild.node"

+ 1 - 0
vendor/canvas/build/Release/.deps/Release/canvas.node.d Wyświetl plik

@@ -0,0 +1 @@
1
+cmd_Release/canvas.node := rm -rf "Release/canvas.node" && cp -af "Release/obj.target/canvas.node" "Release/canvas.node"

+ 1 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas-postbuild.node.d Wyświetl plik

@@ -0,0 +1 @@
1
+cmd_Release/obj.target/canvas-postbuild.node := g++ -shared -pthread -rdynamic -m64  -Wl,-soname=canvas-postbuild.node -o Release/obj.target/canvas-postbuild.node -Wl,--start-group  -Wl,--end-group 

Plik diff jest za duży
+ 1 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas.node.d


Plik diff jest za duży
+ 309 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d


Plik diff jest za duży
+ 292 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d


Plik diff jest za duży
+ 291 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d


Plik diff jest za duży
+ 298 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d


Plik diff jest za duży
+ 289 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d


Plik diff jest za duży
+ 290 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d


Plik diff jest za duży
+ 4 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d


Plik diff jest za duży
+ 317 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d


Plik diff jest za duży
+ 260 - 0
vendor/canvas/build/Release/.deps/Release/obj.target/canvas/src/register_font.o.d


BIN
vendor/canvas/build/Release/canvas-postbuild.node Wyświetl plik


BIN
vendor/canvas/build/Release/canvas.node Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas-postbuild.node Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas.node Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/Canvas.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/Image.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/ImageData.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/color.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/init.o Wyświetl plik


BIN
vendor/canvas/build/Release/obj.target/canvas/src/register_font.o Wyświetl plik


+ 6 - 0
vendor/canvas/build/binding.Makefile Wyświetl plik

@@ -0,0 +1,6 @@
1
+# This file is generated by gyp; do not edit.
2
+
3
+export builddir_name ?= ./build/.
4
+.PHONY: all
5
+all:
6
+	$(MAKE) canvas canvas-postbuild

+ 42 - 0
vendor/canvas/build/canvas-postbuild.target.mk Wyświetl plik

@@ -0,0 +1,42 @@
1
+# This file is generated by gyp; do not edit.
2
+
3
+TOOLSET := target
4
+TARGET := canvas-postbuild
5
+### Rules for final target.
6
+LDFLAGS_Debug := \
7
+	-pthread \
8
+	-rdynamic \
9
+	-m64
10
+
11
+LDFLAGS_Release := \
12
+	-pthread \
13
+	-rdynamic \
14
+	-m64
15
+
16
+LIBS :=
17
+
18
+$(obj).target/canvas-postbuild.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
19
+$(obj).target/canvas-postbuild.node: LIBS := $(LIBS)
20
+$(obj).target/canvas-postbuild.node: TOOLSET := $(TOOLSET)
21
+$(obj).target/canvas-postbuild.node:  FORCE_DO_CMD
22
+	$(call do_cmd,solink_module)
23
+
24
+all_deps += $(obj).target/canvas-postbuild.node
25
+# Add target alias
26
+.PHONY: canvas-postbuild
27
+canvas-postbuild: $(builddir)/canvas-postbuild.node
28
+
29
+# Copy this to the executable output path.
30
+$(builddir)/canvas-postbuild.node: TOOLSET := $(TOOLSET)
31
+$(builddir)/canvas-postbuild.node: $(obj).target/canvas-postbuild.node FORCE_DO_CMD
32
+	$(call do_cmd,copy)
33
+
34
+all_deps += $(builddir)/canvas-postbuild.node
35
+# Short alias for building this executable.
36
+.PHONY: canvas-postbuild.node
37
+canvas-postbuild.node: $(obj).target/canvas-postbuild.node $(builddir)/canvas-postbuild.node
38
+
39
+# Add executable to "all" target.
40
+.PHONY: all
41
+all: $(builddir)/canvas-postbuild.node
42
+

+ 178 - 0
vendor/canvas/build/canvas.target.mk Wyświetl plik

@@ -0,0 +1,178 @@
1
+# This file is generated by gyp; do not edit.
2
+
3
+TOOLSET := target
4
+TARGET := canvas
5
+DEFS_Debug := \
6
+	'-DNODE_GYP_MODULE_NAME=canvas' \
7
+	'-DUSING_UV_SHARED=1' \
8
+	'-DUSING_V8_SHARED=1' \
9
+	'-DV8_DEPRECATION_WARNINGS=1' \
10
+	'-D_LARGEFILE_SOURCE' \
11
+	'-D_FILE_OFFSET_BITS=64' \
12
+	'-DHAVE_JPEG' \
13
+	'-DHAVE_GIF' \
14
+	'-DBUILDING_NODE_EXTENSION' \
15
+	'-DDEBUG' \
16
+	'-D_DEBUG'
17
+
18
+# Flags passed to all source files.
19
+CFLAGS_Debug := \
20
+	-fPIC \
21
+	-pthread \
22
+	-Wall \
23
+	-Wextra \
24
+	-Wno-unused-parameter \
25
+	-m64 \
26
+	-g \
27
+	-O0
28
+
29
+# Flags passed to only C files.
30
+CFLAGS_C_Debug :=
31
+
32
+# Flags passed to only C++ files.
33
+CFLAGS_CC_Debug := \
34
+	-fno-rtti \
35
+	-fno-exceptions \
36
+	-std=gnu++0x
37
+
38
+INCS_Debug := \
39
+	-I/root/.node-gyp/7.10.1/include/node \
40
+	-I/root/.node-gyp/7.10.1/src \
41
+	-I/root/.node-gyp/7.10.1/deps/uv/include \
42
+	-I/root/.node-gyp/7.10.1/deps/v8/include \
43
+	-I$(srcdir)/../nan \
44
+	-I/usr/include/cairo \
45
+	-I/usr/include/glib-2.0 \
46
+	-I/usr/lib/x86_64-linux-gnu/glib-2.0/include \
47
+	-I/usr/include/pixman-1 \
48
+	-I/usr/include/freetype2 \
49
+	-I/usr/include/libpng12 \
50
+	-I/usr/include/pango-1.0
51
+
52
+DEFS_Release := \
53
+	'-DNODE_GYP_MODULE_NAME=canvas' \
54
+	'-DUSING_UV_SHARED=1' \
55
+	'-DUSING_V8_SHARED=1' \
56
+	'-DV8_DEPRECATION_WARNINGS=1' \
57
+	'-D_LARGEFILE_SOURCE' \
58
+	'-D_FILE_OFFSET_BITS=64' \
59
+	'-DHAVE_JPEG' \
60
+	'-DHAVE_GIF' \
61
+	'-DBUILDING_NODE_EXTENSION'
62
+
63
+# Flags passed to all source files.
64
+CFLAGS_Release := \
65
+	-fPIC \
66
+	-pthread \
67
+	-Wall \
68
+	-Wextra \
69
+	-Wno-unused-parameter \
70
+	-m64 \
71
+	-O3 \
72
+	-fno-omit-frame-pointer
73
+
74
+# Flags passed to only C files.
75
+CFLAGS_C_Release :=
76
+
77
+# Flags passed to only C++ files.
78
+CFLAGS_CC_Release := \
79
+	-fno-rtti \
80
+	-fno-exceptions \
81
+	-std=gnu++0x
82
+
83
+INCS_Release := \
84
+	-I/root/.node-gyp/7.10.1/include/node \
85
+	-I/root/.node-gyp/7.10.1/src \
86
+	-I/root/.node-gyp/7.10.1/deps/uv/include \
87
+	-I/root/.node-gyp/7.10.1/deps/v8/include \
88
+	-I$(srcdir)/../nan \
89
+	-I/usr/include/cairo \
90
+	-I/usr/include/glib-2.0 \
91
+	-I/usr/lib/x86_64-linux-gnu/glib-2.0/include \
92
+	-I/usr/include/pixman-1 \
93
+	-I/usr/include/freetype2 \
94
+	-I/usr/include/libpng12 \
95
+	-I/usr/include/pango-1.0
96
+
97
+OBJS := \
98
+	$(obj).target/$(TARGET)/src/Canvas.o \
99
+	$(obj).target/$(TARGET)/src/CanvasGradient.o \
100
+	$(obj).target/$(TARGET)/src/CanvasPattern.o \
101
+	$(obj).target/$(TARGET)/src/CanvasRenderingContext2d.o \
102
+	$(obj).target/$(TARGET)/src/color.o \
103
+	$(obj).target/$(TARGET)/src/Image.o \
104
+	$(obj).target/$(TARGET)/src/ImageData.o \
105
+	$(obj).target/$(TARGET)/src/register_font.o \
106
+	$(obj).target/$(TARGET)/src/init.o
107
+
108
+# Add to the list of files we specially track dependencies for.
109
+all_deps += $(OBJS)
110
+
111
+# CFLAGS et al overrides must be target-local.
112
+# See "Target-specific Variable Values" in the GNU Make manual.
113
+$(OBJS): TOOLSET := $(TOOLSET)
114
+$(OBJS): GYP_CFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE))  $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_C_$(BUILDTYPE))
115
+$(OBJS): GYP_CXXFLAGS := $(DEFS_$(BUILDTYPE)) $(INCS_$(BUILDTYPE))  $(CFLAGS_$(BUILDTYPE)) $(CFLAGS_CC_$(BUILDTYPE))
116
+
117
+# Suffix rules, putting all outputs into $(obj).
118
+
119
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(srcdir)/%.cc FORCE_DO_CMD
120
+	@$(call do_cmd,cxx,1)
121
+
122
+# Try building from generated source, too.
123
+
124
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj).$(TOOLSET)/%.cc FORCE_DO_CMD
125
+	@$(call do_cmd,cxx,1)
126
+
127
+$(obj).$(TOOLSET)/$(TARGET)/%.o: $(obj)/%.cc FORCE_DO_CMD
128
+	@$(call do_cmd,cxx,1)
129
+
130
+# End of this set of suffix rules
131
+### Rules for final target.
132
+LDFLAGS_Debug := \
133
+	-pthread \
134
+	-rdynamic \
135
+	-m64
136
+
137
+LDFLAGS_Release := \
138
+	-pthread \
139
+	-rdynamic \
140
+	-m64
141
+
142
+LIBS := \
143
+	-lpixman-1 \
144
+	-lcairo \
145
+	-lpng12 \
146
+	-lpangocairo-1.0 \
147
+	-lpango-1.0 \
148
+	-lgobject-2.0 \
149
+	-lglib-2.0 \
150
+	-lfreetype \
151
+	-ljpeg \
152
+	-lgif
153
+
154
+$(obj).target/canvas.node: GYP_LDFLAGS := $(LDFLAGS_$(BUILDTYPE))
155
+$(obj).target/canvas.node: LIBS := $(LIBS)
156
+$(obj).target/canvas.node: TOOLSET := $(TOOLSET)
157
+$(obj).target/canvas.node: $(OBJS) FORCE_DO_CMD
158
+	$(call do_cmd,solink_module)
159
+
160
+all_deps += $(obj).target/canvas.node
161
+# Add target alias
162
+.PHONY: canvas
163
+canvas: $(builddir)/canvas.node
164
+
165
+# Copy this to the executable output path.
166
+$(builddir)/canvas.node: TOOLSET := $(TOOLSET)
167
+$(builddir)/canvas.node: $(obj).target/canvas.node FORCE_DO_CMD
168
+	$(call do_cmd,copy)
169
+
170
+all_deps += $(builddir)/canvas.node
171
+# Short alias for building this executable.
172
+.PHONY: canvas.node
173
+canvas.node: $(obj).target/canvas.node $(builddir)/canvas.node
174
+
175
+# Add executable to "all" target.
176
+.PHONY: all
177
+all: $(builddir)/canvas.node
178
+

+ 160 - 0
vendor/canvas/build/config.gypi Wyświetl plik

@@ -0,0 +1,160 @@
1
+# Do not edit. File was generated by node-gyp's "configure" step
2
+{
3
+  "target_defaults": {
4
+    "cflags": [],
5
+    "default_configuration": "Release",
6
+    "defines": [],
7
+    "include_dirs": [],
8
+    "libraries": []
9
+  },
10
+  "variables": {
11
+    "asan": 0,
12
+    "coverage": "false",
13
+    "debug_devtools": "node",
14
+    "force_dynamic_crt": 0,
15
+    "gas_version": "2.23",
16
+    "host_arch": "x64",
17
+    "icu_data_file": "icudt58l.dat",
18
+    "icu_data_in": "../../deps/icu-small/source/data/in/icudt58l.dat",
19
+    "icu_endianness": "l",
20
+    "icu_gyp_path": "tools/icu/icu-generic.gyp",
21
+    "icu_locales": "en,root",
22
+    "icu_path": "deps/icu-small",
23
+    "icu_small": "true",
24
+    "icu_ver_major": "58",
25
+    "node_byteorder": "little",
26
+    "node_enable_d8": "false",
27
+    "node_enable_v8_vtunejit": "false",
28
+    "node_install_npm": "true",
29
+    "node_module_version": 51,
30
+    "node_no_browser_globals": "false",
31
+    "node_prefix": "/",
32
+    "node_release_urlbase": "https://nodejs.org/download/release/",
33
+    "node_shared": "false",
34
+    "node_shared_cares": "false",
35
+    "node_shared_http_parser": "false",
36
+    "node_shared_libuv": "false",
37
+    "node_shared_openssl": "false",
38
+    "node_shared_zlib": "false",
39
+    "node_tag": "",
40
+    "node_use_bundled_v8": "true",
41
+    "node_use_dtrace": "false",
42
+    "node_use_etw": "false",
43
+    "node_use_lttng": "false",
44
+    "node_use_openssl": "true",
45
+    "node_use_perfctr": "false",
46
+    "node_use_v8_platform": "true",
47
+    "openssl_fips": "",
48
+    "openssl_no_asm": 0,
49
+    "shlib_suffix": "so.51",
50
+    "target_arch": "x64",
51
+    "uv_parent_path": "/deps/uv/",
52
+    "uv_use_dtrace": "false",
53
+    "v8_enable_gdbjit": 0,
54
+    "v8_enable_i18n_support": 1,
55
+    "v8_inspector": "true",
56
+    "v8_no_strict_aliasing": 1,
57
+    "v8_optimized_debug": 0,
58
+    "v8_random_seed": 0,
59
+    "v8_use_snapshot": "false",
60
+    "want_separate_host_toolset": 0,
61
+    "want_separate_host_toolset_mkpeephole": 0,
62
+    "nodedir": "/root/.node-gyp/7.10.1",
63
+    "copy_dev_lib": "true",
64
+    "standalone_static_library": 1,
65
+    "cache_lock_stale": "60000",
66
+    "legacy_bundling": "",
67
+    "sign_git_tag": "",
68
+    "user_agent": "npm/4.2.0 node/v7.10.1 linux x64",
69
+    "always_auth": "",
70
+    "bin_links": "true",
71
+    "key": "",
72
+    "description": "true",
73
+    "fetch_retries": "2",
74
+    "heading": "npm",
75
+    "if_present": "",
76
+    "init_version": "1.0.0",
77
+    "user": "",
78
+    "force": "",
79
+    "only": "",
80
+    "cache_min": "10",
81
+    "init_license": "ISC",
82
+    "editor": "vi",
83
+    "rollback": "true",
84
+    "tag_version_prefix": "v",
85
+    "cache_max": "Infinity",
86
+    "userconfig": "/root/.npmrc",
87
+    "engine_strict": "",
88
+    "init_author_name": "",
89
+    "init_author_url": "",
90
+    "tmp": "/tmp",
91
+    "depth": "Infinity",
92
+    "save_dev": "",
93
+    "usage": "",
94
+    "metrics_registry": "https://registry.npmjs.org/",
95
+    "progress": "true",
96
+    "https_proxy": "",
97
+    "onload_script": "",
98
+    "rebuild_bundle": "true",
99
+    "save_bundle": "",
100
+    "shell": "bash",
101
+    "dry_run": "",
102
+    "prefix": "/usr/local",
103
+    "scope": "",
104
+    "browser": "",
105
+    "cache_lock_wait": "10000",
106
+    "registry": "https://registry.npmjs.org/",
107
+    "save_optional": "",
108
+    "searchopts": "",
109
+    "versions": "",
110
+    "cache": "/root/.npm",
111
+    "send_metrics": "",
112
+    "global_style": "",
113
+    "ignore_scripts": "",
114
+    "version": "",
115
+    "local_address": "",
116
+    "viewer": "man",
117
+    "color": "true",
118
+    "fetch_retry_mintimeout": "10000",
119
+    "maxsockets": "50",
120
+    "umask": "0022",
121
+    "fetch_retry_maxtimeout": "60000",
122
+    "logs_max": "10",
123
+    "message": "%s",
124
+    "ca": "",
125
+    "cert": "",
126
+    "global": "",
127
+    "link": "",
128
+    "access": "",
129
+    "also": "",
130
+    "save": "",
131
+    "unicode": "",
132
+    "production": "true",
133
+    "long": "",
134
+    "searchlimit": "20",
135
+    "unsafe_perm": "",
136
+    "node_version": "7.10.1",
137
+    "tag": "latest",
138
+    "git_tag_version": "true",
139
+    "shrinkwrap": "true",
140
+    "fetch_retry_factor": "10",
141
+    "proprietary_attribs": "true",
142
+    "save_exact": "",
143
+    "strict_ssl": "true",
144
+    "dev": "",
145
+    "globalconfig": "/usr/local/etc/npmrc",
146
+    "init_module": "/root/.npm-init.js",
147
+    "parseable": "",
148
+    "globalignorefile": "/usr/local/etc/npmignore",
149
+    "cache_lock_retries": "10",
150
+    "searchstaleness": "900",
151
+    "save_prefix": "^",
152
+    "scripts_prepend_node_path": "warn-only",
153
+    "group": "",
154
+    "init_author_email": "",
155
+    "searchexclude": "",
156
+    "git": "git",
157
+    "optional": "true",
158
+    "json": ""
159
+  }
160
+}

+ 1 - 0
vendor/canvas/index.js Wyświetl plik

@@ -0,0 +1 @@
1
+module.exports = require('./lib/canvas');

+ 3 - 0
vendor/canvas/lib/bindings.js Wyświetl plik

@@ -0,0 +1,3 @@
1
+'use strict';
2
+
3
+module.exports = require('../build/Release/canvas');

+ 288 - 0
vendor/canvas/lib/canvas.js Wyświetl plik

@@ -0,0 +1,288 @@
1
+'use strict';
2
+
3
+/*!
4
+ * Canvas
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+/**
10
+ * Module dependencies.
11
+ */
12
+
13
+var canvas = require('./bindings')
14
+  , Canvas = canvas.Canvas
15
+  , Image = canvas.Image
16
+  , cairoVersion = canvas.cairoVersion
17
+  , Context2d = require('./context2d')
18
+  , PNGStream = require('./pngstream')
19
+  , PDFStream = require('./pdfstream')
20
+  , JPEGStream = require('./jpegstream')
21
+  , fs = require('fs')
22
+  , packageJson = require("../package.json")
23
+  , FORMATS = ['image/png', 'image/jpeg'];
24
+
25
+/**
26
+ * Export `Canvas` as the module.
27
+ */
28
+
29
+var Canvas = exports = module.exports = Canvas;
30
+
31
+/**
32
+ * Library version.
33
+ */
34
+
35
+exports.version = packageJson.version;
36
+
37
+/**
38
+ * Cairo version.
39
+ */
40
+
41
+exports.cairoVersion = cairoVersion;
42
+
43
+/**
44
+ * jpeglib version.
45
+ */
46
+
47
+if (canvas.jpegVersion) {
48
+  exports.jpegVersion = canvas.jpegVersion;
49
+}
50
+
51
+/**
52
+ * gif_lib version.
53
+ */
54
+
55
+if (canvas.gifVersion) {
56
+  exports.gifVersion = canvas.gifVersion.replace(/[^.\d]/g, '');
57
+}
58
+
59
+/**
60
+ * freetype version.
61
+ */
62
+
63
+if (canvas.freetypeVersion) {
64
+  exports.freetypeVersion = canvas.freetypeVersion;
65
+}
66
+
67
+/**
68
+ * Expose constructors.
69
+ */
70
+
71
+exports.Context2d = Context2d;
72
+exports.PNGStream = PNGStream;
73
+exports.PDFStream = PDFStream;
74
+exports.JPEGStream = JPEGStream;
75
+exports.Image = Image;
76
+exports.ImageData = canvas.ImageData;
77
+
78
+/**
79
+ * Context2d implementation.
80
+ */
81
+
82
+require('./context2d');
83
+
84
+/**
85
+ * Image implementation.
86
+ */
87
+
88
+require('./image');
89
+
90
+/**
91
+ * Inspect canvas.
92
+ *
93
+ * @return {String}
94
+ * @api public
95
+ */
96
+
97
+Canvas.prototype.inspect = function(){
98
+  return '[Canvas ' + this.width + 'x' + this.height + ']';
99
+};
100
+
101
+/**
102
+ * Get a context object.
103
+ *
104
+ * @param {String} contextId
105
+ * @return {Context2d}
106
+ * @api public
107
+ */
108
+
109
+Canvas.prototype.getContext = function(contextId){
110
+  if ('2d' == contextId) {
111
+    var ctx = this._context2d || (this._context2d = new Context2d(this));
112
+    this.context = ctx;
113
+    ctx.canvas = this;
114
+    return ctx;
115
+  }
116
+};
117
+
118
+/**
119
+ * Create a `PNGStream` for `this` canvas.
120
+ *
121
+ * @return {PNGStream}
122
+ * @api public
123
+ */
124
+
125
+Canvas.prototype.pngStream =
126
+Canvas.prototype.createPNGStream = function(){
127
+  return new PNGStream(this);
128
+};
129
+
130
+/**
131
+ * Create a synchronous `PNGStream` for `this` canvas.
132
+ *
133
+ * @return {PNGStream}
134
+ * @api public
135
+ */
136
+
137
+Canvas.prototype.syncPNGStream =
138
+Canvas.prototype.createSyncPNGStream = function(){
139
+  return new PNGStream(this, true);
140
+};
141
+
142
+/**
143
+ * Create a `PDFStream` for `this` canvas.
144
+ *
145
+ * @return {PDFStream}
146
+ * @api public
147
+ */
148
+
149
+Canvas.prototype.pdfStream =
150
+Canvas.prototype.createPDFStream = function(){
151
+  return new PDFStream(this);
152
+};
153
+
154
+/**
155
+ * Create a synchronous `PDFStream` for `this` canvas.
156
+ *
157
+ * @return {PDFStream}
158
+ * @api public
159
+ */
160
+
161
+Canvas.prototype.syncPDFStream =
162
+Canvas.prototype.createSyncPDFStream = function(){
163
+  return new PDFStream(this, true);
164
+};
165
+
166
+/**
167
+ * Create a `JPEGStream` for `this` canvas.
168
+ *
169
+ * @param {Object} options
170
+ * @return {JPEGStream}
171
+ * @api public
172
+ */
173
+
174
+Canvas.prototype.jpegStream =
175
+Canvas.prototype.createJPEGStream = function(options){
176
+  return this.createSyncJPEGStream(options);
177
+};
178
+
179
+/**
180
+ * Create a synchronous `JPEGStream` for `this` canvas.
181
+ *
182
+ * @param {Object} options
183
+ * @return {JPEGStream}
184
+ * @api public
185
+ */
186
+
187
+Canvas.prototype.syncJPEGStream =
188
+Canvas.prototype.createSyncJPEGStream = function(options){
189
+  options = options || {};
190
+  // Don't allow the buffer size to exceed the size of the canvas (#674)
191
+  var maxBufSize = this.width * this.height * 4;
192
+  var clampedBufSize = Math.min(options.bufsize || 4096, maxBufSize);
193
+  return new JPEGStream(this, {
194
+      bufsize: clampedBufSize
195
+    , quality: options.quality || 75
196
+    , progressive: options.progressive || false
197
+  });
198
+};
199
+
200
+/**
201
+ * Return a data url. Pass a function for async support (required for "image/jpeg").
202
+ *
203
+ * @param {String} type, optional, one of "image/png" or "image/jpeg", defaults to "image/png"
204
+ * @param {Object|Number} encoderOptions, optional, options for jpeg compression (see documentation for Canvas#jpegStream) or the JPEG encoding quality from 0 to 1.
205
+ * @param {Function} fn, optional, callback for asynchronous operation. Required for type "image/jpeg".
206
+ * @return {String} data URL if synchronous (callback omitted)
207
+ * @api public
208
+ */
209
+
210
+Canvas.prototype.toDataURL = function(a1, a2, a3){
211
+  // valid arg patterns (args -> [type, opts, fn]):
212
+  // [] -> ['image/png', null, null]
213
+  // [qual] -> ['image/png', null, null]
214
+  // [undefined] -> ['image/png', null, null]
215
+  // ['image/png'] -> ['image/png', null, null]
216
+  // ['image/png', qual] -> ['image/png', null, null]
217
+  // [fn] -> ['image/png', null, fn]
218
+  // [type, fn] -> [type, null, fn]
219
+  // [undefined, fn] -> ['image/png', null, fn]
220
+  // ['image/png', qual, fn] -> ['image/png', null, fn]
221
+  // ['image/jpeg', fn] -> ['image/jpeg', null, fn]
222
+  // ['image/jpeg', opts, fn] -> ['image/jpeg', opts, fn]
223
+  // ['image/jpeg', qual, fn] -> ['image/jpeg', {quality: qual}, fn]
224
+  // ['image/jpeg', undefined, fn] -> ['image/jpeg', null, fn]
225
+
226
+  if (this.width === 0 || this.height === 0) {
227
+    // Per spec, if the bitmap has no pixels, return this string:
228
+    return "data:,";
229
+  }
230
+
231
+  var type = 'image/png';
232
+  var opts = {};
233
+  var fn;
234
+
235
+  if ('function' === typeof a1) {
236
+    fn = a1;
237
+  } else {
238
+    if ('string' === typeof a1 && FORMATS.indexOf(a1.toLowerCase()) !== -1) {
239
+      type = a1.toLowerCase();
240
+    }
241
+
242
+    if ('function' === typeof a2) {
243
+      fn = a2;
244
+    } else {
245
+      if ('object' === typeof a2) {
246
+        opts = a2;
247
+      } else if ('number' === typeof a2) {
248
+        opts = {quality: Math.max(0, Math.min(1, a2)) * 100};
249
+      }
250
+
251
+      if ('function' === typeof a3) {
252
+        fn = a3;
253
+      } else if (undefined !== a3) {
254
+        throw new TypeError(typeof a3 + ' is not a function');
255
+      }
256
+    }
257
+  }
258
+
259
+  if ('image/png' === type) {
260
+    if (fn) {
261
+      this.toBuffer(function(err, buf){
262
+        if (err) return fn(err);
263
+        fn(null, 'data:image/png;base64,' + buf.toString('base64'));
264
+      });
265
+    } else {
266
+      return 'data:image/png;base64,' + this.toBuffer().toString('base64');
267
+    }
268
+
269
+  } else if ('image/jpeg' === type) {
270
+    if (undefined === fn) {
271
+      throw new Error('Missing required callback function for format "image/jpeg"');
272
+    }
273
+
274
+    var stream = this.jpegStream(opts);
275
+    // note that jpegStream is synchronous
276
+    var buffers = [];
277
+    stream.on('data', function (chunk) {
278
+      buffers.push(chunk);
279
+    });
280
+    stream.on('error', function (err) {
281
+      fn(err);
282
+    });
283
+    stream.on('end', function() {
284
+      var result = 'data:image/jpeg;base64,' + Buffer.concat(buffers).toString('base64');
285
+      fn(null, result);
286
+    });
287
+  }
288
+};

+ 348 - 0
vendor/canvas/lib/context2d.js Wyświetl plik

@@ -0,0 +1,348 @@
1
+'use strict';
2
+
3
+/*!
4
+ * Canvas - Context2d
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+/**
10
+ * Module dependencies.
11
+ */
12
+
13
+var canvas = require('./bindings')
14
+  , Context2d = canvas.CanvasRenderingContext2d
15
+  , CanvasGradient = canvas.CanvasGradient
16
+  , CanvasPattern = canvas.CanvasPattern
17
+  , ImageData = canvas.ImageData;
18
+
19
+/**
20
+ * Export `Context2d` as the module.
21
+ */
22
+
23
+var Context2d = exports = module.exports = Context2d;
24
+
25
+/**
26
+ * Cache color string RGBA values.
27
+ */
28
+
29
+var cache = {};
30
+
31
+/**
32
+ * Text baselines.
33
+ */
34
+
35
+var baselines = ['alphabetic', 'top', 'bottom', 'middle', 'ideographic', 'hanging'];
36
+
37
+/**
38
+ * Font RegExp helpers.
39
+ */
40
+
41
+var weights = 'normal|bold|bolder|lighter|[1-9]00'
42
+  , styles = 'normal|italic|oblique'
43
+  , units = 'px|pt|pc|in|cm|mm|%'
44
+  , string = '\'([^\']+)\'|"([^"]+)"|[\\w-]+';
45
+
46
+/**
47
+ * Font parser RegExp;
48
+ */
49
+
50
+var fontre = new RegExp('^ *'
51
+  + '(?:(' + weights + ') *)?'
52
+  + '(?:(' + styles + ') *)?'
53
+  + '([\\d\\.]+)(' + units + ') *'
54
+  + '((?:' + string + ')( *, *(?:' + string + '))*)'
55
+  );
56
+
57
+/**
58
+ * Parse font `str`.
59
+ *
60
+ * @param {String} str
61
+ * @return {Object}
62
+ * @api private
63
+ */
64
+
65
+var parseFont = exports.parseFont = function(str){
66
+  var font = {}
67
+    , captures = fontre.exec(str);
68
+
69
+  // Invalid
70
+  if (!captures) return;
71
+
72
+  // Cached
73
+  if (cache[str]) return cache[str];
74
+
75
+  // Populate font object
76
+  font.weight = captures[1] || 'normal';
77
+  font.style = captures[2] || 'normal';
78
+  font.size = parseFloat(captures[3]);
79
+  font.unit = captures[4];
80
+  font.family = captures[5].replace(/["']/g, '').split(',')[0].trim();
81
+
82
+  // TODO: dpi
83
+  // TODO: remaining unit conversion
84
+  switch (font.unit) {
85
+    case 'pt':
86
+      font.size /= .75;
87
+      break;
88
+    case 'in':
89
+      font.size *= 96;
90
+      break;
91
+    case 'mm':
92
+      font.size *= 96.0 / 25.4;
93
+      break;
94
+    case 'cm':
95
+      font.size *= 96.0 / 2.54;
96
+      break;
97
+  }
98
+
99
+  return cache[str] = font;
100
+};
101
+
102
+/**
103
+ * Enable or disable image smoothing.
104
+ *
105
+ * @api public
106
+ */
107
+
108
+Context2d.prototype.__defineSetter__('imageSmoothingEnabled', function(val){
109
+  this._imageSmoothing = !! val;
110
+  this.patternQuality = val ? 'best' : 'fast';
111
+});
112
+
113
+/**
114
+ * Get image smoothing value.
115
+ *
116
+ * @api public
117
+ */
118
+
119
+Context2d.prototype.__defineGetter__('imageSmoothingEnabled', function(val){
120
+  return !! this._imageSmoothing;
121
+});
122
+
123
+/**
124
+ * Create a pattern from `Image` or `Canvas`.
125
+ *
126
+ * @param {Image|Canvas} image
127
+ * @param {String} repetition
128
+ * @return {CanvasPattern}
129
+ * @api public
130
+ */
131
+
132
+Context2d.prototype.createPattern = function(image, repetition){
133
+  // TODO Use repetition (currently always 'repeat')
134
+  return new CanvasPattern(image);
135
+};
136
+
137
+/**
138
+ * Create a linear gradient at the given point `(x0, y0)` and `(x1, y1)`.
139
+ *
140
+ * @param {Number} x0
141
+ * @param {Number} y0
142
+ * @param {Number} x1
143
+ * @param {Number} y1
144
+ * @return {CanvasGradient}
145
+ * @api public
146
+ */
147
+
148
+Context2d.prototype.createLinearGradient = function(x0, y0, x1, y1){
149
+  return new CanvasGradient(x0, y0, x1, y1);
150
+};
151
+
152
+/**
153
+ * Create a radial gradient at the given point `(x0, y0)` and `(x1, y1)`
154
+ * and radius `r0` and `r1`.
155
+ *
156
+ * @param {Number} x0
157
+ * @param {Number} y0
158
+ * @param {Number} r0
159
+ * @param {Number} x1
160
+ * @param {Number} y1
161
+ * @param {Number} r1
162
+ * @return {CanvasGradient}
163
+ * @api public
164
+ */
165
+
166
+Context2d.prototype.createRadialGradient = function(x0, y0, r0, x1, y1, r1){
167
+  return new CanvasGradient(x0, y0, r0, x1, y1, r1);
168
+};
169
+
170
+/**
171
+ * Reset transform matrix to identity, then apply the given args.
172
+ *
173
+ * @param {...}
174
+ * @api public
175
+ */
176
+
177
+Context2d.prototype.setTransform = function(){
178
+  this.resetTransform();
179
+  this.transform.apply(this, arguments);
180
+};
181
+
182
+/**
183
+ * Set the fill style with the given css color string.
184
+ *
185
+ * @api public
186
+ */
187
+
188
+Context2d.prototype.__defineSetter__('fillStyle', function(val){
189
+  if (!val) return;
190
+  if ('CanvasGradient' == val.constructor.name
191
+    || 'CanvasPattern' == val.constructor.name) {
192
+    this.lastFillStyle = val;
193
+    this._setFillPattern(val);
194
+  } else if ('string' == typeof val) {
195
+    this._setFillColor(val);
196
+  }
197
+});
198
+
199
+/**
200
+ * Get previous fill style.
201
+ *
202
+ * @return {CanvasGradient|String}
203
+ * @api public
204
+ */
205
+
206
+Context2d.prototype.__defineGetter__('fillStyle', function(){
207
+  return this.lastFillStyle || this.fillColor;
208
+});
209
+
210
+/**
211
+ * Set the stroke style with the given css color string.
212
+ *
213
+ * @api public
214
+ */
215
+
216
+Context2d.prototype.__defineSetter__('strokeStyle', function(val){
217
+  if (!val) return;
218
+  if ('CanvasGradient' == val.constructor.name
219
+    || 'CanvasPattern' == val.constructor.name) {
220
+    this.lastStrokeStyle = val;
221
+    this._setStrokePattern(val);
222
+  } else if ('string' == typeof val) {
223
+    this._setStrokeColor(val);
224
+  }
225
+});
226
+
227
+/**
228
+ * Get previous stroke style.
229
+ *
230
+ * @return {CanvasGradient|String}
231
+ * @api public
232
+ */
233
+
234
+Context2d.prototype.__defineGetter__('strokeStyle', function(){
235
+  return this.lastStrokeStyle || this.strokeColor;
236
+});
237
+
238
+/**
239
+ * Set font.
240
+ *
241
+ * @see exports.parseFont()
242
+ * @api public
243
+ */
244
+
245
+Context2d.prototype.__defineSetter__('font', function(val){
246
+  if (!val) return;
247
+  if ('string' == typeof val) {
248
+    var font;
249
+    if (font = parseFont(val)) {
250
+      this.lastFontString = val;
251
+      this._setFont(
252
+          font.weight
253
+        , font.style
254
+        , font.size
255
+        , font.unit
256
+        , font.family);
257
+    }
258
+  }
259
+});
260
+
261
+/**
262
+ * Get the current font.
263
+ *
264
+ * @api public
265
+ */
266
+
267
+Context2d.prototype.__defineGetter__('font', function(){
268
+  return this.lastFontString || '10px sans-serif';
269
+});
270
+
271
+/**
272
+ * Set text baseline.
273
+ *
274
+ * @api public
275
+ */
276
+
277
+Context2d.prototype.__defineSetter__('textBaseline', function(val){
278
+  if (!val) return;
279
+  var n = baselines.indexOf(val);
280
+  if (~n) {
281
+    this.lastBaseline = val;
282
+    this._setTextBaseline(n);
283
+  }
284
+});
285
+
286
+/**
287
+ * Get the current baseline setting.
288
+ *
289
+ * @api public
290
+ */
291
+
292
+Context2d.prototype.__defineGetter__('textBaseline', function(){
293
+  return this.lastBaseline || 'alphabetic';
294
+});
295
+
296
+/**
297
+ * Set text alignment.
298
+ *
299
+ * @api public
300
+ */
301
+
302
+Context2d.prototype.__defineSetter__('textAlign', function(val){
303
+  switch (val) {
304
+    case 'center':
305
+      this._setTextAlignment(0);
306
+      this.lastTextAlignment = val;
307
+      break;
308
+    case 'left':
309
+    case 'start':
310
+      this._setTextAlignment(-1);
311
+      this.lastTextAlignment = val;
312
+      break;
313
+    case 'right':
314
+    case 'end':
315
+      this._setTextAlignment(1);
316
+      this.lastTextAlignment = val;
317
+      break;
318
+  }
319
+});
320
+
321
+/**
322
+ * Get the current font.
323
+ *
324
+ * @see exports.parseFont()
325
+ * @api public
326
+ */
327
+
328
+Context2d.prototype.__defineGetter__('textAlign', function(){
329
+  return this.lastTextAlignment || 'start';
330
+});
331
+
332
+/**
333
+ * Create `ImageData` with the given dimensions or
334
+ * `ImageData` instance for dimensions.
335
+ *
336
+ * @param {Number|ImageData} width
337
+ * @param {Number} height
338
+ * @return {ImageData}
339
+ * @api public
340
+ */
341
+
342
+Context2d.prototype.createImageData = function(width, height){
343
+  if ('ImageData' == width.constructor.name) {
344
+    height = width.height;
345
+    width = width.width;
346
+  }
347
+  return new ImageData(new Uint8ClampedArray(width * height * 4), width, height);
348
+};

+ 61 - 0
vendor/canvas/lib/image.js Wyświetl plik

@@ -0,0 +1,61 @@
1
+'use strict';
2
+
3
+/*!
4
+ * Canvas - Image
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+/**
10
+ * Module dependencies.
11
+ */
12
+
13
+var Canvas = require('./bindings')
14
+  , Image = Canvas.Image;
15
+
16
+/**
17
+ * Src setter.
18
+ *
19
+ *  - convert data uri to `Buffer`
20
+ *
21
+ * @param {String|Buffer} val filename, buffer, data uri
22
+ * @api public
23
+ */
24
+
25
+Image.prototype.__defineSetter__('src', function(val){
26
+  if ('string' == typeof val && 0 == val.indexOf('data:')) {
27
+    val = val.slice(val.indexOf(',') + 1);
28
+    this.source = new Buffer(val, 'base64');
29
+  } else {
30
+    this.source = val;
31
+  }
32
+});
33
+
34
+/**
35
+ * Src getter.
36
+ *
37
+ * TODO: return buffer
38
+ *
39
+ * @api public
40
+ */
41
+
42
+Image.prototype.__defineGetter__('src', function(){
43
+  return this.source;
44
+});
45
+
46
+/**
47
+ * Inspect image.
48
+ *
49
+ * TODO: indicate that the .src was a buffer, data uri etc
50
+ *
51
+ * @return {String}
52
+ * @api public
53
+ */
54
+
55
+Image.prototype.inspect = function(){
56
+  return '[Image'
57
+    + (this.complete ? ':' + this.width + 'x' + this.height : '')
58
+    + (this.src ? ' ' + this.src : '')
59
+    + (this.complete ? ' complete' : '')
60
+    + ']';
61
+};

+ 62 - 0
vendor/canvas/lib/jpegstream.js Wyświetl plik

@@ -0,0 +1,62 @@
1
+'use strict';
2
+
3
+/*!
4
+ * Canvas - JPEGStream
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+/**
10
+ * Module dependencies.
11
+ */
12
+
13
+var Stream = require('stream').Stream;
14
+
15
+/**
16
+ * Initialize a `JPEGStream` with the given `canvas`.
17
+ *
18
+ * "data" events are emitted with `Buffer` chunks, once complete the
19
+ * "end" event is emitted. The following example will stream to a file
20
+ * named "./my.jpeg".
21
+ *
22
+ *     var out = fs.createWriteStream(__dirname + '/my.jpeg')
23
+ *       , stream = canvas.createJPEGStream();
24
+ *
25
+ *     stream.pipe(out);
26
+ *
27
+ * @param {Canvas} canvas
28
+ * @param {Boolean} sync
29
+ * @api public
30
+ */
31
+
32
+var JPEGStream = module.exports = function JPEGStream(canvas, options, sync) {
33
+  var self = this
34
+    , method = sync
35
+      ? 'streamJPEGSync'
36
+      : 'streamJPEG';
37
+  this.options = options;
38
+  this.sync = sync;
39
+  this.canvas = canvas;
40
+  this.readable = true;
41
+  // TODO: implement async
42
+  if ('streamJPEG' == method) method = 'streamJPEGSync';
43
+  process.nextTick(function(){
44
+    canvas[method](options.bufsize, options.quality, options.progressive, function(err, chunk){
45
+      if (err) {
46
+        self.emit('error', err);
47
+        self.readable = false;
48
+      } else if (chunk) {
49
+        self.emit('data', chunk);
50
+      } else {
51
+        self.emit('end');
52
+        self.readable = false;
53
+      }
54
+    });
55
+  });
56
+};
57
+
58
+/**
59
+ * Inherit from `EventEmitter`.
60
+ */
61
+
62
+JPEGStream.prototype.__proto__ = Stream.prototype;

+ 59 - 0
vendor/canvas/lib/pdfstream.js Wyświetl plik

@@ -0,0 +1,59 @@
1
+'use strict';
2
+
3
+/*!
4
+ * Canvas - PDFStream
5
+ */
6
+
7
+/**
8
+ * Module dependencies.
9
+ */
10
+
11
+var Stream = require('stream').Stream;
12
+
13
+/**
14
+ * Initialize a `PDFStream` with the given `canvas`.
15
+ *
16
+ * "data" events are emitted with `Buffer` chunks, once complete the
17
+ * "end" event is emitted. The following example will stream to a file
18
+ * named "./my.pdf".
19
+ *
20
+ *     var out = fs.createWriteStream(__dirname + '/my.pdf')
21
+ *       , stream = canvas.createPDFStream();
22
+ *
23
+ *     stream.pipe(out);
24
+ *
25
+ * @param {Canvas} canvas
26
+ * @param {Boolean} sync
27
+ * @api public
28
+ */
29
+
30
+var PDFStream = module.exports = function PDFStream(canvas, sync) {
31
+  var self = this
32
+    , method = sync
33
+      ? 'streamPDFSync'
34
+      : 'streamPDF';
35
+  this.sync = sync;
36
+  this.canvas = canvas;
37
+  this.readable = true;
38
+  // TODO: implement async
39
+  if ('streamPDF' == method) method = 'streamPDFSync';
40
+  process.nextTick(function(){
41
+    canvas[method](function(err, chunk, len){
42
+      if (err) {
43
+        self.emit('error', err);
44
+        self.readable = false;
45
+      } else if (len) {
46
+        self.emit('data', chunk, len);
47
+      } else {
48
+        self.emit('end');
49
+        self.readable = false;
50
+      }
51
+    });
52
+  });
53
+};
54
+
55
+/**
56
+ * Inherit from `EventEmitter`.
57
+ */
58
+
59
+PDFStream.prototype.__proto__ = Stream.prototype;

+ 61 - 0
vendor/canvas/lib/pngstream.js Wyświetl plik

@@ -0,0 +1,61 @@
1
+'use strict';
2
+
3
+/*!
4
+ * Canvas - PNGStream
5
+ * Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+ * MIT Licensed
7
+ */
8
+
9
+/**
10
+ * Module dependencies.
11
+ */
12
+
13
+var Stream = require('stream').Stream;
14
+
15
+/**
16
+ * Initialize a `PNGStream` with the given `canvas`.
17
+ *
18
+ * "data" events are emitted with `Buffer` chunks, once complete the
19
+ * "end" event is emitted. The following example will stream to a file
20
+ * named "./my.png".
21
+ *
22
+ *     var out = fs.createWriteStream(__dirname + '/my.png')
23
+ *       , stream = canvas.createPNGStream();
24
+ *
25
+ *     stream.pipe(out);
26
+ *
27
+ * @param {Canvas} canvas
28
+ * @param {Boolean} sync
29
+ * @api public
30
+ */
31
+
32
+var PNGStream = module.exports = function PNGStream(canvas, sync) {
33
+  var self = this
34
+    , method = sync
35
+      ? 'streamPNGSync'
36
+      : 'streamPNG';
37
+  this.sync = sync;
38
+  this.canvas = canvas;
39
+  this.readable = true;
40
+  // TODO: implement async
41
+  if ('streamPNG' == method) method = 'streamPNGSync';
42
+  process.nextTick(function(){
43
+    canvas[method](function(err, chunk, len){
44
+      if (err) {
45
+        self.emit('error', err);
46
+        self.readable = false;
47
+      } else if (len) {
48
+        self.emit('data', chunk, len);
49
+      } else {
50
+        self.emit('end');
51
+        self.readable = false;
52
+      }
53
+    });
54
+  });
55
+};
56
+
57
+/**
58
+ * Inherit from `EventEmitter`.
59
+ */
60
+
61
+PNGStream.prototype.__proto__ = Stream.prototype;

Plik diff jest za duży
+ 124 - 0
vendor/canvas/package.json


+ 842 - 0
vendor/canvas/src/Canvas.cc Wyświetl plik

@@ -0,0 +1,842 @@
1
+//
2
+// Canvas.cc
3
+//
4
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
5
+//
6
+
7
+#include <assert.h>
8
+#include <stdlib.h>
9
+#include <string.h>
10
+#include <node_buffer.h>
11
+#include <node_version.h>
12
+#include <glib.h>
13
+#include <cairo-pdf.h>
14
+#include <cairo-svg.h>
15
+
16
+#include "Canvas.h"
17
+#include "PNG.h"
18
+#include "CanvasRenderingContext2d.h"
19
+#include "closure.h"
20
+#include "register_font.h"
21
+
22
+#ifdef HAVE_JPEG
23
+#include "JPEGStream.h"
24
+#endif
25
+
26
+#define GENERIC_FACE_ERROR \
27
+  "The second argument to registerFont is required, and should be an object " \
28
+  "with at least a family (string) and optionally weight (string/number) " \
29
+  "and style (string)."
30
+
31
+Nan::Persistent<FunctionTemplate> Canvas::constructor;
32
+
33
+/*
34
+ * Initialize Canvas.
35
+ */
36
+
37
+void
38
+Canvas::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
39
+  Nan::HandleScope scope;
40
+
41
+  // Constructor
42
+  Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Canvas::New);
43
+  constructor.Reset(ctor);
44
+  ctor->InstanceTemplate()->SetInternalFieldCount(1);
45
+  ctor->SetClassName(Nan::New("Canvas").ToLocalChecked());
46
+
47
+  // Prototype
48
+  Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
49
+  Nan::SetPrototypeMethod(ctor, "toBuffer", ToBuffer);
50
+  Nan::SetPrototypeMethod(ctor, "streamPNGSync", StreamPNGSync);
51
+  Nan::SetPrototypeMethod(ctor, "streamPDFSync", StreamPDFSync);
52
+#ifdef HAVE_JPEG
53
+  Nan::SetPrototypeMethod(ctor, "streamJPEGSync", StreamJPEGSync);
54
+#endif
55
+  Nan::SetAccessor(proto, Nan::New("type").ToLocalChecked(), GetType);
56
+  Nan::SetAccessor(proto, Nan::New("stride").ToLocalChecked(), GetStride);
57
+  Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth, SetWidth);
58
+  Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight, SetHeight);
59
+
60
+  Nan::SetTemplate(proto, "PNG_NO_FILTERS", Nan::New<Uint32>(PNG_NO_FILTERS));
61
+  Nan::SetTemplate(proto, "PNG_FILTER_NONE", Nan::New<Uint32>(PNG_FILTER_NONE));
62
+  Nan::SetTemplate(proto, "PNG_FILTER_SUB", Nan::New<Uint32>(PNG_FILTER_SUB));
63
+  Nan::SetTemplate(proto, "PNG_FILTER_UP", Nan::New<Uint32>(PNG_FILTER_UP));
64
+  Nan::SetTemplate(proto, "PNG_FILTER_AVG", Nan::New<Uint32>(PNG_FILTER_AVG));
65
+  Nan::SetTemplate(proto, "PNG_FILTER_PAETH", Nan::New<Uint32>(PNG_FILTER_PAETH));
66
+  Nan::SetTemplate(proto, "PNG_ALL_FILTERS", Nan::New<Uint32>(PNG_ALL_FILTERS));
67
+
68
+  // Class methods
69
+  Nan::SetMethod(ctor, "registerFont", RegisterFont);
70
+
71
+  Nan::Set(target, Nan::New("Canvas").ToLocalChecked(), ctor->GetFunction());
72
+}
73
+
74
+/*
75
+ * Initialize a Canvas with the given width and height.
76
+ */
77
+
78
+NAN_METHOD(Canvas::New) {
79
+  if (!info.IsConstructCall()) {
80
+    return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
81
+  }
82
+
83
+  int width = 0, height = 0;
84
+  canvas_type_t type = CANVAS_TYPE_IMAGE;
85
+  if (info[0]->IsNumber()) width = info[0]->Uint32Value();
86
+  if (info[1]->IsNumber()) height = info[1]->Uint32Value();
87
+  if (info[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(info[2]))
88
+    ? CANVAS_TYPE_PDF
89
+    : !strcmp("svg", *String::Utf8Value(info[2]))
90
+      ? CANVAS_TYPE_SVG
91
+      : CANVAS_TYPE_IMAGE;
92
+  Canvas *canvas = new Canvas(width, height, type);
93
+  canvas->Wrap(info.This());
94
+  info.GetReturnValue().Set(info.This());
95
+}
96
+
97
+/*
98
+ * Get type string.
99
+ */
100
+
101
+NAN_GETTER(Canvas::GetType) {
102
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
103
+  info.GetReturnValue().Set(Nan::New<String>(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image").ToLocalChecked());
104
+}
105
+
106
+/*
107
+ * Get stride.
108
+ */
109
+NAN_GETTER(Canvas::GetStride) {
110
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
111
+  info.GetReturnValue().Set(Nan::New<Number>(canvas->stride()));
112
+}
113
+
114
+/*
115
+ * Get width.
116
+ */
117
+
118
+NAN_GETTER(Canvas::GetWidth) {
119
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
120
+  info.GetReturnValue().Set(Nan::New<Number>(canvas->width));
121
+}
122
+
123
+/*
124
+ * Set width.
125
+ */
126
+
127
+NAN_SETTER(Canvas::SetWidth) {
128
+  if (value->IsNumber()) {
129
+    Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
130
+    canvas->width = value->Uint32Value();
131
+    canvas->resurface(info.This());
132
+  }
133
+}
134
+
135
+/*
136
+ * Get height.
137
+ */
138
+
139
+NAN_GETTER(Canvas::GetHeight) {
140
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
141
+  info.GetReturnValue().Set(Nan::New<Number>(canvas->height));
142
+}
143
+
144
+/*
145
+ * Set height.
146
+ */
147
+
148
+NAN_SETTER(Canvas::SetHeight) {
149
+  if (value->IsNumber()) {
150
+    Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
151
+    canvas->height = value->Uint32Value();
152
+    canvas->resurface(info.This());
153
+  }
154
+}
155
+
156
+/*
157
+ * Canvas::ToBuffer callback.
158
+ */
159
+
160
+static cairo_status_t
161
+toBuffer(void *c, const uint8_t *data, unsigned len) {
162
+  closure_t *closure = (closure_t *) c;
163
+
164
+  if (closure->len + len > closure->max_len) {
165
+    uint8_t *data;
166
+    unsigned max = closure->max_len;
167
+
168
+    do {
169
+      max *= 2;
170
+    } while (closure->len + len > max);
171
+
172
+    data = (uint8_t *) realloc(closure->data, max);
173
+    if (!data) return CAIRO_STATUS_NO_MEMORY;
174
+    closure->data = data;
175
+    closure->max_len = max;
176
+  }
177
+
178
+  memcpy(closure->data + closure->len, data, len);
179
+  closure->len += len;
180
+
181
+  return CAIRO_STATUS_SUCCESS;
182
+}
183
+
184
+/*
185
+ * EIO toBuffer callback.
186
+ */
187
+
188
+#if NODE_VERSION_AT_LEAST(0, 6, 0)
189
+void
190
+Canvas::ToBufferAsync(uv_work_t *req) {
191
+#elif NODE_VERSION_AT_LEAST(0, 5, 4)
192
+void
193
+Canvas::EIO_ToBuffer(eio_req *req) {
194
+#else
195
+int
196
+Canvas::EIO_ToBuffer(eio_req *req) {
197
+#endif
198
+  closure_t *closure = (closure_t *) req->data;
199
+
200
+  closure->status = canvas_write_to_png_stream(
201
+      closure->canvas->surface()
202
+    , toBuffer
203
+    , closure);
204
+
205
+#if !NODE_VERSION_AT_LEAST(0, 5, 4)
206
+  return 0;
207
+#endif
208
+}
209
+
210
+/*
211
+ * EIO after toBuffer callback.
212
+ */
213
+
214
+#if NODE_VERSION_AT_LEAST(0, 6, 0)
215
+void
216
+Canvas::ToBufferAsyncAfter(uv_work_t *req) {
217
+#else
218
+int
219
+Canvas::EIO_AfterToBuffer(eio_req *req) {
220
+#endif
221
+
222
+  Nan::HandleScope scope;
223
+  closure_t *closure = (closure_t *) req->data;
224
+#if NODE_VERSION_AT_LEAST(0, 6, 0)
225
+  delete req;
226
+#else
227
+  ev_unref(EV_DEFAULT_UC);
228
+#endif
229
+
230
+  if (closure->status) {
231
+    Local<Value> argv[1] = { Canvas::Error(closure->status) };
232
+    closure->pfn->Call(1, argv);
233
+  } else {
234
+    Local<Object> buf = Nan::CopyBuffer((char*)closure->data, closure->len).ToLocalChecked();
235
+    memcpy(Buffer::Data(buf), closure->data, closure->len);
236
+    Local<Value> argv[2] = { Nan::Null(), buf };
237
+    closure->pfn->Call(2, argv);
238
+  }
239
+
240
+  closure->canvas->Unref();
241
+  delete closure->pfn;
242
+  closure_destroy(closure);
243
+  free(closure);
244
+
245
+#if !NODE_VERSION_AT_LEAST(0, 6, 0)
246
+  return 0;
247
+#endif
248
+}
249
+
250
+/*
251
+ * Convert PNG data to a node::Buffer, async when a
252
+ * callback function is passed.
253
+ */
254
+
255
+NAN_METHOD(Canvas::ToBuffer) {
256
+  cairo_status_t status;
257
+  uint32_t compression_level = 6;
258
+  uint32_t filter = PNG_ALL_FILTERS;
259
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
260
+
261
+  // TODO: async / move this out
262
+  if (canvas->isPDF() || canvas->isSVG()) {
263
+    cairo_surface_finish(canvas->surface());
264
+    closure_t *closure = (closure_t *) canvas->closure();
265
+
266
+    Local<Object> buf = Nan::CopyBuffer((char*) closure->data, closure->len).ToLocalChecked();
267
+    info.GetReturnValue().Set(buf);
268
+    return;
269
+  }
270
+
271
+  if (info.Length() >= 1 && info[0]->StrictEquals(Nan::New<String>("raw").ToLocalChecked())) {
272
+    // Return raw ARGB data -- just a memcpy()
273
+    cairo_surface_t *surface = canvas->surface();
274
+    cairo_surface_flush(surface);
275
+    const unsigned char *data = cairo_image_surface_get_data(surface);
276
+    Local<Object> buf = Nan::CopyBuffer(reinterpret_cast<const char*>(data), canvas->nBytes()).ToLocalChecked();
277
+    info.GetReturnValue().Set(buf);
278
+    return;
279
+  }
280
+
281
+  if (info.Length() > 1 && !(info[1]->IsUndefined() && info[2]->IsUndefined())) {
282
+    if (!info[1]->IsUndefined()) {
283
+        bool good = true;
284
+        if (info[1]->IsNumber()) {
285
+          compression_level = info[1]->Uint32Value();
286
+        } else if (info[1]->IsString()) {
287
+          if (info[1]->StrictEquals(Nan::New<String>("0").ToLocalChecked())) {
288
+            compression_level = 0;
289
+          } else {
290
+            uint32_t tmp = info[1]->Uint32Value();
291
+            if (tmp == 0) {
292
+              good = false;
293
+            } else {
294
+              compression_level = tmp;
295
+            }
296
+          }
297
+       } else {
298
+         good = false;
299
+       }
300
+
301
+       if (good) {
302
+         if (compression_level > 9) {
303
+           return Nan::ThrowRangeError("Allowed compression levels lie in the range [0, 9].");
304
+         }
305
+       } else {
306
+        return Nan::ThrowTypeError("Compression level must be a number.");
307
+       }
308
+    }
309
+
310
+    if (!info[2]->IsUndefined()) {
311
+      if (info[2]->IsUint32()) {
312
+        filter = info[2]->Uint32Value();
313
+      } else {
314
+        return Nan::ThrowTypeError("Invalid filter value.");
315
+      }
316
+    }
317
+  }
318
+
319
+  // Async
320
+  if (info[0]->IsFunction()) {
321
+    closure_t *closure = (closure_t *) malloc(sizeof(closure_t));
322
+    status = closure_init(closure, canvas, compression_level, filter);
323
+
324
+    // ensure closure is ok
325
+    if (status) {
326
+      closure_destroy(closure);
327
+      free(closure);
328
+      return Nan::ThrowError(Canvas::Error(status));
329
+    }
330
+
331
+    // TODO: only one callback fn in closure
332
+    canvas->Ref();
333
+    closure->pfn = new Nan::Callback(info[0].As<Function>());
334
+
335
+#if NODE_VERSION_AT_LEAST(0, 6, 0)
336
+    uv_work_t* req = new uv_work_t;
337
+    req->data = closure;
338
+    uv_queue_work(uv_default_loop(), req, ToBufferAsync, (uv_after_work_cb)ToBufferAsyncAfter);
339
+#else
340
+    eio_custom(EIO_ToBuffer, EIO_PRI_DEFAULT, EIO_AfterToBuffer, closure);
341
+    ev_ref(EV_DEFAULT_UC);
342
+#endif
343
+
344
+    return;
345
+  // Sync
346
+  } else {
347
+    closure_t closure;
348
+    status = closure_init(&closure, canvas, compression_level, filter);
349
+
350
+    // ensure closure is ok
351
+    if (status) {
352
+      closure_destroy(&closure);
353
+      return Nan::ThrowError(Canvas::Error(status));
354
+    }
355
+
356
+    TryCatch try_catch;
357
+    status = canvas_write_to_png_stream(canvas->surface(), toBuffer, &closure);
358
+
359
+    if (try_catch.HasCaught()) {
360
+      closure_destroy(&closure);
361
+      try_catch.ReThrow();
362
+      return;
363
+    } else if (status) {
364
+      closure_destroy(&closure);
365
+      return Nan::ThrowError(Canvas::Error(status));
366
+    } else {
367
+      Local<Object> buf = Nan::CopyBuffer((char *)closure.data, closure.len).ToLocalChecked();
368
+      closure_destroy(&closure);
369
+      info.GetReturnValue().Set(buf);
370
+      return;
371
+    }
372
+  }
373
+}
374
+
375
+/*
376
+ * Canvas::StreamPNG callback.
377
+ */
378
+
379
+static cairo_status_t
380
+streamPNG(void *c, const uint8_t *data, unsigned len) {
381
+  Nan::HandleScope scope;
382
+  closure_t *closure = (closure_t *) c;
383
+  Local<Object> buf = Nan::CopyBuffer((char *)data, len).ToLocalChecked();
384
+  Local<Value> argv[3] = {
385
+      Nan::Null()
386
+    , buf
387
+    , Nan::New<Number>(len) };
388
+  Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure->fn, 3, argv);
389
+  return CAIRO_STATUS_SUCCESS;
390
+}
391
+
392
+/*
393
+ * Stream PNG data synchronously.
394
+ */
395
+
396
+NAN_METHOD(Canvas::StreamPNGSync) {
397
+  uint32_t compression_level = 6;
398
+  uint32_t filter = PNG_ALL_FILTERS;
399
+  // TODO: async as well
400
+  if (!info[0]->IsFunction())
401
+    return Nan::ThrowTypeError("callback function required");
402
+
403
+  if (info.Length() > 1 && !(info[1]->IsUndefined() && info[2]->IsUndefined())) {
404
+    if (!info[1]->IsUndefined()) {
405
+        bool good = true;
406
+        if (info[1]->IsNumber()) {
407
+          compression_level = info[1]->Uint32Value();
408
+        } else if (info[1]->IsString()) {
409
+          if (info[1]->StrictEquals(Nan::New<String>("0").ToLocalChecked())) {
410
+            compression_level = 0;
411
+          } else {
412
+            uint32_t tmp = info[1]->Uint32Value();
413
+            if (tmp == 0) {
414
+              good = false;
415
+            } else {
416
+              compression_level = tmp;
417
+            }
418
+          }
419
+       } else {
420
+         good = false;
421
+       }
422
+
423
+       if (good) {
424
+         if (compression_level > 9) {
425
+           return Nan::ThrowRangeError("Allowed compression levels lie in the range [0, 9].");
426
+         }
427
+       } else {
428
+        return Nan::ThrowTypeError("Compression level must be a number.");
429
+       }
430
+    }
431
+
432
+    if (!info[2]->IsUndefined()) {
433
+      if (info[2]->IsUint32()) {
434
+        filter = info[2]->Uint32Value();
435
+      } else {
436
+        return Nan::ThrowTypeError("Invalid filter value.");
437
+      }
438
+    }
439
+  }
440
+
441
+
442
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
443
+  closure_t closure;
444
+  closure.fn = Local<Function>::Cast(info[0]);
445
+  closure.compression_level = compression_level;
446
+  closure.filter = filter;
447
+
448
+  TryCatch try_catch;
449
+
450
+  cairo_status_t status = canvas_write_to_png_stream(canvas->surface(), streamPNG, &closure);
451
+
452
+  if (try_catch.HasCaught()) {
453
+    try_catch.ReThrow();
454
+    return;
455
+  } else if (status) {
456
+    Local<Value> argv[1] = { Canvas::Error(status) };
457
+    Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
458
+  } else {
459
+    Local<Value> argv[3] = {
460
+        Nan::Null()
461
+      , Nan::Null()
462
+      , Nan::New<Uint32>(0) };
463
+    Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)closure.fn, 1, argv);
464
+  }
465
+  return;
466
+}
467
+
468
+/*
469
+ * Canvas::StreamPDF FreeCallback
470
+ */
471
+
472
+void stream_pdf_free(char *, void *) {}
473
+
474
+/*
475
+ * Canvas::StreamPDF callback.
476
+ */
477
+
478
+static cairo_status_t
479
+streamPDF(void *c, const uint8_t *data, unsigned len) {
480
+  Nan::HandleScope scope;
481
+  closure_t *closure = static_cast<closure_t *>(c);
482
+  Local<Object> buf = Nan::NewBuffer(const_cast<char *>(reinterpret_cast<const char *>(data)), len, stream_pdf_free, 0).ToLocalChecked();
483
+  Local<Value> argv[3] = {
484
+      Nan::Null()
485
+    , buf
486
+    , Nan::New<Number>(len) };
487
+  Nan::MakeCallback(Nan::GetCurrentContext()->Global(), closure->fn, 3, argv);
488
+  return CAIRO_STATUS_SUCCESS;
489
+}
490
+
491
+
492
+cairo_status_t canvas_write_to_pdf_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) {
493
+  closure_t *pdf_closure = static_cast<closure_t *>(closure);
494
+  size_t whole_chunks = pdf_closure->len / PAGE_SIZE;
495
+  size_t remainder = pdf_closure->len - whole_chunks * PAGE_SIZE;
496
+
497
+  for (size_t i = 0; i < whole_chunks; ++i) {
498
+    write_func(pdf_closure, &pdf_closure->data[i * PAGE_SIZE], PAGE_SIZE);
499
+  }
500
+
501
+  if (remainder) {
502
+    write_func(pdf_closure, &pdf_closure->data[whole_chunks * PAGE_SIZE], remainder);
503
+  }
504
+
505
+  return CAIRO_STATUS_SUCCESS;
506
+}
507
+
508
+/*
509
+ * Stream PDF data synchronously.
510
+ */
511
+
512
+NAN_METHOD(Canvas::StreamPDFSync) {
513
+  if (!info[0]->IsFunction())
514
+    return Nan::ThrowTypeError("callback function required");
515
+
516
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.Holder());
517
+
518
+  if (!canvas->isPDF())
519
+    return Nan::ThrowTypeError("wrong canvas type");
520
+
521
+  cairo_surface_finish(canvas->surface());
522
+
523
+  closure_t closure;
524
+  closure.data = static_cast<closure_t *>(canvas->closure())->data;
525
+  closure.len = static_cast<closure_t *>(canvas->closure())->len;
526
+  closure.fn = info[0].As<Function>();
527
+
528
+  Nan::TryCatch try_catch;
529
+
530
+  cairo_status_t status = canvas_write_to_pdf_stream(canvas->surface(), streamPDF, &closure);
531
+
532
+  if (try_catch.HasCaught()) {
533
+    try_catch.ReThrow();
534
+  } else if (status) {
535
+    Local<Value> error = Canvas::Error(status);
536
+    Nan::Call(closure.fn, Nan::GetCurrentContext()->Global(), 1, &error);
537
+  } else {
538
+    Local<Value> argv[3] = {
539
+        Nan::Null()
540
+      , Nan::Null()
541
+      , Nan::New<Uint32>(0) };
542
+    Nan::Call(closure.fn, Nan::GetCurrentContext()->Global(), 3, argv);
543
+  }
544
+}
545
+
546
+/*
547
+ * Stream JPEG data synchronously.
548
+ */
549
+
550
+#ifdef HAVE_JPEG
551
+
552
+NAN_METHOD(Canvas::StreamJPEGSync) {
553
+  // TODO: async as well
554
+  if (!info[0]->IsNumber())
555
+    return Nan::ThrowTypeError("buffer size required");
556
+  if (!info[1]->IsNumber())
557
+    return Nan::ThrowTypeError("quality setting required");
558
+  if (!info[2]->IsBoolean())
559
+    return Nan::ThrowTypeError("progressive setting required");
560
+  if (!info[3]->IsFunction())
561
+    return Nan::ThrowTypeError("callback function required");
562
+
563
+  Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(info.This());
564
+  closure_t closure;
565
+  closure.fn = Local<Function>::Cast(info[3]);
566
+
567
+  TryCatch try_catch;
568
+  write_to_jpeg_stream(canvas->surface(), info[0]->NumberValue(), info[1]->NumberValue(), info[2]->BooleanValue(), &closure);
569
+
570
+  if (try_catch.HasCaught()) {
571
+    try_catch.ReThrow();
572
+  }
573
+  return;
574
+}
575
+
576
+#endif
577
+
578
+NAN_METHOD(Canvas::RegisterFont) {
579
+  FontFace face;
580
+
581
+  if (!info[0]->IsString()) {
582
+    return Nan::ThrowError("Wrong argument type");
583
+  }
584
+
585
+  String::Utf8Value filePath(info[0]);
586
+
587
+  if (!register_font((unsigned char*) *filePath, &face.target_desc)) {
588
+    Nan::ThrowError("Could not load font to the system's font host");
589
+  } else {
590
+    PangoFontDescription* d = pango_font_description_new();
591
+
592
+    if (!info[1]->IsObject()) {
593
+      Nan::ThrowError(GENERIC_FACE_ERROR);
594
+    } else { // now check the attrs, there are many ways to be wrong
595
+      Local<Object> desc = info[1]->ToObject();
596
+      Local<String> family_prop = Nan::New<String>("family").ToLocalChecked();
597
+      Local<String> weight_prop = Nan::New<String>("weight").ToLocalChecked();
598
+      Local<String> style_prop = Nan::New<String>("style").ToLocalChecked();
599
+
600
+      const char* family;
601
+      const char* weight = "normal";
602
+      const char* style = "normal";
603
+
604
+      Local<Value> family_val = desc->Get(family_prop);
605
+      if (family_val->IsString()) {
606
+        family = strdup(*String::Utf8Value(family_val));
607
+      } else {
608
+        Nan::ThrowError(GENERIC_FACE_ERROR);
609
+        return;
610
+      }
611
+
612
+      if (desc->HasOwnProperty(weight_prop)) {
613
+        Local<Value> weight_val = desc->Get(weight_prop);
614
+        if (weight_val->IsString() || weight_val->IsNumber()) {
615
+          weight = strdup(*String::Utf8Value(weight_val));
616
+        } else {
617
+          Nan::ThrowError(GENERIC_FACE_ERROR);
618
+          return;
619
+        }
620
+      }
621
+
622
+      if (desc->HasOwnProperty(style_prop)) {
623
+        Local<Value> style_val = desc->Get(style_prop);
624
+        if (style_val->IsString()) {
625
+          style = strdup(*String::Utf8Value(style_val));
626
+        } else {
627
+          Nan::ThrowError(GENERIC_FACE_ERROR);
628
+          return;
629
+        }
630
+      }
631
+
632
+      pango_font_description_set_weight(d, Canvas::GetWeightFromCSSString(weight));
633
+      pango_font_description_set_style(d, Canvas::GetStyleFromCSSString(style));
634
+      pango_font_description_set_family(d, family);
635
+
636
+      free((char*)family);
637
+      if (desc->HasOwnProperty(weight_prop)) free((char*)weight);
638
+      if (desc->HasOwnProperty(style_prop)) free((char*)style);
639
+
640
+      face.user_desc = d;
641
+      _font_face_list.push_back(face);
642
+    }
643
+  }
644
+}
645
+
646
+/*
647
+ * Initialize cairo surface.
648
+ */
649
+
650
+Canvas::Canvas(int w, int h, canvas_type_t t): Nan::ObjectWrap() {
651
+  type = t;
652
+  width = w;
653
+  height = h;
654
+  _surface = NULL;
655
+  _closure = NULL;
656
+
657
+  if (CANVAS_TYPE_PDF == t) {
658
+    _closure = malloc(sizeof(closure_t));
659
+    assert(_closure);
660
+    cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS);
661
+    assert(status == CAIRO_STATUS_SUCCESS);
662
+    _surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h);
663
+  } else if (CANVAS_TYPE_SVG == t) {
664
+    _closure = malloc(sizeof(closure_t));
665
+    assert(_closure);
666
+    cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS);
667
+    assert(status == CAIRO_STATUS_SUCCESS);
668
+    _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, w, h);
669
+  } else {
670
+    _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h);
671
+    assert(_surface);
672
+    Nan::AdjustExternalMemory(nBytes());
673
+  }
674
+}
675
+
676
+/*
677
+ * Destroy cairo surface.
678
+ */
679
+
680
+Canvas::~Canvas() {
681
+  switch (type) {
682
+    case CANVAS_TYPE_PDF:
683
+    case CANVAS_TYPE_SVG:
684
+      cairo_surface_finish(_surface);
685
+      closure_destroy((closure_t *) _closure);
686
+      free(_closure);
687
+      cairo_surface_destroy(_surface);
688
+      break;
689
+    case CANVAS_TYPE_IMAGE:
690
+      int oldNBytes = nBytes();
691
+      cairo_surface_destroy(_surface);
692
+      Nan::AdjustExternalMemory(-oldNBytes);
693
+      break;
694
+  }
695
+}
696
+
697
+std::vector<FontFace>
698
+_init_font_face_list() {
699
+  std::vector<FontFace> x;
700
+  return x;
701
+}
702
+
703
+std::vector<FontFace> Canvas::_font_face_list = _init_font_face_list();
704
+
705
+/*
706
+ * Get a PangoStyle from a CSS string (like "italic")
707
+ */
708
+
709
+PangoStyle
710
+Canvas::GetStyleFromCSSString(const char *style) {
711
+  PangoStyle s = PANGO_STYLE_NORMAL;
712
+
713
+  if (strlen(style) > 0) {
714
+    if (0 == strcmp("italic", style)) {
715
+      s = PANGO_STYLE_ITALIC;
716
+    } else if (0 == strcmp("oblique", style)) {
717
+      s = PANGO_STYLE_OBLIQUE;
718
+    }
719
+  }
720
+
721
+  return s;
722
+}
723
+
724
+/*
725
+ * Get a PangoWeight from a CSS string ("bold", "100", etc)
726
+ */
727
+
728
+PangoWeight
729
+Canvas::GetWeightFromCSSString(const char *weight) {
730
+  PangoWeight w = PANGO_WEIGHT_NORMAL;
731
+
732
+  if (strlen(weight) > 0) {
733
+    if (0 == strcmp("bold", weight)) {
734
+      w = PANGO_WEIGHT_BOLD;
735
+    } else if (0 == strcmp("100", weight)) {
736
+      w = PANGO_WEIGHT_THIN;
737
+    } else if (0 == strcmp("200", weight)) {
738
+      w = PANGO_WEIGHT_ULTRALIGHT;
739
+    } else if (0 == strcmp("300", weight)) {
740
+      w = PANGO_WEIGHT_LIGHT;
741
+    } else if (0 == strcmp("400", weight)) {
742
+      w = PANGO_WEIGHT_NORMAL;
743
+    } else if (0 == strcmp("500", weight)) {
744
+      w = PANGO_WEIGHT_MEDIUM;
745
+    } else if (0 == strcmp("600", weight)) {
746
+      w = PANGO_WEIGHT_SEMIBOLD;
747
+    } else if (0 == strcmp("700", weight)) {
748
+      w = PANGO_WEIGHT_BOLD;
749
+    } else if (0 == strcmp("800", weight)) {
750
+      w = PANGO_WEIGHT_ULTRABOLD;
751
+    } else if (0 == strcmp("900", weight)) {
752
+      w = PANGO_WEIGHT_HEAVY;
753
+    }
754
+  }
755
+
756
+  return w;
757
+}
758
+
759
+/*
760
+ * Tries to find a matching font given to registerFont
761
+ */
762
+
763
+PangoFontDescription *
764
+Canvas::FindCustomFace(PangoFontDescription *desc) {
765
+  PangoFontDescription* best_match = NULL;
766
+  PangoFontDescription* best_match_target = NULL;
767
+  std::vector<FontFace>::iterator it = _font_face_list.begin();
768
+
769
+  while (it != _font_face_list.end()) {
770
+    FontFace f = *it;
771
+
772
+    if (g_ascii_strcasecmp(pango_font_description_get_family(desc),
773
+      pango_font_description_get_family(f.user_desc)) == 0) {
774
+
775
+      if (best_match == NULL || pango_font_description_better_match(desc, best_match, f.user_desc)) {
776
+        best_match = f.user_desc;
777
+        best_match_target = f.target_desc;
778
+      }
779
+    }
780
+
781
+    ++it;
782
+  }
783
+
784
+  return best_match_target;
785
+}
786
+
787
+/*
788
+ * Re-alloc the surface, destroying the previous.
789
+ */
790
+
791
+void
792
+Canvas::resurface(Local<Object> canvas) {
793
+  Nan::HandleScope scope;
794
+  Local<Value> context;
795
+  switch (type) {
796
+    case CANVAS_TYPE_PDF:
797
+      cairo_pdf_surface_set_size(_surface, width, height);
798
+      break;
799
+    case CANVAS_TYPE_SVG:
800
+      // Re-surface
801
+      cairo_surface_finish(_surface);
802
+      closure_destroy((closure_t *) _closure);
803
+      cairo_surface_destroy(_surface);
804
+      closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS);
805
+      _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height);
806
+
807
+      // Reset context
808
+      context = canvas->Get(Nan::New<String>("context").ToLocalChecked());
809
+      if (!context->IsUndefined()) {
810
+        Context2d *context2d = Nan::ObjectWrap::Unwrap<Context2d>(context->ToObject());
811
+        cairo_t *prev = context2d->context();
812
+        context2d->setContext(cairo_create(surface()));
813
+        cairo_destroy(prev);
814
+      }
815
+      break;
816
+    case CANVAS_TYPE_IMAGE:
817
+      // Re-surface
818
+      size_t oldNBytes = nBytes();
819
+      cairo_surface_destroy(_surface);
820
+      _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
821
+      Nan::AdjustExternalMemory(nBytes() - oldNBytes);
822
+
823
+      // Reset context
824
+      context = canvas->Get(Nan::New<String>("context").ToLocalChecked());
825
+      if (!context->IsUndefined()) {
826
+        Context2d *context2d = Nan::ObjectWrap::Unwrap<Context2d>(context->ToObject());
827
+        cairo_t *prev = context2d->context();
828
+        context2d->setContext(cairo_create(surface()));
829
+        cairo_destroy(prev);
830
+      }
831
+      break;
832
+  }
833
+}
834
+
835
+/*
836
+ * Construct an Error from the given cairo status.
837
+ */
838
+
839
+Local<Value>
840
+Canvas::Error(cairo_status_t status) {
841
+  return Exception::Error(Nan::New<String>(cairo_status_to_string(status)).ToLocalChecked());
842
+}

+ 111 - 0
vendor/canvas/src/Canvas.h Wyświetl plik

@@ -0,0 +1,111 @@
1
+
2
+//
3
+// Canvas.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_CANVAS_H__
9
+#define __NODE_CANVAS_H__
10
+
11
+#include <node.h>
12
+#include <v8.h>
13
+#include <node_object_wrap.h>
14
+#include <node_version.h>
15
+#include <pango/pangocairo.h>
16
+#include <vector>
17
+#include <cairo.h>
18
+#include <nan.h>
19
+
20
+
21
+using namespace node;
22
+using namespace v8;
23
+
24
+/*
25
+ * Maxmimum states per context.
26
+ * TODO: remove/resize
27
+ */
28
+
29
+#ifndef CANVAS_MAX_STATES
30
+#define CANVAS_MAX_STATES 64
31
+#endif
32
+
33
+/*
34
+ * Canvas types.
35
+ */
36
+
37
+typedef enum {
38
+  CANVAS_TYPE_IMAGE,
39
+  CANVAS_TYPE_PDF,
40
+  CANVAS_TYPE_SVG
41
+} canvas_type_t;
42
+
43
+/**
44
+ * FontFace describes a font file in terms of one PangoFontDescription that
45
+ * will resolve to it and one that the user describes it as (like @font-face)
46
+ */
47
+class FontFace {
48
+  public:
49
+    PangoFontDescription *target_desc;
50
+    PangoFontDescription *user_desc;
51
+};
52
+
53
+/*
54
+ * Canvas.
55
+ */
56
+
57
+class Canvas: public Nan::ObjectWrap {
58
+  public:
59
+    int width;
60
+    int height;
61
+    canvas_type_t type;
62
+    static Nan::Persistent<FunctionTemplate> constructor;
63
+    static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
64
+    static NAN_METHOD(New);
65
+    static NAN_METHOD(ToBuffer);
66
+    static NAN_GETTER(GetType);
67
+    static NAN_GETTER(GetStride);
68
+    static NAN_GETTER(GetWidth);
69
+    static NAN_GETTER(GetHeight);
70
+    static NAN_SETTER(SetWidth);
71
+    static NAN_SETTER(SetHeight);
72
+    static NAN_METHOD(StreamPNGSync);
73
+    static NAN_METHOD(StreamPDFSync);
74
+    static NAN_METHOD(StreamJPEGSync);
75
+    static NAN_METHOD(RegisterFont);
76
+    static Local<Value> Error(cairo_status_t status);
77
+#if NODE_VERSION_AT_LEAST(0, 6, 0)
78
+    static void ToBufferAsync(uv_work_t *req);
79
+    static void ToBufferAsyncAfter(uv_work_t *req);
80
+#else
81
+    static
82
+#if NODE_VERSION_AT_LEAST(0, 5, 4)
83
+      void
84
+#else
85
+      int
86
+#endif
87
+      EIO_ToBuffer(eio_req *req);
88
+    static int EIO_AfterToBuffer(eio_req *req);
89
+#endif
90
+    static PangoWeight GetWeightFromCSSString(const char *weight);
91
+    static PangoStyle GetStyleFromCSSString(const char *style);
92
+    static PangoFontDescription* FindCustomFace(PangoFontDescription *desc);
93
+
94
+    inline bool isPDF(){ return CANVAS_TYPE_PDF == type; }
95
+    inline bool isSVG(){ return CANVAS_TYPE_SVG == type; }
96
+    inline cairo_surface_t *surface(){ return _surface; }
97
+    inline void *closure(){ return _closure; }
98
+    inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
99
+    inline int stride(){ return cairo_image_surface_get_stride(_surface); }
100
+    inline int nBytes(){ return height * stride(); }
101
+    Canvas(int width, int height, canvas_type_t type);
102
+    void resurface(Local<Object> canvas);
103
+
104
+  private:
105
+    ~Canvas();
106
+    cairo_surface_t *_surface;
107
+    void *_closure;
108
+    static std::vector<FontFace> _font_face_list;
109
+};
110
+
111
+#endif

+ 122 - 0
vendor/canvas/src/CanvasGradient.cc Wyświetl plik

@@ -0,0 +1,122 @@
1
+
2
+//
3
+// Gradient.cc
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#include "color.h"
9
+#include "Canvas.h"
10
+#include "CanvasGradient.h"
11
+
12
+Nan::Persistent<FunctionTemplate> Gradient::constructor;
13
+
14
+/*
15
+ * Initialize CanvasGradient.
16
+ */
17
+
18
+void
19
+Gradient::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
20
+  Nan::HandleScope scope;
21
+
22
+  // Constructor
23
+  Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Gradient::New);
24
+  constructor.Reset(ctor);
25
+  ctor->InstanceTemplate()->SetInternalFieldCount(1);
26
+  ctor->SetClassName(Nan::New("CanvasGradient").ToLocalChecked());
27
+
28
+  // Prototype
29
+  Nan::SetPrototypeMethod(ctor, "addColorStop", AddColorStop);
30
+  Nan::Set(target, Nan::New("CanvasGradient").ToLocalChecked(), ctor->GetFunction());
31
+}
32
+
33
+/*
34
+ * Initialize a new CanvasGradient.
35
+ */
36
+
37
+NAN_METHOD(Gradient::New) {
38
+  if (!info.IsConstructCall()) {
39
+    return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
40
+  }
41
+
42
+  // Linear
43
+  if (4 == info.Length()) {
44
+    Gradient *grad = new Gradient(
45
+        info[0]->NumberValue()
46
+      , info[1]->NumberValue()
47
+      , info[2]->NumberValue()
48
+      , info[3]->NumberValue());
49
+    grad->Wrap(info.This());
50
+    info.GetReturnValue().Set(info.This());
51
+    return;
52
+  }
53
+
54
+  // Radial
55
+  if (6 == info.Length()) {
56
+    Gradient *grad = new Gradient(
57
+        info[0]->NumberValue()
58
+      , info[1]->NumberValue()
59
+      , info[2]->NumberValue()
60
+      , info[3]->NumberValue()
61
+      , info[4]->NumberValue()
62
+      , info[5]->NumberValue());
63
+    grad->Wrap(info.This());
64
+    info.GetReturnValue().Set(info.This());
65
+    return;
66
+  }
67
+
68
+  return Nan::ThrowTypeError("invalid arguments");
69
+}
70
+
71
+/*
72
+ * Add color stop.
73
+ */
74
+
75
+NAN_METHOD(Gradient::AddColorStop) {
76
+  if (!info[0]->IsNumber())
77
+    return Nan::ThrowTypeError("offset required");
78
+  if (!info[1]->IsString())
79
+    return Nan::ThrowTypeError("color string required");
80
+
81
+  Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(info.This());
82
+  short ok;
83
+  String::Utf8Value str(info[1]);
84
+  uint32_t rgba = rgba_from_string(*str, &ok);
85
+
86
+  if (ok) {
87
+    rgba_t color = rgba_create(rgba);
88
+    cairo_pattern_add_color_stop_rgba(
89
+        grad->pattern()
90
+      , info[0]->NumberValue()
91
+      , color.r
92
+      , color.g
93
+      , color.b
94
+      , color.a);
95
+  } else {
96
+    return Nan::ThrowTypeError("parse color failed");
97
+  }
98
+}
99
+
100
+/*
101
+ * Initialize linear gradient.
102
+ */
103
+
104
+Gradient::Gradient(double x0, double y0, double x1, double y1) {
105
+  _pattern = cairo_pattern_create_linear(x0, y0, x1, y1);
106
+}
107
+
108
+/*
109
+ * Initialize radial gradient.
110
+ */
111
+
112
+Gradient::Gradient(double x0, double y0, double r0, double x1, double y1, double r1) {
113
+  _pattern = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1);
114
+}
115
+
116
+/*
117
+ * Destroy the pattern.
118
+ */
119
+
120
+Gradient::~Gradient() {
121
+  cairo_pattern_destroy(_pattern);
122
+}

+ 28 - 0
vendor/canvas/src/CanvasGradient.h Wyświetl plik

@@ -0,0 +1,28 @@
1
+
2
+//
3
+// CanvasGradient.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_GRADIENT_H__
9
+#define __NODE_GRADIENT_H__
10
+
11
+#include "Canvas.h"
12
+
13
+class Gradient: public Nan::ObjectWrap {
14
+  public:
15
+    static Nan::Persistent<FunctionTemplate> constructor;
16
+    static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
17
+    static NAN_METHOD(New);
18
+    static NAN_METHOD(AddColorStop);
19
+    Gradient(double x0, double y0, double x1, double y1);
20
+    Gradient(double x0, double y0, double r0, double x1, double y1, double r1);
21
+    inline cairo_pattern_t *pattern(){ return _pattern; }
22
+
23
+  private:
24
+    ~Gradient();
25
+    cairo_pattern_t *_pattern;
26
+};
27
+
28
+#endif

+ 86 - 0
vendor/canvas/src/CanvasPattern.cc Wyświetl plik

@@ -0,0 +1,86 @@
1
+
2
+//
3
+// Pattern.cc
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#include "Canvas.h"
9
+#include "Image.h"
10
+#include "CanvasPattern.h"
11
+
12
+Nan::Persistent<FunctionTemplate> Pattern::constructor;
13
+
14
+/*
15
+ * Initialize CanvasPattern.
16
+ */
17
+
18
+void
19
+Pattern::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
20
+  Nan::HandleScope scope;
21
+
22
+  // Constructor
23
+  Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Pattern::New);
24
+  constructor.Reset(ctor);
25
+  ctor->InstanceTemplate()->SetInternalFieldCount(1);
26
+  ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
27
+
28
+  ctor->InstanceTemplate()->SetInternalFieldCount(1);
29
+  ctor->SetClassName(Nan::New("CanvasPattern").ToLocalChecked());
30
+
31
+  // Prototype
32
+  Nan::Set(target, Nan::New("CanvasPattern").ToLocalChecked(), ctor->GetFunction());
33
+}
34
+
35
+/*
36
+ * Initialize a new CanvasPattern.
37
+ */
38
+
39
+NAN_METHOD(Pattern::New) {
40
+  if (!info.IsConstructCall()) {
41
+    return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
42
+  }
43
+
44
+  cairo_surface_t *surface;
45
+
46
+  Local<Object> obj = info[0]->ToObject();
47
+
48
+  // Image
49
+  if (Nan::New(Image::constructor)->HasInstance(obj)) {
50
+    Image *img = Nan::ObjectWrap::Unwrap<Image>(obj);
51
+    if (!img->isComplete()) {
52
+      return Nan::ThrowError("Image given has not completed loading");
53
+    }
54
+    surface = img->surface();
55
+
56
+  // Canvas
57
+  } else if (Nan::New(Canvas::constructor)->HasInstance(obj)) {
58
+    Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
59
+    surface = canvas->surface();
60
+
61
+  // Invalid
62
+  } else {
63
+    return Nan::ThrowTypeError("Image or Canvas expected");
64
+  }
65
+
66
+  Pattern *pattern = new Pattern(surface);
67
+  pattern->Wrap(info.This());
68
+  info.GetReturnValue().Set(info.This());
69
+}
70
+
71
+
72
+/*
73
+ * Initialize linear gradient.
74
+ */
75
+
76
+Pattern::Pattern(cairo_surface_t *surface) {
77
+  _pattern = cairo_pattern_create_for_surface(surface);
78
+}
79
+
80
+/*
81
+ * Destroy the pattern.
82
+ */
83
+
84
+Pattern::~Pattern() {
85
+  cairo_pattern_destroy(_pattern);
86
+}

+ 27 - 0
vendor/canvas/src/CanvasPattern.h Wyświetl plik

@@ -0,0 +1,27 @@
1
+
2
+//
3
+// CanvasPattern.h
4
+//
5
+// Copyright (c) 2011 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_PATTERN_H__
9
+#define __NODE_PATTERN_H__
10
+
11
+#include "Canvas.h"
12
+
13
+class Pattern: public Nan::ObjectWrap {
14
+  public:
15
+    static Nan::Persistent<FunctionTemplate> constructor;
16
+    static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
17
+    static NAN_METHOD(New);
18
+    Pattern(cairo_surface_t *surface);
19
+    inline cairo_pattern_t *pattern(){ return _pattern; }
20
+
21
+  private:
22
+    ~Pattern();
23
+    // TODO REPEAT/REPEAT_X/REPEAT_Y
24
+    cairo_pattern_t *_pattern;
25
+};
26
+
27
+#endif

Plik diff jest za duży
+ 2227 - 0
vendor/canvas/src/CanvasRenderingContext2d.cc


+ 164 - 0
vendor/canvas/src/CanvasRenderingContext2d.h Wyświetl plik

@@ -0,0 +1,164 @@
1
+
2
+//
3
+// CanvasRenderingContext2d.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_CONTEXT2D_H__
9
+#define __NODE_CONTEXT2D_H__
10
+
11
+#include <vector>
12
+#include <pango/pangocairo.h>
13
+
14
+#include "color.h"
15
+#include "Canvas.h"
16
+#include "CanvasGradient.h"
17
+
18
+using namespace std;
19
+
20
+typedef enum {
21
+  TEXT_DRAW_PATHS,
22
+  TEXT_DRAW_GLYPHS
23
+} canvas_draw_mode_t;
24
+
25
+/*
26
+ * State struct.
27
+ *
28
+ * Used in conjunction with Save() / Restore() since
29
+ * cairo's gstate maintains only a single source pattern at a time.
30
+ */
31
+
32
+typedef struct {
33
+  rgba_t fill;
34
+  rgba_t stroke;
35
+  cairo_filter_t patternQuality;
36
+  cairo_pattern_t *fillPattern;
37
+  cairo_pattern_t *strokePattern;
38
+  cairo_pattern_t *fillGradient;
39
+  cairo_pattern_t *strokeGradient;
40
+  float globalAlpha;
41
+  short textAlignment;
42
+  short textBaseline;
43
+  rgba_t shadow;
44
+  int shadowBlur;
45
+  double shadowOffsetX;
46
+  double shadowOffsetY;
47
+  canvas_draw_mode_t textDrawingMode;
48
+  PangoFontDescription *fontDescription;
49
+} canvas_state_t;
50
+
51
+void state_assign_fontFamily(canvas_state_t *state, const char *str);
52
+
53
+class Context2d: public Nan::ObjectWrap {
54
+  public:
55
+    short stateno;
56
+    canvas_state_t *states[CANVAS_MAX_STATES];
57
+    canvas_state_t *state;
58
+    Context2d(Canvas *canvas);
59
+    static Nan::Persistent<FunctionTemplate> constructor;
60
+    static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
61
+    static NAN_METHOD(New);
62
+    static NAN_METHOD(DrawImage);
63
+    static NAN_METHOD(PutImageData);
64
+    static NAN_METHOD(Save);
65
+    static NAN_METHOD(Restore);
66
+    static NAN_METHOD(Rotate);
67
+    static NAN_METHOD(Translate);
68
+    static NAN_METHOD(Scale);
69
+    static NAN_METHOD(Transform);
70
+    static NAN_METHOD(ResetTransform);
71
+    static NAN_METHOD(IsPointInPath);
72
+    static NAN_METHOD(BeginPath);
73
+    static NAN_METHOD(ClosePath);
74
+    static NAN_METHOD(AddPage);
75
+    static NAN_METHOD(Clip);
76
+    static NAN_METHOD(Fill);
77
+    static NAN_METHOD(Stroke);
78
+    static NAN_METHOD(FillText);
79
+    static NAN_METHOD(StrokeText);
80
+    static NAN_METHOD(SetFont);
81
+    static NAN_METHOD(SetFillColor);
82
+    static NAN_METHOD(SetStrokeColor);
83
+    static NAN_METHOD(SetFillPattern);
84
+    static NAN_METHOD(SetStrokePattern);
85
+    static NAN_METHOD(SetTextBaseline);
86
+    static NAN_METHOD(SetTextAlignment);
87
+    static NAN_METHOD(SetLineDash);
88
+    static NAN_METHOD(GetLineDash);
89
+    static NAN_METHOD(MeasureText);
90
+    static NAN_METHOD(BezierCurveTo);
91
+    static NAN_METHOD(QuadraticCurveTo);
92
+    static NAN_METHOD(LineTo);
93
+    static NAN_METHOD(MoveTo);
94
+    static NAN_METHOD(FillRect);
95
+    static NAN_METHOD(StrokeRect);
96
+    static NAN_METHOD(ClearRect);
97
+    static NAN_METHOD(Rect);
98
+    static NAN_METHOD(Arc);
99
+    static NAN_METHOD(ArcTo);
100
+    static NAN_METHOD(GetImageData);
101
+    static NAN_GETTER(GetPatternQuality);
102
+    static NAN_GETTER(GetGlobalCompositeOperation);
103
+    static NAN_GETTER(GetGlobalAlpha);
104
+    static NAN_GETTER(GetShadowColor);
105
+    static NAN_GETTER(GetFillColor);
106
+    static NAN_GETTER(GetStrokeColor);
107
+    static NAN_GETTER(GetMiterLimit);
108
+    static NAN_GETTER(GetLineCap);
109
+    static NAN_GETTER(GetLineJoin);
110
+    static NAN_GETTER(GetLineWidth);
111
+    static NAN_GETTER(GetLineDashOffset);
112
+    static NAN_GETTER(GetShadowOffsetX);
113
+    static NAN_GETTER(GetShadowOffsetY);
114
+    static NAN_GETTER(GetShadowBlur);
115
+    static NAN_GETTER(GetAntiAlias);
116
+    static NAN_GETTER(GetTextDrawingMode);
117
+    static NAN_GETTER(GetFilter);
118
+    static NAN_SETTER(SetPatternQuality);
119
+    static NAN_SETTER(SetGlobalCompositeOperation);
120
+    static NAN_SETTER(SetGlobalAlpha);
121
+    static NAN_SETTER(SetShadowColor);
122
+    static NAN_SETTER(SetMiterLimit);
123
+    static NAN_SETTER(SetLineCap);
124
+    static NAN_SETTER(SetLineJoin);
125
+    static NAN_SETTER(SetLineWidth);
126
+    static NAN_SETTER(SetLineDashOffset);
127
+    static NAN_SETTER(SetShadowOffsetX);
128
+    static NAN_SETTER(SetShadowOffsetY);
129
+    static NAN_SETTER(SetShadowBlur);
130
+    static NAN_SETTER(SetAntiAlias);
131
+    static NAN_SETTER(SetTextDrawingMode);
132
+    static NAN_SETTER(SetFilter);
133
+    inline void setContext(cairo_t *ctx) { _context = ctx; }
134
+    inline cairo_t *context(){ return _context; }
135
+    inline Canvas *canvas(){ return _canvas; }
136
+    inline bool hasShadow();
137
+    void inline setSourceRGBA(rgba_t color);
138
+    void inline setSourceRGBA(cairo_t *ctx, rgba_t color);
139
+    void setTextPath(const char *str, double x, double y);
140
+    void blur(cairo_surface_t *surface, int radius);
141
+    void shadow(void (fn)(cairo_t *cr));
142
+    void shadowStart();
143
+    void shadowApply();
144
+    void savePath();
145
+    void restorePath();
146
+    void saveState();
147
+    void restoreState();
148
+    void inline setFillRule(v8::Local<v8::Value> value);
149
+    void fill(bool preserve = false);
150
+    void stroke(bool preserve = false);
151
+    void save();
152
+    void restore();
153
+    void setFontFromState();
154
+    inline PangoLayout *layout(){ return _layout; }
155
+
156
+  private:
157
+    ~Context2d();
158
+    Canvas *_canvas;
159
+    cairo_t *_context;
160
+    cairo_path_t *_path;
161
+    PangoLayout *_layout;
162
+};
163
+
164
+#endif

+ 974 - 0
vendor/canvas/src/Image.cc Wyświetl plik

@@ -0,0 +1,974 @@
1
+//
2
+// Image.cc
3
+//
4
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
5
+//
6
+
7
+#include "Canvas.h"
8
+#include "Image.h"
9
+#include <stdlib.h>
10
+#include <string.h>
11
+#include <errno.h>
12
+#include <node_buffer.h>
13
+
14
+#ifdef HAVE_GIF
15
+typedef struct {
16
+  uint8_t *buf;
17
+  unsigned len;
18
+  unsigned pos;
19
+} gif_data_t;
20
+#endif
21
+
22
+/*
23
+ * Read closure used by loadFromBuffer.
24
+ */
25
+
26
+typedef struct {
27
+  unsigned len;
28
+  uint8_t *buf;
29
+} read_closure_t;
30
+
31
+Nan::Persistent<FunctionTemplate> Image::constructor;
32
+
33
+/*
34
+ * Initialize Image.
35
+ */
36
+
37
+void
38
+Image::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
39
+  Nan::HandleScope scope;
40
+
41
+  Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Image::New);
42
+  constructor.Reset(ctor);
43
+  ctor->InstanceTemplate()->SetInternalFieldCount(1);
44
+  ctor->SetClassName(Nan::New("Image").ToLocalChecked());
45
+
46
+  // Prototype
47
+  Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
48
+  Nan::SetAccessor(proto, Nan::New("source").ToLocalChecked(), GetSource, SetSource);
49
+  Nan::SetAccessor(proto, Nan::New("complete").ToLocalChecked(), GetComplete);
50
+  Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
51
+  Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
52
+  Nan::SetAccessor(proto, Nan::New("onload").ToLocalChecked(), GetOnload, SetOnload);
53
+  Nan::SetAccessor(proto, Nan::New("onerror").ToLocalChecked(), GetOnerror, SetOnerror);
54
+#if CAIRO_VERSION_MINOR >= 10
55
+  Nan::SetAccessor(proto, Nan::New("dataMode").ToLocalChecked(), GetDataMode, SetDataMode);
56
+  ctor->Set(Nan::New("MODE_IMAGE").ToLocalChecked(), Nan::New<Number>(DATA_IMAGE));
57
+  ctor->Set(Nan::New("MODE_MIME").ToLocalChecked(), Nan::New<Number>(DATA_MIME));
58
+#endif
59
+  Nan::Set(target, Nan::New("Image").ToLocalChecked(), ctor->GetFunction());
60
+}
61
+
62
+/*
63
+ * Initialize a new Image.
64
+ */
65
+
66
+NAN_METHOD(Image::New) {
67
+  if (!info.IsConstructCall()) {
68
+    return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
69
+  }
70
+
71
+  Image *img = new Image;
72
+  img->data_mode = DATA_IMAGE;
73
+  img->Wrap(info.This());
74
+  info.GetReturnValue().Set(info.This());
75
+}
76
+
77
+/*
78
+ * Get complete boolean.
79
+ */
80
+
81
+NAN_GETTER(Image::GetComplete) {
82
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
83
+  info.GetReturnValue().Set(Nan::New<Boolean>(Image::COMPLETE == img->state));
84
+}
85
+
86
+#if CAIRO_VERSION_MINOR >= 10
87
+
88
+/*
89
+ * Get dataMode.
90
+ */
91
+
92
+NAN_GETTER(Image::GetDataMode) {
93
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
94
+  info.GetReturnValue().Set(Nan::New<Number>(img->data_mode));
95
+}
96
+
97
+/*
98
+ * Set dataMode.
99
+ */
100
+
101
+NAN_SETTER(Image::SetDataMode) {
102
+  if (value->IsNumber()) {
103
+    Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
104
+    int mode = value->Uint32Value();
105
+    img->data_mode = (data_mode_t) mode;
106
+  }
107
+}
108
+
109
+#endif
110
+
111
+/*
112
+ * Get width.
113
+ */
114
+
115
+NAN_GETTER(Image::GetWidth) {
116
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
117
+  info.GetReturnValue().Set(Nan::New<Number>(img->width));
118
+}
119
+/*
120
+ * Get height.
121
+ */
122
+
123
+NAN_GETTER(Image::GetHeight) {
124
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
125
+  info.GetReturnValue().Set(Nan::New<Number>(img->height));
126
+}
127
+
128
+/*
129
+ * Get src path.
130
+ */
131
+
132
+NAN_GETTER(Image::GetSource) {
133
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
134
+  info.GetReturnValue().Set(Nan::New<String>(img->filename ? img->filename : "").ToLocalChecked());
135
+}
136
+
137
+/*
138
+ * Clean up assets and variables.
139
+ */
140
+
141
+void
142
+Image::clearData() {
143
+  if (_surface) {
144
+    cairo_surface_destroy(_surface);
145
+    Nan::AdjustExternalMemory(-_data_len);
146
+    _data_len = 0;
147
+    _surface = NULL;
148
+  }
149
+
150
+  free(_data);
151
+  _data = NULL;
152
+
153
+  free(filename);
154
+  filename = NULL;
155
+
156
+  width = height = 0;
157
+  state = DEFAULT;
158
+}
159
+
160
+/*
161
+ * Set src path.
162
+ */
163
+
164
+NAN_SETTER(Image::SetSource) {
165
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
166
+  cairo_status_t status = CAIRO_STATUS_READ_ERROR;
167
+
168
+  img->clearData();
169
+
170
+  // url string
171
+  if (value->IsString()) {
172
+    String::Utf8Value src(value);
173
+    if (img->filename) free(img->filename);
174
+    img->filename = strdup(*src);
175
+    status = img->load();
176
+  // Buffer
177
+  } else if (Buffer::HasInstance(value)) {
178
+    uint8_t *buf = (uint8_t *) Buffer::Data(value->ToObject());
179
+    unsigned len = Buffer::Length(value->ToObject());
180
+    status = img->loadFromBuffer(buf, len);
181
+  }
182
+
183
+  // check status
184
+  if (status) {
185
+    img->error(Canvas::Error(status));
186
+  } else {
187
+    img->loaded();
188
+  }
189
+}
190
+
191
+/*
192
+ * Load image data from `buf` by sniffing
193
+ * the bytes to determine format.
194
+ */
195
+
196
+cairo_status_t
197
+Image::loadFromBuffer(uint8_t *buf, unsigned len) {
198
+  uint8_t data[4] = {0};
199
+  memcpy(data, buf, (len < 4 ? len : 4) * sizeof(uint8_t));
200
+
201
+  if (isPNG(data)) return loadPNGFromBuffer(buf);
202
+#ifdef HAVE_GIF
203
+  if (isGIF(data)) return loadGIFFromBuffer(buf, len);
204
+#endif
205
+#ifdef HAVE_JPEG
206
+#if CAIRO_VERSION_MINOR < 10
207
+  if (isJPEG(data)) return loadJPEGFromBuffer(buf, len);
208
+#else
209
+  if (isJPEG(data)) {
210
+    if (DATA_IMAGE == data_mode) return loadJPEGFromBuffer(buf, len);
211
+    if (DATA_MIME == data_mode) return decodeJPEGBufferIntoMimeSurface(buf, len);
212
+    if ((DATA_IMAGE | DATA_MIME) == data_mode) {
213
+      cairo_status_t status;
214
+      status = loadJPEGFromBuffer(buf, len);
215
+      if (status) return status;
216
+      return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG);
217
+    }
218
+  }
219
+#endif
220
+#endif
221
+  return CAIRO_STATUS_READ_ERROR;
222
+}
223
+
224
+/*
225
+ * Load PNG data from `buf`.
226
+ */
227
+
228
+cairo_status_t
229
+Image::loadPNGFromBuffer(uint8_t *buf) {
230
+  read_closure_t closure;
231
+  closure.len = 0;
232
+  closure.buf = buf;
233
+  _surface = cairo_image_surface_create_from_png_stream(readPNG, &closure);
234
+  cairo_status_t status = cairo_surface_status(_surface);
235
+  if (status) return status;
236
+  return CAIRO_STATUS_SUCCESS;
237
+}
238
+
239
+/*
240
+ * Read PNG data.
241
+ */
242
+
243
+cairo_status_t
244
+Image::readPNG(void *c, uint8_t *data, unsigned int len) {
245
+  read_closure_t *closure = (read_closure_t *) c;
246
+  memcpy(data, closure->buf + closure->len, len);
247
+  closure->len += len;
248
+  return CAIRO_STATUS_SUCCESS;
249
+}
250
+
251
+/*
252
+ * Get onload callback.
253
+ */
254
+
255
+NAN_GETTER(Image::GetOnload) {
256
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
257
+  if (img->onload) {
258
+    info.GetReturnValue().Set(img->onload->GetFunction());
259
+  } else {
260
+    info.GetReturnValue().SetNull();
261
+  }
262
+}
263
+
264
+/*
265
+ * Set onload callback.
266
+ */
267
+
268
+NAN_SETTER(Image::SetOnload) {
269
+  if (value->IsFunction()) {
270
+    Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
271
+    img->onload = new Nan::Callback(value.As<Function>());
272
+  } else if (value->IsNull()) {
273
+    Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
274
+    if (img->onload) {
275
+      delete img->onload;
276
+    }
277
+    img->onload = NULL;
278
+  }
279
+}
280
+
281
+/*
282
+ * Get onerror callback.
283
+ */
284
+
285
+NAN_GETTER(Image::GetOnerror) {
286
+  Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
287
+  if (img->onerror) {
288
+    info.GetReturnValue().Set(img->onerror->GetFunction());
289
+  } else {
290
+    info.GetReturnValue().SetNull();
291
+  }
292
+}
293
+
294
+/*
295
+ * Set onerror callback.
296
+ */
297
+
298
+NAN_SETTER(Image::SetOnerror) {
299
+  if (value->IsFunction()) {
300
+    Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
301
+    img->onerror = new Nan::Callback(value.As<Function>());
302
+  } else if (value->IsNull()) {
303
+    Image *img = Nan::ObjectWrap::Unwrap<Image>(info.This());
304
+    if (img->onerror) {
305
+        delete img->onerror;
306
+    }
307
+    img->onerror = NULL;
308
+  }
309
+}
310
+
311
+/*
312
+ * Initialize a new Image.
313
+ */
314
+
315
+Image::Image() {
316
+  filename = NULL;
317
+  _data = NULL;
318
+  _data_len = 0;
319
+  _surface = NULL;
320
+  width = height = 0;
321
+  state = DEFAULT;
322
+  onload = NULL;
323
+  onerror = NULL;
324
+}
325
+
326
+/*
327
+ * Destroy image and associated surface.
328
+ */
329
+
330
+Image::~Image() {
331
+  clearData();
332
+
333
+  if (onerror) {
334
+    delete onerror;
335
+    onerror = NULL;
336
+  }
337
+
338
+  if (onload) {
339
+    delete onload;
340
+    onload = NULL;
341
+  }
342
+}
343
+
344
+/*
345
+ * Initiate image loading.
346
+ */
347
+
348
+cairo_status_t
349
+Image::load() {
350
+  if (LOADING != state) {
351
+    state = LOADING;
352
+    return loadSurface();
353
+  }
354
+  return CAIRO_STATUS_READ_ERROR;
355
+}
356
+
357
+/*
358
+ * Invoke onload (when assigned) and assign dimensions.
359
+ */
360
+
361
+void
362
+Image::loaded() {
363
+  Nan::HandleScope scope;
364
+  state = COMPLETE;
365
+
366
+  width = cairo_image_surface_get_width(_surface);
367
+  height = cairo_image_surface_get_height(_surface);
368
+  _data_len = height * cairo_image_surface_get_stride(_surface);
369
+  Nan::AdjustExternalMemory(_data_len);
370
+
371
+  if (onload != NULL) {
372
+    onload->Call(0, NULL);
373
+  }
374
+}
375
+
376
+/*
377
+ * Invoke onerror (when assigned) with the given err.
378
+ */
379
+
380
+void
381
+Image::error(Local<Value> err) {
382
+  Nan::HandleScope scope;
383
+  if (onerror != NULL) {
384
+    Local<Value> argv[1] = { err };
385
+    onerror->Call(1, argv);
386
+  }
387
+}
388
+
389
+/*
390
+ * Load cairo surface from the image src.
391
+ *
392
+ * TODO: support more formats
393
+ * TODO: use node IO or at least thread pool
394
+ */
395
+
396
+cairo_status_t
397
+Image::loadSurface() {
398
+  FILE *stream = fopen(filename, "rb");
399
+  if (!stream) return CAIRO_STATUS_READ_ERROR;
400
+  uint8_t buf[5];
401
+  if (1 != fread(&buf, 5, 1, stream)) {
402
+    fclose(stream);
403
+    return CAIRO_STATUS_READ_ERROR;
404
+  }
405
+  fseek(stream, 0, SEEK_SET);
406
+
407
+  // png
408
+  if (isPNG(buf)) {
409
+    fclose(stream);
410
+    return loadPNG();
411
+  }
412
+
413
+  // gif
414
+#ifdef HAVE_GIF
415
+  if (isGIF(buf)) return loadGIF(stream);
416
+#endif
417
+
418
+  // jpeg
419
+#ifdef HAVE_JPEG
420
+  if (isJPEG(buf)) return loadJPEG(stream);
421
+#endif
422
+
423
+  fclose(stream);
424
+  return CAIRO_STATUS_READ_ERROR;
425
+}
426
+
427
+/*
428
+ * Load PNG.
429
+ */
430
+
431
+cairo_status_t
432
+Image::loadPNG() {
433
+  _surface = cairo_image_surface_create_from_png(filename);
434
+  return cairo_surface_status(_surface);
435
+}
436
+
437
+// GIF support
438
+
439
+#ifdef HAVE_GIF
440
+
441
+/*
442
+ * Return the alpha color for `gif` at `frame`, or -1.
443
+ */
444
+
445
+int
446
+get_gif_transparent_color(GifFileType *gif, int frame) {
447
+  ExtensionBlock *ext = gif->SavedImages[frame].ExtensionBlocks;
448
+  int len = gif->SavedImages[frame].ExtensionBlockCount;
449
+  for (int x = 0; x < len; ++x, ++ext) {
450
+    if ((ext->Function == GRAPHICS_EXT_FUNC_CODE) && (ext->Bytes[0] & 1)) {
451
+      return ext->Bytes[3] == 0 ? 0 : (uint8_t) ext->Bytes[3];
452
+    }
453
+  }
454
+  return -1;
455
+}
456
+
457
+/*
458
+ * Memory GIF reader callback.
459
+ */
460
+
461
+int
462
+read_gif_from_memory(GifFileType *gif, GifByteType *buf, int len) {
463
+  gif_data_t *data = (gif_data_t *) gif->UserData;
464
+  if ((data->pos + len) > data->len) len = data->len - data->pos;
465
+  memcpy(buf, data->pos + data->buf, len);
466
+  data->pos += len;
467
+  return len;
468
+}
469
+
470
+/*
471
+ * Load GIF.
472
+ */
473
+
474
+cairo_status_t
475
+Image::loadGIF(FILE *stream) {
476
+  struct stat s;
477
+  int fd = fileno(stream);
478
+
479
+  // stat
480
+  if (fstat(fd, &s) < 0) {
481
+    fclose(stream);
482
+    return CAIRO_STATUS_READ_ERROR;
483
+  }
484
+
485
+  uint8_t *buf = (uint8_t *) malloc(s.st_size);
486
+
487
+  if (!buf) {
488
+    fclose(stream);
489
+    return CAIRO_STATUS_NO_MEMORY;
490
+  }
491
+
492
+  size_t read = fread(buf, s.st_size, 1, stream);
493
+  fclose(stream);
494
+
495
+  cairo_status_t result = CAIRO_STATUS_READ_ERROR;
496
+  if (1 == read) result = loadGIFFromBuffer(buf, s.st_size);
497
+  free(buf);
498
+
499
+  return result;
500
+}
501
+
502
+/*
503
+ * Load give from `buf` and the given `len`.
504
+ */
505
+
506
+cairo_status_t
507
+Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) {
508
+  int i = 0;
509
+  GifFileType* gif;
510
+
511
+  gif_data_t gifd = { buf, len, 0 };
512
+
513
+#if GIFLIB_MAJOR >= 5
514
+  int errorcode;
515
+  if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory, &errorcode)) == NULL)
516
+    return CAIRO_STATUS_READ_ERROR;
517
+#else
518
+  if ((gif = DGifOpen((void*) &gifd, read_gif_from_memory)) == NULL)
519
+    return CAIRO_STATUS_READ_ERROR;
520
+#endif
521
+
522
+  if (GIF_OK != DGifSlurp(gif)) {
523
+    GIF_CLOSE_FILE(gif);
524
+    return CAIRO_STATUS_READ_ERROR;
525
+  }
526
+
527
+  width = gif->SWidth;
528
+  height = gif->SHeight;
529
+
530
+  uint8_t *data = (uint8_t *) malloc(width * height * 4);
531
+  if (!data) {
532
+    GIF_CLOSE_FILE(gif);
533
+    return CAIRO_STATUS_NO_MEMORY;
534
+  }
535
+
536
+  GifImageDesc *img = &gif->SavedImages[i].ImageDesc;
537
+
538
+  // local colormap takes precedence over global
539
+  ColorMapObject *colormap = img->ColorMap
540
+    ? img->ColorMap
541
+    : gif->SColorMap;
542
+
543
+  int bgColor = 0;
544
+  int alphaColor = get_gif_transparent_color(gif, i);
545
+  if (gif->SColorMap) bgColor = (uint8_t) gif->SBackGroundColor;
546
+  else if(alphaColor >= 0) bgColor = alphaColor;
547
+
548
+  uint8_t *src_data = (uint8_t*) gif->SavedImages[i].RasterBits;
549
+  uint32_t *dst_data = (uint32_t*) data;
550
+
551
+  if (!gif->Image.Interlace) {
552
+    if (width == img->Width && height == img->Height) {
553
+      for (int y = 0; y < height; ++y) {
554
+        for (int x = 0; x < width; ++x) {
555
+          *dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24
556
+            | colormap->Colors[*src_data].Red << 16
557
+            | colormap->Colors[*src_data].Green << 8
558
+            | colormap->Colors[*src_data].Blue;
559
+
560
+          dst_data++;
561
+          src_data++;
562
+        }
563
+      }
564
+    } else {
565
+      // Image does not take up whole "screen" so we need to fill-in the background
566
+      int bottom = img->Top + img->Height;
567
+      int right = img->Left + img->Width;
568
+
569
+      for (int y = 0; y < height; ++y) {
570
+        for (int x = 0; x < width; ++x) {
571
+          if (y < img->Top || y >= bottom || x < img->Left || x >= right) {
572
+            *dst_data = ((bgColor == alphaColor) ? 0 : 255) << 24
573
+              | colormap->Colors[bgColor].Red << 16
574
+              | colormap->Colors[bgColor].Green << 8
575
+              | colormap->Colors[bgColor].Blue;
576
+          } else {
577
+            *dst_data = ((*src_data == alphaColor) ? 0 : 255) << 24
578
+              | colormap->Colors[*src_data].Red << 16
579
+              | colormap->Colors[*src_data].Green << 8
580
+              | colormap->Colors[*src_data].Blue;
581
+          }
582
+
583
+          dst_data++;
584
+          src_data++;
585
+        }
586
+      }
587
+    }
588
+  } else {
589
+    // Image is interlaced so that it streams nice over 14.4k and 28.8k modems :)
590
+    // We first load in 1/8 of the image, followed by another 1/8, followed by
591
+    // 1/4 and finally the remaining 1/2.
592
+    int ioffs[] = { 0, 4, 2, 1 };
593
+    int ijumps[] = { 8, 8, 4, 2 };
594
+
595
+    uint8_t *src_ptr = src_data;
596
+    uint32_t *dst_ptr;
597
+
598
+    for(int z = 0; z < 4; z++) {
599
+      for(int y = ioffs[z]; y < height; y += ijumps[z]) {
600
+        dst_ptr = dst_data + width * y;
601
+        for(int x = 0; x < width; ++x) {
602
+          *dst_ptr = ((*src_ptr == alphaColor) ? 0 : 255) << 24
603
+            | (colormap->Colors[*src_ptr].Red) << 16
604
+            | (colormap->Colors[*src_ptr].Green) << 8
605
+            | (colormap->Colors[*src_ptr].Blue);
606
+
607
+          dst_ptr++;
608
+          src_ptr++;
609
+        }
610
+      }
611
+    }
612
+  }
613
+
614
+  GIF_CLOSE_FILE(gif);
615
+
616
+  // New image surface
617
+  _surface = cairo_image_surface_create_for_data(
618
+      data
619
+    , CAIRO_FORMAT_ARGB32
620
+    , width
621
+    , height
622
+    , cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
623
+
624
+  cairo_status_t status = cairo_surface_status(_surface);
625
+
626
+  if (status) {
627
+    free(data);
628
+    return status;
629
+  }
630
+
631
+  _data = data;
632
+
633
+  return CAIRO_STATUS_SUCCESS;
634
+}
635
+#endif /* HAVE_GIF */
636
+
637
+// JPEG support
638
+
639
+#ifdef HAVE_JPEG
640
+
641
+// libjpeg 6.2 does not have jpeg_mem_src; define it ourselves here unless
642
+// libjpeg 8 is installed.
643
+#if JPEG_LIB_VERSION < 80
644
+
645
+/* Read JPEG image from a memory segment */
646
+static void
647
+init_source(j_decompress_ptr cinfo) {}
648
+
649
+static boolean
650
+fill_input_buffer(j_decompress_ptr cinfo) {
651
+  ERREXIT(cinfo, JERR_INPUT_EMPTY);
652
+  return TRUE;
653
+}
654
+static void
655
+skip_input_data(j_decompress_ptr cinfo, long num_bytes) {
656
+  struct jpeg_source_mgr* src = (struct jpeg_source_mgr*) cinfo->src;
657
+  if (num_bytes > 0) {
658
+    src->next_input_byte += (size_t) num_bytes;
659
+    src->bytes_in_buffer -= (size_t) num_bytes;
660
+  }
661
+}
662
+
663
+static void term_source (j_decompress_ptr cinfo) {}
664
+static void jpeg_mem_src (j_decompress_ptr cinfo, void* buffer, long nbytes) {
665
+  struct jpeg_source_mgr* src;
666
+
667
+  if (cinfo->src == NULL) {
668
+    cinfo->src = (struct jpeg_source_mgr *)
669
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
670
+                                  sizeof(struct jpeg_source_mgr));
671
+  }
672
+
673
+  src = (struct jpeg_source_mgr*) cinfo->src;
674
+  src->init_source = init_source;
675
+  src->fill_input_buffer = fill_input_buffer;
676
+  src->skip_input_data = skip_input_data;
677
+  src->resync_to_restart = jpeg_resync_to_restart; /* use default method */
678
+  src->term_source = term_source;
679
+  src->bytes_in_buffer = nbytes;
680
+  src->next_input_byte = (JOCTET*)buffer;
681
+}
682
+
683
+#endif
684
+
685
+/*
686
+ * Takes an initialised jpeg_decompress_struct and decodes the
687
+ * data into _surface.
688
+ */
689
+
690
+cairo_status_t
691
+Image::decodeJPEGIntoSurface(jpeg_decompress_struct *args) {
692
+  int stride = width * 4;
693
+  cairo_status_t status;
694
+
695
+  uint8_t *data = (uint8_t *) malloc(width * height * 4);
696
+  if (!data) {
697
+    jpeg_abort_decompress(args);
698
+    jpeg_destroy_decompress(args);
699
+    return CAIRO_STATUS_NO_MEMORY;
700
+  }
701
+
702
+  uint8_t *src = (uint8_t *) malloc(width * args->output_components);
703
+  if (!src) {
704
+    free(data);
705
+    jpeg_abort_decompress(args);
706
+    jpeg_destroy_decompress(args);
707
+    return CAIRO_STATUS_NO_MEMORY;
708
+  }
709
+
710
+  for (int y = 0; y < height; ++y) {
711
+    jpeg_read_scanlines(args, &src, 1);
712
+    uint32_t *row = (uint32_t *)(data + stride * y);
713
+    for (int x = 0; x < width; ++x) {
714
+      if (args->jpeg_color_space == 1) {
715
+        uint32_t *pixel = row + x;
716
+        *pixel = 255 << 24
717
+          | src[x] << 16
718
+          | src[x] << 8
719
+          | src[x];
720
+      } else {
721
+        int bx = 3 * x;
722
+        uint32_t *pixel = row + x;
723
+        *pixel = 255 << 24
724
+          | src[bx + 0] << 16
725
+          | src[bx + 1] << 8
726
+          | src[bx + 2];
727
+      }
728
+    }
729
+  }
730
+
731
+  _surface = cairo_image_surface_create_for_data(
732
+      data
733
+    , CAIRO_FORMAT_ARGB32
734
+    , width
735
+    , height
736
+    , cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width));
737
+
738
+  jpeg_finish_decompress(args);
739
+  jpeg_destroy_decompress(args);
740
+  status = cairo_surface_status(_surface);
741
+
742
+  if (status) {
743
+    free(data);
744
+    free(src);
745
+    return status;
746
+  }
747
+
748
+  free(src);
749
+
750
+  _data = data;
751
+
752
+  return CAIRO_STATUS_SUCCESS;
753
+}
754
+
755
+#if CAIRO_VERSION_MINOR >= 10
756
+
757
+/*
758
+ * Takes a jpeg data buffer and assigns it as mime data to a
759
+ * dummy surface
760
+ */
761
+
762
+cairo_status_t
763
+Image::decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len) {
764
+  // TODO: remove this duplicate logic
765
+  // JPEG setup
766
+  struct jpeg_decompress_struct args;
767
+  struct jpeg_error_mgr err;
768
+  args.err = jpeg_std_error(&err);
769
+  jpeg_create_decompress(&args);
770
+
771
+  jpeg_mem_src(&args, buf, len);
772
+
773
+  jpeg_read_header(&args, 1);
774
+  jpeg_start_decompress(&args);
775
+  width = args.output_width;
776
+  height = args.output_height;
777
+
778
+  // Data alloc
779
+  // 8 pixels per byte using Alpha Channel format to reduce memory requirement.
780
+  int buf_size = height * cairo_format_stride_for_width(CAIRO_FORMAT_A1, width);
781
+  uint8_t *data = (uint8_t *) malloc(buf_size);
782
+  if (!data) return CAIRO_STATUS_NO_MEMORY;
783
+
784
+  // New image surface
785
+  _surface = cairo_image_surface_create_for_data(
786
+      data
787
+    , CAIRO_FORMAT_A1
788
+    , width
789
+    , height
790
+    , cairo_format_stride_for_width(CAIRO_FORMAT_A1, width));
791
+
792
+  // Cleanup
793
+  jpeg_abort_decompress(&args);
794
+  jpeg_destroy_decompress(&args);
795
+  cairo_status_t status = cairo_surface_status(_surface);
796
+
797
+  if (status) {
798
+    free(data);
799
+    return status;
800
+  }
801
+
802
+  _data = data;
803
+
804
+  return assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG);
805
+}
806
+
807
+/*
808
+ * Helper function for disposing of a mime data closure.
809
+ */
810
+
811
+void
812
+clearMimeData(void *closure) {
813
+  Nan::AdjustExternalMemory(-((read_closure_t *)closure)->len);
814
+  free(((read_closure_t *) closure)->buf);
815
+  free(closure);
816
+}
817
+
818
+/*
819
+ * Assign a given buffer as mime data against the surface.
820
+ * The provided buffer will be copied, and the copy will
821
+ * be automatically freed when the surface is destroyed.
822
+ */
823
+
824
+cairo_status_t
825
+Image::assignDataAsMime(uint8_t *data, int len, const char *mime_type) {
826
+  uint8_t *mime_data = (uint8_t *) malloc(len);
827
+  if (!mime_data) return CAIRO_STATUS_NO_MEMORY;
828
+
829
+  read_closure_t *mime_closure = (read_closure_t *) malloc(sizeof(read_closure_t));
830
+  if (!mime_closure) {
831
+    free(mime_data);
832
+    return CAIRO_STATUS_NO_MEMORY;
833
+  }
834
+
835
+  memcpy(mime_data, data, len);
836
+
837
+  mime_closure->buf = mime_data;
838
+  mime_closure->len = len;
839
+
840
+  Nan::AdjustExternalMemory(len);
841
+
842
+  return cairo_surface_set_mime_data(_surface
843
+    , mime_type
844
+    , mime_data
845
+    , len
846
+    , clearMimeData
847
+    , mime_closure);
848
+}
849
+
850
+#endif
851
+
852
+/*
853
+ * Load jpeg from buffer.
854
+ */
855
+
856
+cairo_status_t
857
+Image::loadJPEGFromBuffer(uint8_t *buf, unsigned len) {
858
+  // TODO: remove this duplicate logic
859
+  // JPEG setup
860
+  struct jpeg_decompress_struct args;
861
+  struct jpeg_error_mgr err;
862
+  args.err = jpeg_std_error(&err);
863
+  jpeg_create_decompress(&args);
864
+
865
+  jpeg_mem_src(&args, buf, len);
866
+
867
+  jpeg_read_header(&args, 1);
868
+  jpeg_start_decompress(&args);
869
+  width = args.output_width;
870
+  height = args.output_height;
871
+
872
+  return decodeJPEGIntoSurface(&args);
873
+}
874
+
875
+/*
876
+ * Load JPEG, convert RGB to ARGB.
877
+ */
878
+
879
+cairo_status_t
880
+Image::loadJPEG(FILE *stream) {
881
+  cairo_status_t status;
882
+
883
+  if (data_mode == DATA_IMAGE) { // Can lazily read in the JPEG.
884
+    // JPEG setup
885
+    struct jpeg_decompress_struct args;
886
+    struct jpeg_error_mgr err;
887
+    args.err = jpeg_std_error(&err);
888
+    jpeg_create_decompress(&args);
889
+
890
+    jpeg_stdio_src(&args, stream);
891
+
892
+    jpeg_read_header(&args, 1);
893
+    jpeg_start_decompress(&args);
894
+    width = args.output_width;
895
+    height = args.output_height;
896
+
897
+    status = decodeJPEGIntoSurface(&args);
898
+    fclose(stream);
899
+  } else { // We'll need the actual source jpeg data, so read fully.
900
+#if CAIRO_VERSION_MINOR >= 10
901
+    uint8_t *buf;
902
+    unsigned len;
903
+
904
+    fseek(stream, 0, SEEK_END);
905
+    len = ftell(stream);
906
+    fseek(stream, 0, SEEK_SET);
907
+
908
+    buf = (uint8_t *) malloc(len);
909
+    if (!buf) return CAIRO_STATUS_NO_MEMORY;
910
+
911
+    if (fread(buf, len, 1, stream) != 1) {
912
+      status = CAIRO_STATUS_READ_ERROR;
913
+    } else if ((DATA_IMAGE | DATA_MIME) == data_mode) {
914
+      status = loadJPEGFromBuffer(buf, len);
915
+      if (!status) status = assignDataAsMime(buf, len, CAIRO_MIME_TYPE_JPEG);
916
+    } else if (DATA_MIME == data_mode) {
917
+      status = decodeJPEGBufferIntoMimeSurface(buf, len);
918
+    } else {
919
+      status = CAIRO_STATUS_READ_ERROR;
920
+    }
921
+
922
+    fclose(stream);
923
+    free(buf);
924
+#else
925
+    status = CAIRO_STATUS_READ_ERROR;
926
+#endif
927
+  }
928
+
929
+  return status;
930
+}
931
+
932
+#endif /* HAVE_JPEG */
933
+
934
+/*
935
+ * Return UNKNOWN, JPEG, or PNG based on the filename.
936
+ */
937
+
938
+Image::type
939
+Image::extension(const char *filename) {
940
+  size_t len = strlen(filename);
941
+  filename += len;
942
+  if (len >= 5 && 0 == strcmp(".jpeg", filename - 5)) return Image::JPEG;
943
+  if (len >= 4 && 0 == strcmp(".gif", filename - 4)) return Image::GIF;
944
+  if (len >= 4 && 0 == strcmp(".jpg", filename - 4)) return Image::JPEG;
945
+  if (len >= 4 && 0 == strcmp(".png", filename - 4)) return Image::PNG;
946
+  return Image::UNKNOWN;
947
+}
948
+
949
+/*
950
+ * Sniff bytes 0..1 for JPEG's magic number ff d8.
951
+ */
952
+
953
+int
954
+Image::isJPEG(uint8_t *data) {
955
+  return 0xff == data[0] && 0xd8 == data[1];
956
+}
957
+
958
+/*
959
+ * Sniff bytes 0..2 for "GIF".
960
+ */
961
+
962
+int
963
+Image::isGIF(uint8_t *data) {
964
+  return 'G' == data[0] && 'I' == data[1] && 'F' == data[2];
965
+}
966
+
967
+/*
968
+ * Sniff bytes 1..3 for "PNG".
969
+ */
970
+
971
+int
972
+Image::isPNG(uint8_t *data) {
973
+  return 'P' == data[1] && 'N' == data[2] && 'G' == data[3];
974
+}

+ 108 - 0
vendor/canvas/src/Image.h Wyświetl plik

@@ -0,0 +1,108 @@
1
+
2
+//
3
+// Image.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_IMAGE_H__
9
+#define __NODE_IMAGE_H__
10
+
11
+#include "Canvas.h"
12
+
13
+#ifdef HAVE_JPEG
14
+#include <jpeglib.h>
15
+#include <jerror.h>
16
+#endif
17
+
18
+#ifdef HAVE_GIF
19
+#include <gif_lib.h>
20
+
21
+  #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1
22
+    #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL)
23
+  #else
24
+    #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif)
25
+  #endif
26
+#endif
27
+
28
+
29
+
30
+class Image: public Nan::ObjectWrap {
31
+  public:
32
+    char *filename;
33
+    int width, height;
34
+    Nan::Callback *onload;
35
+    Nan::Callback *onerror;
36
+    static Nan::Persistent<FunctionTemplate> constructor;
37
+    static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
38
+    static NAN_METHOD(New);
39
+    static NAN_GETTER(GetSource);
40
+    static NAN_GETTER(GetOnload);
41
+    static NAN_GETTER(GetOnerror);
42
+    static NAN_GETTER(GetComplete);
43
+    static NAN_GETTER(GetWidth);
44
+    static NAN_GETTER(GetHeight);
45
+    static NAN_GETTER(GetDataMode);
46
+    static NAN_SETTER(SetSource);
47
+    static NAN_SETTER(SetOnload);
48
+    static NAN_SETTER(SetOnerror);
49
+    static NAN_SETTER(SetDataMode);
50
+    inline cairo_surface_t *surface(){ return _surface; }
51
+    inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); }
52
+    inline int stride(){ return cairo_image_surface_get_stride(_surface); }
53
+    static int isPNG(uint8_t *data);
54
+    static int isJPEG(uint8_t *data);
55
+    static int isGIF(uint8_t *data);
56
+    static cairo_status_t readPNG(void *closure, unsigned char *data, unsigned len);
57
+    inline int isComplete(){ return COMPLETE == state; }
58
+    cairo_status_t loadSurface();
59
+    cairo_status_t loadFromBuffer(uint8_t *buf, unsigned len);
60
+    cairo_status_t loadPNGFromBuffer(uint8_t *buf);
61
+    cairo_status_t loadPNG();
62
+    void clearData();
63
+#ifdef HAVE_GIF
64
+    cairo_status_t loadGIFFromBuffer(uint8_t *buf, unsigned len);
65
+    cairo_status_t loadGIF(FILE *stream);
66
+#endif
67
+#ifdef HAVE_JPEG
68
+    cairo_status_t loadJPEGFromBuffer(uint8_t *buf, unsigned len);
69
+    cairo_status_t loadJPEG(FILE *stream);
70
+    cairo_status_t decodeJPEGIntoSurface(jpeg_decompress_struct *info);
71
+#if CAIRO_VERSION_MINOR >= 10
72
+    cairo_status_t decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len);
73
+    cairo_status_t assignDataAsMime(uint8_t *data, int len, const char *mime_type);
74
+#endif
75
+#endif
76
+    void error(Local<Value> error);
77
+    void loaded();
78
+    cairo_status_t load();
79
+    Image();
80
+
81
+    enum {
82
+        DEFAULT
83
+      , LOADING
84
+      , COMPLETE
85
+    } state;
86
+
87
+    enum data_mode_t {
88
+        DATA_IMAGE = 1
89
+      , DATA_MIME = 2
90
+    } data_mode;
91
+
92
+    typedef enum {
93
+        UNKNOWN
94
+      , GIF
95
+      , JPEG
96
+      , PNG
97
+    } type;
98
+
99
+    static type extension(const char *filename);
100
+
101
+  private:
102
+    cairo_surface_t *_surface;
103
+    uint8_t *_data;
104
+    int _data_len;
105
+    ~Image();
106
+};
107
+
108
+#endif

+ 135 - 0
vendor/canvas/src/ImageData.cc Wyświetl plik

@@ -0,0 +1,135 @@
1
+
2
+//
3
+// ImageData.cc
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#include "ImageData.h"
9
+
10
+Nan::Persistent<FunctionTemplate> ImageData::constructor;
11
+
12
+/*
13
+ * Initialize ImageData.
14
+ */
15
+
16
+void
17
+ImageData::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
18
+  Nan::HandleScope scope;
19
+
20
+  // Constructor
21
+  Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(ImageData::New);
22
+  constructor.Reset(ctor);
23
+  ctor->InstanceTemplate()->SetInternalFieldCount(1);
24
+  ctor->SetClassName(Nan::New("ImageData").ToLocalChecked());
25
+
26
+  // Prototype
27
+  Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
28
+  Nan::SetAccessor(proto, Nan::New("width").ToLocalChecked(), GetWidth);
29
+  Nan::SetAccessor(proto, Nan::New("height").ToLocalChecked(), GetHeight);
30
+  Nan::Set(target, Nan::New("ImageData").ToLocalChecked(), ctor->GetFunction());
31
+}
32
+
33
+/*
34
+ * Initialize a new ImageData object.
35
+ */
36
+
37
+NAN_METHOD(ImageData::New) {
38
+  if (!info.IsConstructCall()) {
39
+    return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
40
+  }
41
+
42
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
43
+  Local<v8::Object> clampedArray;
44
+  Local<Object> global = Context::GetCurrent()->Global();
45
+#else
46
+  Local<Uint8ClampedArray> clampedArray;
47
+#endif
48
+
49
+  uint32_t width;
50
+  uint32_t height;
51
+  int length;
52
+
53
+  if (info[0]->IsUint32() && info[1]->IsUint32()) {
54
+    width = info[0]->Uint32Value();
55
+    if (width == 0) {
56
+      Nan::ThrowRangeError("The source width is zero.");
57
+      return;
58
+    }
59
+    height = info[1]->Uint32Value();
60
+    if (height == 0) {
61
+      Nan::ThrowRangeError("The source height is zero.");
62
+      return;
63
+    }
64
+    length = width * height * 4;
65
+
66
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
67
+    Local<Int32> sizeHandle = Nan::New(length);
68
+    Local<Value> caargv[] = { sizeHandle };
69
+    clampedArray = global->Get(Nan::New("Uint8ClampedArray").ToLocalChecked()).As<Function>()->NewInstance(1, caargv);
70
+#else
71
+    clampedArray = Uint8ClampedArray::New(ArrayBuffer::New(Isolate::GetCurrent(), length), 0, length);
72
+#endif
73
+
74
+#if NODE_MAJOR_VERSION == 0 && NODE_MINOR_VERSION <= 10
75
+  } else if (info[0]->ToObject()->GetIndexedPropertiesExternalArrayDataType() == kExternalPixelArray && info[1]->IsUint32()) {
76
+    clampedArray = info[0]->ToObject();
77
+    length = clampedArray->GetIndexedPropertiesExternalArrayDataLength();
78
+#else
79
+  } else if (info[0]->IsUint8ClampedArray() && info[1]->IsUint32()) {
80
+    clampedArray = info[0].As<Uint8ClampedArray>();
81
+    length = clampedArray->Length();
82
+#endif
83
+    if (length == 0) {
84
+      Nan::ThrowRangeError("The input data has a zero byte length.");
85
+      return;
86
+    }
87
+    if (length % 4 != 0) {
88
+      Nan::ThrowRangeError("The input data byte length is not a multiple of 4.");
89
+      return;
90
+    }
91
+    width = info[1]->Uint32Value();
92
+    int size = length / 4;
93
+    if (width == 0) {
94
+      Nan::ThrowRangeError("The source width is zero.");
95
+      return;
96
+    }
97
+    if (size % width != 0) {
98
+      Nan::ThrowRangeError("The input data byte length is not a multiple of (4 * width).");
99
+      return;
100
+    }
101
+    height = size / width;
102
+    if (info[2]->IsUint32() && info[2]->Uint32Value() != height) {
103
+      Nan::ThrowRangeError("The input data byte length is not equal to (4 * width * height).");
104
+      return;
105
+    }
106
+  } else {
107
+    Nan::ThrowTypeError("Expected (Uint8ClampedArray, width[, height]) or (width, height)");
108
+    return;
109
+  }
110
+
111
+  Nan::TypedArrayContents<uint8_t> dataPtr(clampedArray);
112
+
113
+  ImageData *imageData = new ImageData(reinterpret_cast<uint8_t*>(*dataPtr), width, height);
114
+  imageData->Wrap(info.This());
115
+  info.This()->Set(Nan::New("data").ToLocalChecked(), clampedArray);
116
+  info.GetReturnValue().Set(info.This());
117
+}
118
+
119
+/*
120
+ * Get width.
121
+ */
122
+
123
+NAN_GETTER(ImageData::GetWidth) {
124
+  ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
125
+  info.GetReturnValue().Set(Nan::New<Number>(imageData->width()));
126
+}
127
+
128
+/*
129
+ * Get height.
130
+ */
131
+
132
+NAN_GETTER(ImageData::GetHeight) {
133
+  ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(info.This());
134
+  info.GetReturnValue().Set(Nan::New<Number>(imageData->height()));
135
+}

+ 36 - 0
vendor/canvas/src/ImageData.h Wyświetl plik

@@ -0,0 +1,36 @@
1
+
2
+//
3
+// ImageData.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_IMAGE_DATA_H__
9
+#define __NODE_IMAGE_DATA_H__
10
+
11
+#include "Canvas.h"
12
+#include <stdlib.h>
13
+#include <v8.h>
14
+
15
+class ImageData: public Nan::ObjectWrap {
16
+  public:
17
+    static Nan::Persistent<FunctionTemplate> constructor;
18
+    static void Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target);
19
+    static NAN_METHOD(New);
20
+    static NAN_GETTER(GetWidth);
21
+    static NAN_GETTER(GetHeight);
22
+
23
+    inline int width() { return _width; }
24
+    inline int height() { return _height; }
25
+    inline uint8_t *data() { return _data; }
26
+    inline int stride() { return _width * 4; }
27
+    ImageData(uint8_t *data, int width, int height) : _width(width), _height(height), _data(data) {}
28
+
29
+  private:
30
+    int _width;
31
+    int _height;
32
+    uint8_t *_data;
33
+
34
+};
35
+
36
+#endif

+ 146 - 0
vendor/canvas/src/JPEGStream.h Wyświetl plik

@@ -0,0 +1,146 @@
1
+
2
+//
3
+// JPEGStream.h
4
+//
5
+
6
+#ifndef __NODE_JPEG_STREAM_H__
7
+#define __NODE_JPEG_STREAM_H__
8
+
9
+#include "Canvas.h"
10
+#include <jpeglib.h>
11
+#include <jerror.h>
12
+
13
+/*
14
+ * Expanded data destination object for closure output,
15
+ * inspired by IJG's jdatadst.c
16
+ */
17
+
18
+typedef struct {
19
+  struct jpeg_destination_mgr pub;
20
+  closure_t *closure;
21
+  JOCTET *buffer;
22
+  int bufsize;
23
+} closure_destination_mgr;
24
+
25
+void
26
+init_closure_destination(j_compress_ptr cinfo){
27
+  // we really don't have to do anything here
28
+}
29
+
30
+boolean
31
+empty_closure_output_buffer(j_compress_ptr cinfo){
32
+  Nan::HandleScope scope;
33
+  closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
34
+
35
+  Local<Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize).ToLocalChecked();
36
+
37
+  // emit "data"
38
+  Local<Value> argv[2] = {
39
+      Nan::Null()
40
+    , buf
41
+  };
42
+  Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 2, argv);
43
+
44
+  dest->buffer = (JOCTET *)malloc(dest->bufsize);
45
+  cinfo->dest->next_output_byte = dest->buffer;
46
+  cinfo->dest->free_in_buffer = dest->bufsize;
47
+  return true;
48
+}
49
+
50
+void
51
+term_closure_destination(j_compress_ptr cinfo){
52
+  Nan::HandleScope scope;
53
+  closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest;
54
+
55
+  /* emit remaining data */
56
+  Local<Object> buf = Nan::NewBuffer((char *)dest->buffer, dest->bufsize - dest->pub.free_in_buffer).ToLocalChecked();
57
+
58
+  Local<Value> data_argv[2] = {
59
+      Nan::Null()
60
+    , buf
61
+  };
62
+
63
+  Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 2, data_argv);
64
+
65
+  // emit "end"
66
+  Local<Value> end_argv[2] = {
67
+      Nan::Null()
68
+    , Nan::Null()
69
+  };
70
+
71
+  Nan::MakeCallback(Nan::GetCurrentContext()->Global(), (v8::Local<v8::Function>)dest->closure->fn, 2, end_argv);
72
+}
73
+
74
+void
75
+jpeg_closure_dest(j_compress_ptr cinfo, closure_t * closure, int bufsize){
76
+  closure_destination_mgr * dest;
77
+
78
+  /* The destination object is made permanent so that multiple JPEG images
79
+   * can be written to the same buffer without re-executing jpeg_mem_dest.
80
+   */
81
+  if (cinfo->dest == NULL) {  /* first time for this JPEG object? */
82
+    cinfo->dest = (struct jpeg_destination_mgr *)
83
+      (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
84
+         sizeof(closure_destination_mgr));
85
+  }
86
+
87
+  dest = (closure_destination_mgr *) cinfo->dest;
88
+
89
+  cinfo->dest->init_destination = &init_closure_destination;
90
+  cinfo->dest->empty_output_buffer = &empty_closure_output_buffer;
91
+  cinfo->dest->term_destination = &term_closure_destination;
92
+
93
+  dest->closure = closure;
94
+  dest->bufsize = bufsize;
95
+  dest->buffer = (JOCTET *)malloc(bufsize);
96
+
97
+  cinfo->dest->next_output_byte = dest->buffer;
98
+  cinfo->dest->free_in_buffer = dest->bufsize;
99
+}
100
+
101
+void
102
+write_to_jpeg_stream(cairo_surface_t *surface, int bufsize, int quality, bool progressive, closure_t *closure){
103
+  int w = cairo_image_surface_get_width(surface);
104
+  int h = cairo_image_surface_get_height(surface);
105
+  struct jpeg_compress_struct cinfo;
106
+  struct jpeg_error_mgr jerr;
107
+
108
+  JSAMPROW slr;
109
+  cinfo.err = jpeg_std_error(&jerr);
110
+  jpeg_create_compress(&cinfo);
111
+  cinfo.in_color_space = JCS_RGB;
112
+  cinfo.input_components = 3;
113
+  cinfo.image_width = w;
114
+  cinfo.image_height = h;
115
+  jpeg_set_defaults(&cinfo);
116
+  if (progressive)
117
+     jpeg_simple_progression(&cinfo);
118
+  jpeg_set_quality(&cinfo, quality, (quality<25)?0:1);
119
+  jpeg_closure_dest(&cinfo, closure, bufsize);
120
+
121
+  jpeg_start_compress(&cinfo, TRUE);
122
+  unsigned char *dst;
123
+  unsigned int *src = (unsigned int *) cairo_image_surface_get_data(surface);
124
+  int sl = 0;
125
+  dst = (unsigned char *) malloc(w * 3);
126
+  while (sl < h) {
127
+    unsigned char *dp = dst;
128
+    int x = 0;
129
+    while (x < w) {
130
+      dp[0] = (*src >> 16) & 255;
131
+      dp[1] = (*src >> 8) & 255;
132
+      dp[2] = *src & 255;
133
+      src++;
134
+      dp += 3;
135
+      x++;
136
+    }
137
+    slr = dst;
138
+    jpeg_write_scanlines(&cinfo, &slr, 1);
139
+    sl++;
140
+  }
141
+  free(dst);
142
+  jpeg_finish_compress(&cinfo);
143
+  jpeg_destroy_compress(&cinfo);
144
+}
145
+
146
+#endif

+ 227 - 0
vendor/canvas/src/PNG.h Wyświetl plik

@@ -0,0 +1,227 @@
1
+#ifndef _CANVAS_PNG_H
2
+#define _CANVAS_PNG_H
3
+#include <png.h>
4
+#include <pngconf.h>
5
+#include <cairo.h>
6
+#include <stdlib.h>
7
+#include <string.h>
8
+#include "closure.h"
9
+
10
+#if defined(__GNUC__) && (__GNUC__ > 2) && defined(__OPTIMIZE__)
11
+#define likely(expr) (__builtin_expect (!!(expr), 1))
12
+#define unlikely(expr) (__builtin_expect (!!(expr), 0))
13
+#else
14
+#define likely(expr) (expr)
15
+#define unlikely(expr) (expr)
16
+#endif
17
+
18
+#ifndef CAIRO_FORMAT_INVALID
19
+#define CAIRO_FORMAT_INVALID -1
20
+#endif
21
+
22
+static void canvas_png_flush(png_structp png_ptr) {
23
+    /* Do nothing; fflush() is said to be just a waste of energy. */
24
+    (void) png_ptr;   /* Stifle compiler warning */
25
+}
26
+
27
+/* Converts native endian xRGB => RGBx bytes */
28
+static void canvas_convert_data_to_bytes(png_structp png, png_row_infop row_info, png_bytep data) {
29
+    unsigned int i;
30
+
31
+    for (i = 0; i < row_info->rowbytes; i += 4) {
32
+        uint8_t *b = &data[i];
33
+        uint32_t pixel;
34
+
35
+        memcpy(&pixel, b, sizeof (uint32_t));
36
+
37
+        b[0] = (pixel & 0xff0000) >> 16;
38
+        b[1] = (pixel & 0x00ff00) >>  8;
39
+        b[2] = (pixel & 0x0000ff) >>  0;
40
+        b[3] = 0;
41
+    }
42
+}
43
+
44
+/* Unpremultiplies data and converts native endian ARGB => RGBA bytes */
45
+static void canvas_unpremultiply_data(png_structp png, png_row_infop row_info, png_bytep data) {
46
+    unsigned int i;
47
+
48
+    for (i = 0; i < row_info->rowbytes; i += 4) {
49
+        uint8_t *b = &data[i];
50
+        uint32_t pixel;
51
+        uint8_t  alpha;
52
+
53
+        memcpy(&pixel, b, sizeof (uint32_t));
54
+        alpha = (pixel & 0xff000000) >> 24;
55
+        if (alpha == 0) {
56
+            b[0] = b[1] = b[2] = b[3] = 0;
57
+        } else {
58
+            b[0] = (((pixel & 0xff0000) >> 16) * 255 + alpha / 2) / alpha;
59
+            b[1] = (((pixel & 0x00ff00) >>  8) * 255 + alpha / 2) / alpha;
60
+            b[2] = (((pixel & 0x0000ff) >>  0) * 255 + alpha / 2) / alpha;
61
+            b[3] = alpha;
62
+        }
63
+    }
64
+}
65
+
66
+struct canvas_png_write_closure_t {
67
+    cairo_write_func_t write_func;
68
+    void *closure;
69
+};
70
+
71
+static cairo_status_t canvas_write_png(cairo_surface_t *surface, png_rw_ptr write_func, void *closure) {
72
+    unsigned int i;
73
+    cairo_status_t status = CAIRO_STATUS_SUCCESS;
74
+    uint8_t *data;
75
+    png_structp png;
76
+    png_infop info;
77
+    png_bytep *volatile rows = NULL;
78
+    png_color_16 white;
79
+    int png_color_type;
80
+    int bpc;
81
+    unsigned int width = cairo_image_surface_get_width(surface);
82
+    unsigned int height = cairo_image_surface_get_height(surface);
83
+
84
+    data = cairo_image_surface_get_data(surface);
85
+    if (data == NULL) {
86
+        status = CAIRO_STATUS_SURFACE_TYPE_MISMATCH;
87
+        return status;
88
+    }
89
+    cairo_surface_flush(surface);
90
+
91
+    if (width == 0 || height == 0) {
92
+        status = CAIRO_STATUS_WRITE_ERROR;
93
+        return status;
94
+    }
95
+
96
+    rows = (png_bytep *) malloc(height * sizeof (png_byte*));
97
+    if (unlikely(rows == NULL)) {
98
+        status = CAIRO_STATUS_NO_MEMORY;
99
+        return status;
100
+    }
101
+
102
+    for (i = 0; i < height; i++) {
103
+	rows[i] = (png_byte *) data + i * cairo_image_surface_get_stride(surface);
104
+    }
105
+
106
+#ifdef PNG_USER_MEM_SUPPORTED
107
+     png = png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, NULL, NULL, NULL);
108
+#else
109
+    png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
110
+#endif
111
+
112
+    if (unlikely(png == NULL)) {
113
+        status = CAIRO_STATUS_NO_MEMORY;
114
+        free(rows);
115
+        return status;
116
+    }
117
+
118
+    info = png_create_info_struct (png);
119
+    if (unlikely(info == NULL)) {
120
+        status = CAIRO_STATUS_NO_MEMORY;
121
+        png_destroy_write_struct(&png, &info);
122
+        free(rows);
123
+        return status;
124
+
125
+    }
126
+
127
+#ifdef PNG_SETJMP_SUPPORTED
128
+    if (setjmp (png_jmpbuf (png))) {
129
+        png_destroy_write_struct(&png, &info);
130
+        free(rows);
131
+        return status;
132
+    }
133
+#endif
134
+
135
+    png_set_write_fn(png, closure, write_func, canvas_png_flush);
136
+    png_set_compression_level(png, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->compression_level);
137
+    png_set_filter(png, 0, ((closure_t *) ((canvas_png_write_closure_t *) closure)->closure)->filter);
138
+
139
+    switch (cairo_image_surface_get_format(surface)) {
140
+    case CAIRO_FORMAT_ARGB32:
141
+        bpc = 8;
142
+        png_color_type = PNG_COLOR_TYPE_RGB_ALPHA;
143
+        break;
144
+#ifdef CAIRO_FORMAT_RGB30
145
+    case CAIRO_FORMAT_RGB30:
146
+        bpc = 10;
147
+        png_color_type = PNG_COLOR_TYPE_RGB;
148
+        break;
149
+#endif
150
+    case CAIRO_FORMAT_RGB24:
151
+        bpc = 8;
152
+        png_color_type = PNG_COLOR_TYPE_RGB;
153
+        break;
154
+    case CAIRO_FORMAT_A8:
155
+        bpc = 8;
156
+        png_color_type = PNG_COLOR_TYPE_GRAY;
157
+        break;
158
+    case CAIRO_FORMAT_A1:
159
+        bpc = 1;
160
+        png_color_type = PNG_COLOR_TYPE_GRAY;
161
+#ifndef WORDS_BIGENDIAN
162
+        png_set_packswap(png);
163
+#endif
164
+        break;
165
+    case CAIRO_FORMAT_INVALID:
166
+    case CAIRO_FORMAT_RGB16_565:
167
+    default:
168
+        status = CAIRO_STATUS_INVALID_FORMAT;
169
+        png_destroy_write_struct(&png, &info);
170
+        free(rows);
171
+        return status;
172
+    }
173
+
174
+    png_set_IHDR(png, info, width, height, bpc, png_color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
175
+
176
+    white.gray = (1 << bpc) - 1;
177
+    white.red = white.blue = white.green = white.gray;
178
+    png_set_bKGD(png, info, &white);
179
+
180
+    /* We have to call png_write_info() before setting up the write
181
+     * transformation, since it stores data internally in 'png'
182
+     * that is needed for the write transformation functions to work.
183
+     */
184
+    png_write_info(png, info);
185
+    if (png_color_type == PNG_COLOR_TYPE_RGB_ALPHA) {
186
+        png_set_write_user_transform_fn(png, canvas_unpremultiply_data);
187
+    } else if (png_color_type == PNG_COLOR_TYPE_RGB) {
188
+        png_set_write_user_transform_fn(png, canvas_convert_data_to_bytes);
189
+        png_set_filler(png, 0, PNG_FILLER_AFTER);
190
+    }
191
+
192
+    png_write_image(png, rows);
193
+    png_write_end(png, info);
194
+
195
+    png_destroy_write_struct(&png, &info);
196
+    free(rows);
197
+    return status;
198
+}
199
+
200
+static void canvas_stream_write_func(png_structp png, png_bytep data, png_size_t size) {
201
+    cairo_status_t status;
202
+    struct canvas_png_write_closure_t *png_closure;
203
+
204
+    png_closure = (struct canvas_png_write_closure_t *) png_get_io_ptr(png);
205
+    status = png_closure->write_func(png_closure->closure, data, size);
206
+    if (unlikely(status)) {
207
+        cairo_status_t *error = (cairo_status_t *) png_get_error_ptr(png);
208
+        if (*error == CAIRO_STATUS_SUCCESS) {
209
+            *error = status;
210
+        }
211
+        png_error(png, NULL);
212
+    }
213
+}
214
+
215
+static cairo_status_t canvas_write_to_png_stream(cairo_surface_t *surface, cairo_write_func_t write_func, void *closure) {
216
+    struct canvas_png_write_closure_t png_closure;
217
+
218
+    if (cairo_surface_status(surface)) {
219
+        return cairo_surface_status(surface);
220
+    }
221
+
222
+    png_closure.write_func = write_func;
223
+    png_closure.closure = closure;
224
+
225
+    return canvas_write_png(surface, canvas_stream_write_func, &png_closure);
226
+}
227
+#endif

+ 19 - 0
vendor/canvas/src/Point.h Wyświetl plik

@@ -0,0 +1,19 @@
1
+
2
+
3
+//
4
+// Point.h
5
+//
6
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
7
+//
8
+
9
+#ifndef __NODE_POINT_H__
10
+#define __NODE_POINT_H__
11
+
12
+template <class T>
13
+class Point {
14
+  public:
15
+    T x, y;
16
+    Point(T x, T y): x(x), y(y) {}
17
+};
18
+
19
+#endif /* __NODE_POINT_H__ */

+ 65 - 0
vendor/canvas/src/closure.h Wyświetl plik

@@ -0,0 +1,65 @@
1
+
2
+//
3
+// closure.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __NODE_CLOSURE_H__
9
+#define __NODE_CLOSURE_H__
10
+
11
+#ifdef __unix__
12
+  #include<sys/user.h>
13
+#endif
14
+
15
+#ifndef PAGE_SIZE
16
+  #define PAGE_SIZE 4096
17
+#endif
18
+
19
+#include <nan.h>
20
+
21
+/*
22
+ * PNG stream closure.
23
+ */
24
+
25
+typedef struct {
26
+  Nan::Callback *pfn;
27
+  Local<Function> fn;
28
+  unsigned len;
29
+  unsigned max_len;
30
+  uint8_t *data;
31
+  Canvas *canvas;
32
+  cairo_status_t status;
33
+  uint32_t compression_level;
34
+  uint32_t filter;
35
+} closure_t;
36
+
37
+/*
38
+ * Initialize the given closure.
39
+ */
40
+
41
+cairo_status_t
42
+closure_init(closure_t *closure, Canvas *canvas, unsigned int compression_level, unsigned int filter) {
43
+  closure->len = 0;
44
+  closure->canvas = canvas;
45
+  closure->data = (uint8_t *) malloc(closure->max_len = PAGE_SIZE);
46
+  if (!closure->data) return CAIRO_STATUS_NO_MEMORY;
47
+  closure->compression_level = compression_level;
48
+  closure->filter = filter;
49
+  return CAIRO_STATUS_SUCCESS;
50
+}
51
+
52
+/*
53
+ * Free the given closure's data,
54
+ * and hint V8 at the memory dealloc.
55
+ */
56
+
57
+void
58
+closure_destroy(closure_t *closure) {
59
+  if (closure->len) {
60
+    free(closure->data);
61
+    Nan::AdjustExternalMemory(-((intptr_t) closure->max_len));
62
+  }
63
+}
64
+
65
+#endif /* __NODE_CLOSURE_H__ */

+ 744 - 0
vendor/canvas/src/color.cc Wyświetl plik

@@ -0,0 +1,744 @@
1
+
2
+//
3
+// color.cc
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#include "color.h"
9
+#include <stdlib.h>
10
+#include <cmath>
11
+#include <limits>
12
+
13
+// Compatibility with Visual Studio versions prior to VS2015
14
+#if defined(_MSC_VER) && _MSC_VER < 1900
15
+#define snprintf _snprintf
16
+#endif
17
+
18
+/*
19
+ * Parse integer value
20
+ */
21
+
22
+template <typename parsed_t>
23
+static bool
24
+parse_integer(const char** pStr, parsed_t *pParsed) {
25
+  parsed_t& c = *pParsed;
26
+  const char*& str = *pStr;
27
+  int8_t sign=1;
28
+
29
+  c = 0;
30
+  if (*str == '-') {
31
+    sign=-1;
32
+    ++str;
33
+  }
34
+  else if (*str == '+')
35
+    ++str;
36
+
37
+  if (*str >= '0' && *str <= '9') {
38
+     do {
39
+       c *= 10;
40
+       c += *str++ - '0';
41
+     } while (*str >= '0' && *str <= '9');
42
+   } else {
43
+     return false;
44
+   }
45
+   if (sign<0)
46
+    c=-c;
47
+   return true;
48
+}
49
+
50
+
51
+/*
52
+ * Parse CSS <number> value
53
+ * Adapted from http://crackprogramming.blogspot.co.il/2012/10/implement-atof.html
54
+ */
55
+
56
+template <typename parsed_t>
57
+static bool
58
+parse_css_number(const char** pStr, parsed_t *pParsed) {
59
+   parsed_t &parsed = *pParsed;
60
+   const char*& str = *pStr;
61
+   const char* startStr = str;
62
+   if (!str || !*str)
63
+       return false; 
64
+   parsed_t integerPart = 0;
65
+   parsed_t fractionPart = 0;
66
+   int divisorForFraction = 1;
67
+   int sign = 1;
68
+   int exponent = 0;
69
+   int digits = 0;
70
+   bool inFraction = false;
71
+  
72
+   if (*str == '-') {
73
+       ++str;
74
+       sign = -1;
75
+   }
76
+   else if (*str == '+')
77
+       ++str;
78
+   while (*str != '\0') {
79
+       if (*str >= '0' && *str <= '9') {
80
+          if (digits>=std::numeric_limits<parsed_t>::digits10) {
81
+            if (!inFraction)
82
+              return false;
83
+          }
84
+          else {
85
+            ++digits;
86
+          
87
+            if (inFraction) {
88
+                fractionPart = fractionPart*10 + (*str - '0');
89
+                divisorForFraction *= 10;
90
+            }
91
+            else {
92
+                integerPart = integerPart*10 + (*str - '0');
93
+            }
94
+          }
95
+       }
96
+       else if (*str == '.') {
97
+           if (inFraction)
98
+               break;
99
+           else
100
+               inFraction = true;
101
+       }
102
+       else if (*str == 'e') {
103
+          ++str;
104
+          if (!parse_integer(&str, &exponent))
105
+            return false;
106
+          break;
107
+       }
108
+       else
109
+          break;
110
+       ++str;
111
+   }
112
+   if (str != startStr) {
113
+      parsed = sign * (integerPart + fractionPart/divisorForFraction);
114
+      for (;exponent>0;--exponent)
115
+        parsed *= 10;
116
+      for (;exponent<0;++exponent)
117
+        parsed /= 10;
118
+      return true;
119
+   }
120
+   return false;
121
+}
122
+
123
+/*
124
+ * Clip value to the range [minValue, maxValue]
125
+ */
126
+
127
+template <typename T>
128
+static T
129
+clip(T value, T minValue, T maxValue) {
130
+  if (value > maxValue)
131
+      value = maxValue;
132
+  if (value < minValue)
133
+      value = minValue;
134
+  return value;
135
+}
136
+
137
+/*
138
+ * Wrap value to the range [0, limit]
139
+ */
140
+ 
141
+template <typename T>
142
+static T
143
+wrap_float(T value, T limit) {
144
+  return fmod(fmod(value, limit) + limit, limit);
145
+}
146
+
147
+/*
148
+ * Wrap value to the range [0, limit] - currently-unused integer version of wrap_float
149
+ */
150
+
151
+// template <typename T>
152
+// static T wrap_int(T value, T limit) {
153
+//   return (value % limit + limit) % limit;
154
+// }
155
+
156
+/*
157
+ * Parse color channel value
158
+ */
159
+
160
+static bool
161
+parse_rgb_channel(const char** pStr, uint8_t *pChannel) {
162
+  int channel;
163
+  if (parse_integer(pStr, &channel)) {
164
+    *pChannel = clip(channel, 0, 255);
165
+    return true;
166
+  }
167
+  return false;
168
+}
169
+
170
+/*
171
+ * Parse a value in degrees
172
+ */
173
+
174
+static bool
175
+parse_degrees(const char** pStr, float *pDegrees) {
176
+  float degrees;
177
+  if (parse_css_number(pStr, &degrees)) {
178
+    *pDegrees = wrap_float(degrees, 360.0f);
179
+    return true;
180
+  }
181
+  return false;
182
+}
183
+
184
+/*
185
+ * Parse and clip a percentage value. Returns a float in the range [0, 1].
186
+ */
187
+
188
+static bool
189
+parse_clipped_percentage(const char** pStr, float *pFraction) { 
190
+  float percentage;
191
+  bool result = parse_css_number(pStr,&percentage);
192
+  const char*& str = *pStr;
193
+  if (result) {
194
+    if (*str == '%') {
195
+      ++str;
196
+      *pFraction = clip(percentage, 0.0f, 100.0f) / 100.0f;
197
+      return result;
198
+    }
199
+  }
200
+  return false;
201
+}
202
+
203
+/*
204
+ * Macros to help with parsing inside rgba_from_*_string
205
+ */
206
+
207
+#define WHITESPACE \
208
+  while (' ' == *str) ++str;
209
+
210
+#define WHITESPACE_OR_COMMA \
211
+  while (' ' == *str || ',' == *str) ++str;
212
+
213
+#define CHANNEL(NAME) \
214
+   if (!parse_rgb_channel(&str, &NAME)) \
215
+    return 0; \
216
+
217
+#define HUE(NAME) \
218
+   if (!parse_degrees(&str, &NAME)) \
219
+    return 0;
220
+
221
+#define SATURATION(NAME) \
222
+   if (!parse_clipped_percentage(&str, &NAME)) \
223
+    return 0;
224
+
225
+#define LIGHTNESS(NAME) SATURATION(NAME)
226
+
227
+#define ALPHA(NAME) \
228
+  if (*str >= '1' && *str <= '9') { \
229
+      NAME = 1; \
230
+    } else { \
231
+      if ('0' == *str) ++str; \
232
+      if ('.' == *str) { \
233
+        ++str; \
234
+        float n = .1f; \
235
+        while (*str >= '0' && *str <= '9') { \
236
+          NAME += (*str++ - '0') * n; \
237
+          n *= .1f; \
238
+        } \
239
+      } \
240
+    } \
241
+    do {} while (0) // require trailing semicolon
242
+
243
+/*
244
+ * Named colors.
245
+ */
246
+
247
+static struct named_color {
248
+  const char *name;
249
+  uint32_t val;
250
+} named_colors[] = {
251
+    { "transparent", 0xFFFFFF00}
252
+  , { "aliceblue", 0xF0F8FFFF }
253
+  , { "antiquewhite", 0xFAEBD7FF }
254
+  , { "aqua", 0x00FFFFFF }
255
+  , { "aquamarine", 0x7FFFD4FF }
256
+  , { "azure", 0xF0FFFFFF }
257
+  , { "beige", 0xF5F5DCFF }
258
+  , { "bisque", 0xFFE4C4FF }
259
+  , { "black", 0x000000FF }
260
+  , { "blanchedalmond", 0xFFEBCDFF }
261
+  , { "blue", 0x0000FFFF }
262
+  , { "blueviolet", 0x8A2BE2FF }
263
+  , { "brown", 0xA52A2AFF }
264
+  , { "burlywood", 0xDEB887FF }
265
+  , { "cadetblue", 0x5F9EA0FF }
266
+  , { "chartreuse", 0x7FFF00FF }
267
+  , { "chocolate", 0xD2691EFF }
268
+  , { "coral", 0xFF7F50FF }
269
+  , { "cornflowerblue", 0x6495EDFF }
270
+  , { "cornsilk", 0xFFF8DCFF }
271
+  , { "crimson", 0xDC143CFF }
272
+  , { "cyan", 0x00FFFFFF }
273
+  , { "darkblue", 0x00008BFF }
274
+  , { "darkcyan", 0x008B8BFF }
275
+  , { "darkgoldenrod", 0xB8860BFF }
276
+  , { "darkgray", 0xA9A9A9FF }
277
+  , { "darkgreen", 0x006400FF }
278
+  , { "darkgrey", 0xA9A9A9FF }
279
+  , { "darkkhaki", 0xBDB76BFF }
280
+  , { "darkmagenta", 0x8B008BFF }
281
+  , { "darkolivegreen", 0x556B2FFF }
282
+  , { "darkorange", 0xFF8C00FF }
283
+  , { "darkorchid", 0x9932CCFF }
284
+  , { "darkred", 0x8B0000FF }
285
+  , { "darksalmon", 0xE9967AFF }
286
+  , { "darkseagreen", 0x8FBC8FFF }
287
+  , { "darkslateblue", 0x483D8BFF }
288
+  , { "darkslategray", 0x2F4F4FFF }
289
+  , { "darkslategrey", 0x2F4F4FFF }
290
+  , { "darkturquoise", 0x00CED1FF }
291
+  , { "darkviolet", 0x9400D3FF }
292
+  , { "deeppink", 0xFF1493FF }
293
+  , { "deepskyblue", 0x00BFFFFF }
294
+  , { "dimgray", 0x696969FF }
295
+  , { "dimgrey", 0x696969FF }
296
+  , { "dodgerblue", 0x1E90FFFF }
297
+  , { "firebrick", 0xB22222FF }
298
+  , { "floralwhite", 0xFFFAF0FF }
299
+  , { "forestgreen", 0x228B22FF }
300
+  , { "fuchsia", 0xFF00FFFF }
301
+  , { "gainsboro", 0xDCDCDCFF }
302
+  , { "ghostwhite", 0xF8F8FFFF }
303
+  , { "gold", 0xFFD700FF }
304
+  , { "goldenrod", 0xDAA520FF }
305
+  , { "gray", 0x808080FF }
306
+  , { "green", 0x008000FF }
307
+  , { "greenyellow", 0xADFF2FFF }
308
+  , { "grey", 0x808080FF }
309
+  , { "honeydew", 0xF0FFF0FF }
310
+  , { "hotpink", 0xFF69B4FF }
311
+  , { "indianred", 0xCD5C5CFF }
312
+  , { "indigo", 0x4B0082FF }
313
+  , { "ivory", 0xFFFFF0FF }
314
+  , { "khaki", 0xF0E68CFF }
315
+  , { "lavender", 0xE6E6FAFF }
316
+  , { "lavenderblush", 0xFFF0F5FF }
317
+  , { "lawngreen", 0x7CFC00FF }
318
+  , { "lemonchiffon", 0xFFFACDFF }
319
+  , { "lightblue", 0xADD8E6FF }
320
+  , { "lightcoral", 0xF08080FF }
321
+  , { "lightcyan", 0xE0FFFFFF }
322
+  , { "lightgoldenrodyellow", 0xFAFAD2FF }
323
+  , { "lightgray", 0xD3D3D3FF }
324
+  , { "lightgreen", 0x90EE90FF }
325
+  , { "lightgrey", 0xD3D3D3FF }
326
+  , { "lightpink", 0xFFB6C1FF }
327
+  , { "lightsalmon", 0xFFA07AFF }
328
+  , { "lightseagreen", 0x20B2AAFF }
329
+  , { "lightskyblue", 0x87CEFAFF }
330
+  , { "lightslategray", 0x778899FF }
331
+  , { "lightslategrey", 0x778899FF }
332
+  , { "lightsteelblue", 0xB0C4DEFF }
333
+  , { "lightyellow", 0xFFFFE0FF }
334
+  , { "lime", 0x00FF00FF }
335
+  , { "limegreen", 0x32CD32FF }
336
+  , { "linen", 0xFAF0E6FF }
337
+  , { "magenta", 0xFF00FFFF }
338
+  , { "maroon", 0x800000FF }
339
+  , { "mediumaquamarine", 0x66CDAAFF }
340
+  , { "mediumblue", 0x0000CDFF }
341
+  , { "mediumorchid", 0xBA55D3FF }
342
+  , { "mediumpurple", 0x9370DBFF }
343
+  , { "mediumseagreen", 0x3CB371FF }
344
+  , { "mediumslateblue", 0x7B68EEFF }
345
+  , { "mediumspringgreen", 0x00FA9AFF }
346
+  , { "mediumturquoise", 0x48D1CCFF }
347
+  , { "mediumvioletred", 0xC71585FF }
348
+  , { "midnightblue", 0x191970FF }
349
+  , { "mintcream", 0xF5FFFAFF }
350
+  , { "mistyrose", 0xFFE4E1FF }
351
+  , { "moccasin", 0xFFE4B5FF }
352
+  , { "navajowhite", 0xFFDEADFF }
353
+  , { "navy", 0x000080FF }
354
+  , { "oldlace", 0xFDF5E6FF }
355
+  , { "olive", 0x808000FF }
356
+  , { "olivedrab", 0x6B8E23FF }
357
+  , { "orange", 0xFFA500FF }
358
+  , { "orangered", 0xFF4500FF }
359
+  , { "orchid", 0xDA70D6FF }
360
+  , { "palegoldenrod", 0xEEE8AAFF }
361
+  , { "palegreen", 0x98FB98FF }
362
+  , { "paleturquoise", 0xAFEEEEFF }
363
+  , { "palevioletred", 0xDB7093FF }
364
+  , { "papayawhip", 0xFFEFD5FF }
365
+  , { "peachpuff", 0xFFDAB9FF }
366
+  , { "peru", 0xCD853FFF }
367
+  , { "pink", 0xFFC0CBFF }
368
+  , { "plum", 0xDDA0DDFF }
369
+  , { "powderblue", 0xB0E0E6FF }
370
+  , { "purple", 0x800080FF }
371
+  , { "rebeccapurple", 0x663399FF } // Source: CSS Color Level 4 draft
372
+  , { "red", 0xFF0000FF }
373
+  , { "rosybrown", 0xBC8F8FFF }
374
+  , { "royalblue", 0x4169E1FF }
375
+  , { "saddlebrown", 0x8B4513FF }
376
+  , { "salmon", 0xFA8072FF }
377
+  , { "sandybrown", 0xF4A460FF }
378
+  , { "seagreen", 0x2E8B57FF }
379
+  , { "seashell", 0xFFF5EEFF }
380
+  , { "sienna", 0xA0522DFF }
381
+  , { "silver", 0xC0C0C0FF }
382
+  , { "skyblue", 0x87CEEBFF }
383
+  , { "slateblue", 0x6A5ACDFF }
384
+  , { "slategray", 0x708090FF }
385
+  , { "slategrey", 0x708090FF }
386
+  , { "snow", 0xFFFAFAFF }
387
+  , { "springgreen", 0x00FF7FFF }
388
+  , { "steelblue", 0x4682B4FF }
389
+  , { "tan", 0xD2B48CFF }
390
+  , { "teal", 0x008080FF }
391
+  , { "thistle", 0xD8BFD8FF }
392
+  , { "tomato", 0xFF6347FF }
393
+  , { "turquoise", 0x40E0D0FF }
394
+  , { "violet", 0xEE82EEFF }
395
+  , { "wheat", 0xF5DEB3FF }
396
+  , { "white", 0xFFFFFFFF }
397
+  , { "whitesmoke", 0xF5F5F5FF }
398
+  , { "yellow", 0xFFFF00FF }
399
+  , { "yellowgreen", 0x9ACD32FF }
400
+  , { NULL, 0 }
401
+};
402
+
403
+/*
404
+ * Hex digit int val.
405
+ */
406
+
407
+static int
408
+h(char c) {
409
+  switch (c) {
410
+    case '0':
411
+    case '1':
412
+    case '2':
413
+    case '3':
414
+    case '4':
415
+    case '5':
416
+    case '6':
417
+    case '7':
418
+    case '8':
419
+    case '9':
420
+      return c - '0';
421
+    case 'a':
422
+    case 'b':
423
+    case 'c':
424
+    case 'd':
425
+    case 'e':
426
+    case 'f':
427
+      return (c - 'a') + 10;
428
+    case 'A':
429
+    case 'B':
430
+    case 'C':
431
+    case 'D':
432
+    case 'E':
433
+    case 'F':
434
+      return (c - 'A') + 10;
435
+  }
436
+  return 0;
437
+}
438
+
439
+/*
440
+ * Return rgba_t from rgba.
441
+ */
442
+
443
+rgba_t
444
+rgba_create(uint32_t rgba) {
445
+  rgba_t color;
446
+  color.r = (double) (rgba >> 24) / 255;
447
+  color.g = (double) (rgba >> 16 & 0xff) / 255;
448
+  color.b = (double) (rgba >> 8 & 0xff) / 255;
449
+  color.a = (double) (rgba & 0xff) / 255;
450
+  return color;
451
+}
452
+
453
+/*
454
+ * Return a string representation of the color.
455
+ */
456
+
457
+void
458
+rgba_to_string(rgba_t rgba, char *buf, size_t len) {
459
+  if (1 == rgba.a) {
460
+    snprintf(buf, len, "#%.2x%.2x%.2x"
461
+      , (int) (rgba.r * 255)
462
+      , (int) (rgba.g * 255)
463
+      , (int) (rgba.b * 255));
464
+  } else {
465
+    snprintf(buf, len, "rgba(%d, %d, %d, %.2f)"
466
+      , (int) (rgba.r * 255)
467
+      , (int) (rgba.g * 255)
468
+      , (int) (rgba.b * 255)
469
+      , rgba.a);
470
+  }
471
+}
472
+
473
+/*
474
+ * Return rgba from (r,g,b,a).
475
+ */
476
+
477
+static inline int32_t
478
+rgba_from_rgba(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
479
+  return
480
+      r << 24
481
+    | g << 16
482
+    | b << 8
483
+    | a;
484
+}
485
+
486
+/*
487
+ * Helper function used in rgba_from_hsla().
488
+ * Based on http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
489
+ */
490
+
491
+static float
492
+hue_to_rgb(float t1, float t2, float hue) {
493
+  if (hue < 0)
494
+    hue += 6;
495
+  if (hue >= 6)
496
+    hue -= 6;
497
+
498
+  if (hue < 1)
499
+    return (t2 - t1) * hue + t1;
500
+  else if (hue < 3)
501
+    return t2;
502
+  else if (hue < 4)
503
+    return (t2 - t1) * (4 - hue) + t1;
504
+  else
505
+    return t1;
506
+}
507
+
508
+/*
509
+ * Return rgba from (h,s,l,a).
510
+ * Expects h values in the range [0, 360), and s, l, a in the range [0, 1].
511
+ * Adapted from http://dev.w3.org/csswg/css-color-4/#hsl-to-rgb
512
+ */
513
+
514
+static inline int32_t
515
+rgba_from_hsla(float h_deg, float s, float l, float a) {
516
+  uint8_t r, g, b;
517
+  float h = (6 * h_deg) / 360.0f, m1, m2;
518
+
519
+  if (l<=0.5)
520
+    m2=l*(s+1);
521
+  else
522
+    m2=l+s-l*s;
523
+  m1 = l*2 - m2;
524
+
525
+  // Scale and round the RGB components
526
+  r = (uint8_t)floor(hue_to_rgb(m1, m2, h + 2) * 255 + 0.5);
527
+  g = (uint8_t)floor(hue_to_rgb(m1, m2, h    ) * 255 + 0.5);
528
+  b = (uint8_t)floor(hue_to_rgb(m1, m2, h - 2) * 255 + 0.5);
529
+
530
+  return rgba_from_rgba(r, g, b, (uint8_t) (a * 255));
531
+}
532
+
533
+/*
534
+ * Return rgba from (h,s,l).
535
+ * Expects h values in the range [0, 360), and s, l in the range [0, 1].
536
+ */
537
+
538
+static inline int32_t
539
+rgba_from_hsl(float h_deg, float s, float l) {
540
+  return rgba_from_hsla(h_deg, s, l, 1.0);
541
+}
542
+
543
+
544
+/*
545
+ * Return rgba from (r,g,b).
546
+ */
547
+
548
+static int32_t
549
+rgba_from_rgb(uint8_t r, uint8_t g, uint8_t b) {
550
+  return rgba_from_rgba(r, g, b, 255);
551
+}
552
+
553
+/*
554
+ * Return rgb from "#RRGGBB".
555
+ */
556
+
557
+static int32_t
558
+rgba_from_hex6_string(const char *str) {
559
+  return rgba_from_rgb(
560
+      (h(str[0]) << 4) + h(str[1])
561
+    , (h(str[2]) << 4) + h(str[3])
562
+    , (h(str[4]) << 4) + h(str[5])
563
+    );
564
+}
565
+
566
+/*
567
+ * Return rgb from "#RGB"
568
+ */
569
+
570
+static int32_t
571
+rgba_from_hex3_string(const char *str) {
572
+  return rgba_from_rgb(
573
+      (h(str[0]) << 4) + h(str[0])
574
+    , (h(str[1]) << 4) + h(str[1])
575
+    , (h(str[2]) << 4) + h(str[2])
576
+    );
577
+}
578
+
579
+/*
580
+ * Return rgb from "rgb()"
581
+ */
582
+
583
+static int32_t
584
+rgba_from_rgb_string(const char *str, short *ok) {
585
+  if (str == strstr(str, "rgb(")) {
586
+    str += 4;
587
+    WHITESPACE;
588
+    uint8_t r = 0, g = 0, b = 0;
589
+    CHANNEL(r);
590
+    WHITESPACE_OR_COMMA;
591
+    CHANNEL(g);
592
+    WHITESPACE_OR_COMMA;
593
+    CHANNEL(b);
594
+    WHITESPACE;
595
+    return *ok = 1, rgba_from_rgb(r, g, b);
596
+  }
597
+  return *ok = 0;
598
+}
599
+
600
+/*
601
+ * Return rgb from "rgba()"
602
+ */
603
+
604
+static int32_t
605
+rgba_from_rgba_string(const char *str, short *ok) {
606
+  if (str == strstr(str, "rgba(")) {
607
+    str += 5;
608
+    WHITESPACE;
609
+    uint8_t r = 0, g = 0, b = 0;
610
+    float a = 0;
611
+    CHANNEL(r);
612
+    WHITESPACE_OR_COMMA;
613
+    CHANNEL(g);
614
+    WHITESPACE_OR_COMMA;
615
+    CHANNEL(b);
616
+    WHITESPACE_OR_COMMA;
617
+    ALPHA(a);
618
+    WHITESPACE;
619
+    return *ok = 1, rgba_from_rgba(r, g, b, (int) (a * 255));
620
+  }
621
+  return *ok = 0;
622
+}
623
+
624
+/*
625
+ * Return rgb from "hsla()"
626
+ */
627
+
628
+static int32_t
629
+rgba_from_hsla_string(const char *str, short *ok) {
630
+  if (str == strstr(str, "hsla(")) {
631
+    str += 5;
632
+    WHITESPACE;
633
+    float h_deg = 0;
634
+    float s = 0, l = 0;
635
+    float a = 0;
636
+    HUE(h_deg);
637
+    WHITESPACE_OR_COMMA;
638
+    SATURATION(s);
639
+    WHITESPACE_OR_COMMA;
640
+    LIGHTNESS(l);
641
+    WHITESPACE_OR_COMMA;
642
+    ALPHA(a);
643
+    WHITESPACE;
644
+    return *ok = 1, rgba_from_hsla(h_deg, s, l, a);
645
+  }
646
+  return *ok = 0;
647
+}
648
+
649
+/*
650
+ * Return rgb from "hsl()"
651
+ */
652
+
653
+static int32_t
654
+rgba_from_hsl_string(const char *str, short *ok) {
655
+  if (str == strstr(str, "hsl(")) {
656
+    str += 4;
657
+    WHITESPACE;
658
+    float h_deg = 0;
659
+    float s = 0, l = 0;
660
+    HUE(h_deg);
661
+    WHITESPACE_OR_COMMA;
662
+    SATURATION(s);
663
+    WHITESPACE_OR_COMMA;
664
+    LIGHTNESS(l);
665
+    WHITESPACE;
666
+    return *ok = 1, rgba_from_hsl(h_deg, s, l);
667
+  }
668
+  return *ok = 0;
669
+}
670
+
671
+
672
+/*
673
+ * Return rgb from:
674
+ *  
675
+ *  - "#RGB"
676
+ *  - "#RRGGBB"
677
+ *
678
+ */
679
+
680
+static int32_t
681
+rgba_from_hex_string(const char *str, short *ok) {
682
+  size_t len = strlen(str);
683
+  *ok = 1;
684
+  if (6 == len) return rgba_from_hex6_string(str);
685
+  if (3 == len) return rgba_from_hex3_string(str);
686
+  return *ok = 0;
687
+}
688
+
689
+/*
690
+ * Return named color value.
691
+ */
692
+
693
+static int32_t
694
+rgba_from_name_string(const char *str, short *ok) {
695
+  int i = 0;
696
+  struct named_color color;
697
+  while ((color = named_colors[i++]).name) {
698
+    if (*str == *color.name && 0 == strcmp(str, color.name))
699
+      return *ok = 1, color.val;
700
+  }
701
+  return *ok = 0;
702
+}
703
+
704
+/*
705
+ * Return rgb from:
706
+ *  
707
+ *  - #RGB
708
+ *  - #RRGGBB
709
+ *  - rgb(r,g,b)
710
+ *  - rgba(r,g,b,a)
711
+ *  - hsl(h,s,l)
712
+ *  - hsla(h,s,l,a)
713
+ *  - name
714
+ *
715
+ */
716
+
717
+int32_t
718
+rgba_from_string(const char *str, short *ok) {
719
+  if ('#' == str[0]) 
720
+    return rgba_from_hex_string(++str, ok);
721
+  if (str == strstr(str, "rgba"))
722
+    return rgba_from_rgba_string(str, ok);
723
+  if (str == strstr(str, "rgb"))
724
+    return rgba_from_rgb_string(str, ok);
725
+  if (str == strstr(str, "hsla"))
726
+    return rgba_from_hsla_string(str, ok);
727
+  if (str == strstr(str, "hsl"))
728
+    return rgba_from_hsl_string(str, ok);
729
+  return rgba_from_name_string(str, ok);
730
+}
731
+
732
+/*
733
+ * Inspect the given rgba color.
734
+ */
735
+
736
+void
737
+rgba_inspect(int32_t rgba) {
738
+  printf("rgba(%d,%d,%d,%d)\n"
739
+    , rgba >> 24 & 0xff
740
+    , rgba >> 16 & 0xff
741
+    , rgba >> 8 & 0xff
742
+    , rgba & 0xff
743
+    );
744
+}

+ 40 - 0
vendor/canvas/src/color.h Wyświetl plik

@@ -0,0 +1,40 @@
1
+
2
+//
3
+// color.h
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#ifndef __COLOR_PARSER_H__
9
+#define __COLOR_PARSER_H__
10
+
11
+#include <stdio.h>
12
+#include <stdint.h>
13
+#include <string.h>
14
+#include <stddef.h>
15
+
16
+/*
17
+ * RGBA struct.
18
+ */
19
+
20
+typedef struct {
21
+  double r, g, b, a;
22
+} rgba_t;
23
+
24
+/*
25
+ * Prototypes.
26
+ */
27
+
28
+rgba_t
29
+rgba_create(uint32_t rgba);
30
+
31
+int32_t
32
+rgba_from_string(const char *str, short *ok);
33
+
34
+void
35
+rgba_to_string(rgba_t rgba, char *buf, size_t len);
36
+
37
+void
38
+rgba_inspect(int32_t rgba);
39
+
40
+#endif /* __COLOR_PARSER_H__ */

+ 76 - 0
vendor/canvas/src/init.cc Wyświetl plik

@@ -0,0 +1,76 @@
1
+
2
+//
3
+// init.cc
4
+//
5
+// Copyright (c) 2010 LearnBoost <tj@learnboost.com>
6
+//
7
+
8
+#include <stdio.h>
9
+#include <pango/pango.h>
10
+#include <glib.h>
11
+#include "Canvas.h"
12
+#include "Image.h"
13
+#include "ImageData.h"
14
+#include "CanvasGradient.h"
15
+#include "CanvasPattern.h"
16
+#include "CanvasRenderingContext2d.h"
17
+#include <ft2build.h>
18
+#include FT_FREETYPE_H
19
+
20
+// Compatibility with Visual Studio versions prior to VS2015
21
+#if defined(_MSC_VER) && _MSC_VER < 1900
22
+#define snprintf _snprintf
23
+#endif
24
+
25
+NAN_MODULE_INIT(init) {
26
+  Canvas::Initialize(target);
27
+  Image::Initialize(target);
28
+  ImageData::Initialize(target);
29
+  Context2d::Initialize(target);
30
+  Gradient::Initialize(target);
31
+  Pattern::Initialize(target);
32
+
33
+  target->Set(Nan::New<String>("cairoVersion").ToLocalChecked(), Nan::New<String>(cairo_version_string()).ToLocalChecked());
34
+#ifdef HAVE_JPEG
35
+
36
+#ifndef JPEG_LIB_VERSION_MAJOR
37
+#ifdef JPEG_LIB_VERSION
38
+#define JPEG_LIB_VERSION_MAJOR (JPEG_LIB_VERSION / 10)
39
+#else
40
+#define JPEG_LIB_VERSION_MAJOR 0
41
+#endif
42
+#endif
43
+
44
+#ifndef JPEG_LIB_VERSION_MINOR
45
+#ifdef JPEG_LIB_VERSION
46
+#define JPEG_LIB_VERSION_MINOR (JPEG_LIB_VERSION % 10)
47
+#else
48
+#define JPEG_LIB_VERSION_MINOR 0
49
+#endif
50
+#endif
51
+
52
+  char jpeg_version[10];
53
+  if (JPEG_LIB_VERSION_MINOR > 0) {
54
+    snprintf(jpeg_version, 10, "%d%c", JPEG_LIB_VERSION_MAJOR, JPEG_LIB_VERSION_MINOR + 'a' - 1);
55
+  } else {
56
+    snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR);
57
+  }
58
+  target->Set(Nan::New<String>("jpegVersion").ToLocalChecked(), Nan::New<String>(jpeg_version).ToLocalChecked());
59
+#endif
60
+
61
+#ifdef HAVE_GIF
62
+#ifndef GIF_LIB_VERSION
63
+  char gif_version[10];
64
+  snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE);
65
+  target->Set(Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(gif_version).ToLocalChecked());
66
+#else
67
+  target->Set(Nan::New<String>("gifVersion").ToLocalChecked(), Nan::New<String>(GIF_LIB_VERSION).ToLocalChecked());
68
+#endif
69
+#endif
70
+
71
+  char freetype_version[10];
72
+  snprintf(freetype_version, 10, "%d.%d.%d", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH);
73
+  target->Set(Nan::New<String>("freetypeVersion").ToLocalChecked(), Nan::New<String>(freetype_version).ToLocalChecked());
74
+}
75
+
76
+NODE_MODULE(canvas,init);

+ 247 - 0
vendor/canvas/src/register_font.cc Wyświetl plik

@@ -0,0 +1,247 @@
1
+#include <pango/pangocairo.h>
2
+#include <pango/pango-fontmap.h>
3
+#include <pango/pango.h>
4
+
5
+#ifdef __APPLE__
6
+#include <CoreText/CoreText.h>
7
+#elif defined(_WIN32)
8
+#include <windows.h>
9
+#else
10
+#include <fontconfig/fontconfig.h>
11
+#endif
12
+
13
+#include <ft2build.h>
14
+#include FT_FREETYPE_H
15
+#include FT_TRUETYPE_TABLES_H
16
+#include FT_SFNT_NAMES_H
17
+#include FT_TRUETYPE_IDS_H
18
+#ifndef FT_SFNT_OS2
19
+#define FT_SFNT_OS2 ft_sfnt_os2
20
+#endif
21
+
22
+// OSX seems to read the strings in MacRoman encoding and ignore Unicode entries.
23
+// You can verify this by opening a TTF with both Unicode and Macroman on OSX.
24
+// It uses the MacRoman name, while Fontconfig and Windows use Unicode
25
+#ifdef __APPLE__
26
+#define PREFERRED_PLATFORM_ID TT_PLATFORM_MACINTOSH
27
+#define PREFERRED_ENCODING_ID TT_MAC_ID_ROMAN
28
+#else
29
+#define PREFERRED_PLATFORM_ID TT_PLATFORM_MICROSOFT
30
+#define PREFERRED_ENCODING_ID TT_MS_ID_UNICODE_CS
31
+#endif
32
+
33
+#define IS_PREFERRED_ENC(X) \
34
+  X.platform_id == PREFERRED_PLATFORM_ID && X.encoding_id == PREFERRED_ENCODING_ID
35
+
36
+#define GET_NAME_RANK(X) \
37
+  (IS_PREFERRED_ENC(X) ? 1 : 0) + (X.name_id == TT_NAME_ID_PREFERRED_FAMILY ? 1 : 0)
38
+
39
+/*
40
+ * Return a UTF-8 encoded string given a TrueType name buf+len
41
+ * and its platform and encoding
42
+ */
43
+
44
+char *
45
+to_utf8(FT_Byte* buf, FT_UInt len, FT_UShort pid, FT_UShort eid) {
46
+  size_t ret_len = len * 4; // max chars in a utf8 string
47
+  char *ret = (char*)malloc(ret_len + 1); // utf8 string + null
48
+
49
+  if (!ret) return NULL;
50
+
51
+  // In my testing of hundreds of fonts from the Google Font repo, the two types
52
+  // of fonts are TT_PLATFORM_MICROSOFT with TT_MS_ID_UNICODE_CS encoding, or
53
+  // TT_PLATFORM_MACINTOSH with TT_MAC_ID_ROMAN encoding. Usually both, never neither
54
+
55
+  char const *fromcode;
56
+
57
+  if (pid == TT_PLATFORM_MACINTOSH && eid == TT_MAC_ID_ROMAN) {
58
+    fromcode = "MAC";
59
+  } else if (pid == TT_PLATFORM_MICROSOFT && eid == TT_MS_ID_UNICODE_CS) {
60
+    fromcode = "UTF-16BE";
61
+  } else {
62
+    free(ret);
63
+    return NULL;
64
+  }
65
+
66
+  GIConv cd = g_iconv_open("UTF-8", fromcode);
67
+
68
+  if (cd == (GIConv)-1) {
69
+    free(ret);
70
+    return NULL;
71
+  }
72
+
73
+  size_t inbytesleft = len;
74
+  size_t outbytesleft = ret_len;
75
+
76
+  size_t n_converted = g_iconv(cd, (char**)&buf, &inbytesleft, &ret, &outbytesleft);
77
+
78
+  ret -= ret_len - outbytesleft; // rewind the pointers to their
79
+  buf -= len - inbytesleft;      // original starting positions
80
+
81
+  if (n_converted == (size_t)-1) {
82
+    free(ret);
83
+    return NULL;
84
+  } else {
85
+    ret[ret_len - outbytesleft] = '\0';
86
+    return ret;
87
+  }
88
+}
89
+
90
+/*
91
+ * Find a family name in the face's name table, preferring the one the
92
+ * system, fall back to the other
93
+ */
94
+
95
+typedef struct _NameDef {
96
+  const char *buf;
97
+  int rank; // the higher the more desirable
98
+} NameDef;
99
+
100
+gint
101
+_name_def_compare(gconstpointer a, gconstpointer b) {
102
+  return ((NameDef*)a)->rank > ((NameDef*)b)->rank ? -1 : 1;
103
+}
104
+
105
+// Some versions of GTK+ do not have this, particualrly the one we
106
+// currently link to in node-canvas's wiki
107
+void
108
+_free_g_list_item(gpointer data, gpointer user_data) {
109
+  NameDef *d = (NameDef *)data;
110
+  free((void *)(d->buf));
111
+}
112
+
113
+void
114
+_g_list_free_full(GList *list) {
115
+  g_list_foreach(list, _free_g_list_item, NULL);
116
+  g_list_free(list);
117
+}
118
+
119
+char *
120
+get_family_name(FT_Face face) {
121
+  FT_SfntName name;
122
+  GList *list = NULL;
123
+  char *utf8name = NULL;
124
+
125
+  for (unsigned i = 0; i < FT_Get_Sfnt_Name_Count(face); ++i) {
126
+    FT_Get_Sfnt_Name(face, i, &name);
127
+
128
+    if (name.name_id == TT_NAME_ID_FONT_FAMILY || name.name_id == TT_NAME_ID_PREFERRED_FAMILY) {
129
+      char *buf = to_utf8(name.string, name.string_len, name.platform_id, name.encoding_id);
130
+
131
+      if (buf) {
132
+        NameDef *d = (NameDef*)malloc(sizeof(NameDef));
133
+        d->buf = (const char*)buf;
134
+        d->rank = GET_NAME_RANK(name);
135
+
136
+        list = g_list_insert_sorted(list, (gpointer)d, _name_def_compare);
137
+      }
138
+    }
139
+  }
140
+
141
+  GList *best_def = g_list_first(list);
142
+  if (best_def) utf8name = (char*) strdup(((NameDef*)best_def->data)->buf);
143
+  if (list) _g_list_free_full(list);
144
+
145
+  return utf8name;
146
+}
147
+
148
+PangoWeight
149
+get_pango_weight(FT_UShort weight) {
150
+  switch (weight) {
151
+    case 100: return PANGO_WEIGHT_THIN;
152
+    case 200: return PANGO_WEIGHT_ULTRALIGHT;
153
+    case 300: return PANGO_WEIGHT_LIGHT;
154
+    #if PANGO_VERSION >= PANGO_VERSION_ENCODE(1, 36, 7)
155
+    case 350: return PANGO_WEIGHT_SEMILIGHT;
156
+    #endif
157
+    case 380: return PANGO_WEIGHT_BOOK;
158
+    case 400: return PANGO_WEIGHT_NORMAL;
159
+    case 500: return PANGO_WEIGHT_MEDIUM;
160
+    case 600: return PANGO_WEIGHT_SEMIBOLD;
161
+    case 700: return PANGO_WEIGHT_BOLD;
162
+    case 800: return PANGO_WEIGHT_ULTRABOLD;
163
+    case 900: return PANGO_WEIGHT_HEAVY;
164
+    case 1000: return PANGO_WEIGHT_ULTRAHEAVY;
165
+    default: return PANGO_WEIGHT_NORMAL;
166
+  }
167
+}
168
+
169
+PangoStretch
170
+get_pango_stretch(FT_UShort width) {
171
+  switch (width) {
172
+    case 1: return PANGO_STRETCH_ULTRA_CONDENSED;
173
+    case 2: return PANGO_STRETCH_EXTRA_CONDENSED;
174
+    case 3: return PANGO_STRETCH_CONDENSED;
175
+    case 4: return PANGO_STRETCH_SEMI_CONDENSED;
176
+    case 5: return PANGO_STRETCH_NORMAL;
177
+    case 6: return PANGO_STRETCH_SEMI_EXPANDED;
178
+    case 7: return PANGO_STRETCH_EXPANDED;
179
+    case 8: return PANGO_STRETCH_EXTRA_EXPANDED;
180
+    case 9: return PANGO_STRETCH_ULTRA_EXPANDED;
181
+    default: return PANGO_STRETCH_NORMAL;
182
+  }
183
+}
184
+
185
+PangoStyle
186
+get_pango_style(FT_Long flags) {
187
+  if (flags & FT_STYLE_FLAG_ITALIC) {
188
+    return PANGO_STYLE_ITALIC;
189
+  } else {
190
+    return PANGO_STYLE_NORMAL;
191
+  }
192
+}
193
+
194
+PangoFontDescription *
195
+get_pango_font_description(unsigned char* filepath) {
196
+  FT_Library library;
197
+  FT_Face face;
198
+  PangoFontDescription *desc = pango_font_description_new();
199
+
200
+  if (!FT_Init_FreeType(&library) && !FT_New_Face(library, (const char*)filepath, 0, &face)) {
201
+    TT_OS2 *table = (TT_OS2*)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
202
+    char *family = get_family_name(face);
203
+
204
+    if (family) pango_font_description_set_family_static(desc, family);
205
+    pango_font_description_set_weight(desc, get_pango_weight(table->usWeightClass));
206
+    pango_font_description_set_stretch(desc, get_pango_stretch(table->usWidthClass));
207
+    pango_font_description_set_style(desc, get_pango_style(face->style_flags));
208
+
209
+    FT_Done_Face(face);
210
+
211
+    return desc;
212
+  }
213
+
214
+  pango_font_description_free(desc);
215
+
216
+  return NULL;
217
+}
218
+
219
+/*
220
+ * Register font with the OS
221
+ */
222
+
223
+bool
224
+register_font(unsigned char *filepath, PangoFontDescription **desc) {
225
+  bool success;
226
+  
227
+  #ifdef __APPLE__
228
+  CFURLRef filepathUrl = CFURLCreateFromFileSystemRepresentation(NULL, filepath, strlen((char*)filepath), false);
229
+  success = CTFontManagerRegisterFontsForURL(filepathUrl, kCTFontManagerScopeProcess, NULL);
230
+  #elif defined(_WIN32)
231
+  success = AddFontResourceEx((LPCSTR)filepath, FR_PRIVATE, 0) != 0;
232
+  #else
233
+  success = FcConfigAppFontAddFile(FcConfigGetCurrent(), (FcChar8 *)(filepath));
234
+  #endif
235
+
236
+  if (!success) return false;
237
+
238
+  *desc = get_pango_font_description(filepath);
239
+
240
+  // Tell Pango to throw away the current FontMap and create a new one. This
241
+  // has the effect of registering the new font in Pango by re-looking up all
242
+  // font families.
243
+  pango_cairo_font_map_set_default(NULL);
244
+
245
+  return true;
246
+}
247
+

+ 4 - 0
vendor/canvas/src/register_font.h Wyświetl plik

@@ -0,0 +1,4 @@
1
+#include <pango/pango.h>
2
+
3
+bool register_font(unsigned char *filepath, PangoFontDescription** desc);
4
+

+ 63 - 0
vendor/canvas/util/has_lib.sh Wyświetl plik

@@ -0,0 +1,63 @@
1
+#!/bin/bash
2
+
3
+has_ldconfig() {
4
+  hash ldconfig 2>/dev/null
5
+}
6
+
7
+has_system_lib() {
8
+  local regex="lib$1.+(so|dylib)"
9
+
10
+  # Add /sbin to path as ldconfig is located there on some systems - e.g. Debian
11
+  # (and it still can be used by unprivileged users):
12
+  PATH="$PATH:/sbin"
13
+  export PATH
14
+  # Try using ldconfig on linux systems
15
+  if $(has_ldconfig); then
16
+    for _ in $(ldconfig -p 2>/dev/null | grep -E "$regex"); do
17
+      return 0
18
+    done
19
+  fi
20
+
21
+  # Try just checking common library locations
22
+  for dir in /lib /usr/lib /usr/local/lib /opt/local/lib /usr/lib/x86_64-linux-gnu /usr/lib/i386-linux-gnu; do
23
+    test -d $dir && ls $dir | grep -E "$regex" && return 0
24
+  done
25
+
26
+  return 1
27
+}
28
+
29
+has_freetype() {
30
+  pkg-config cairo --cflags-only-I | grep freetype2
31
+}
32
+
33
+has_pkgconfig_lib() {
34
+  pkg-config --exists "$1"
35
+}
36
+
37
+case "$1" in
38
+  gif)
39
+    has_system_lib "gif" > /dev/null
40
+    result=$?
41
+    ;;
42
+  jpeg)
43
+    has_system_lib "jpeg" > /dev/null
44
+    result=$?
45
+    ;;
46
+  pango)
47
+    has_pkgconfig_lib "pango" > /dev/null
48
+    result=$?
49
+    ;;
50
+  freetype)
51
+    has_freetype > /dev/null
52
+    result=$?
53
+    ;;
54
+  *)
55
+    >&2 echo "Unknown library: $1"
56
+    exit 1
57
+esac
58
+
59
+if test $result -eq 0; then
60
+  echo "true"
61
+else
62
+  echo "false"
63
+fi