groove-dev 0.26.14 → 0.26.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (975) hide show
  1. package/GROOVE_AI_PITCH_DECK_OUTLINE.docx +0 -0
  2. package/node_modules/@groove-dev/daemon/src/index.js +34 -4
  3. package/node_modules/@groove-dev/gui/dist/assets/index-7eQvV_N9.js +638 -0
  4. package/node_modules/@groove-dev/gui/dist/assets/index-DAy5FSuv.css +1 -0
  5. package/node_modules/@groove-dev/gui/dist/index.html +2 -2
  6. package/node_modules/@groove-dev/gui/src/app.css +16 -0
  7. package/node_modules/@groove-dev/gui/src/components/agents/agent-chat.jsx +2 -1
  8. package/node_modules/@groove-dev/gui/src/components/agents/agent-feed.jsx +2 -12
  9. package/node_modules/@groove-dev/gui/src/components/ui/thinking-indicator.jsx +49 -0
  10. package/node_modules/@groove-dev/gui/src/stores/groove.js +34 -13
  11. package/node_modules/@groove-dev/gui/src/views/agents.jsx +4 -2
  12. package/node_modules/@groove-dev/gui/src/views/editor.jsx +58 -2
  13. package/package.json +1 -1
  14. package/packages/daemon/src/index.js +34 -4
  15. package/packages/gui/dist/assets/index-7eQvV_N9.js +638 -0
  16. package/packages/gui/dist/assets/index-DAy5FSuv.css +1 -0
  17. package/packages/gui/dist/index.html +2 -2
  18. package/packages/gui/src/app.css +16 -0
  19. package/packages/gui/src/components/agents/agent-chat.jsx +2 -1
  20. package/packages/gui/src/components/agents/agent-feed.jsx +2 -12
  21. package/packages/gui/src/components/ui/thinking-indicator.jsx +49 -0
  22. package/packages/gui/src/stores/groove.js +34 -13
  23. package/packages/gui/src/views/agents.jsx +4 -2
  24. package/packages/gui/src/views/editor.jsx +58 -2
  25. package/pitch-deck-groove/convert-slides.js +795 -0
  26. package/pitch-deck-groove/deck.pptx +0 -0
  27. package/pitch-deck-groove/node_modules/.package-lock.json +755 -0
  28. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/.github/workflows/codeql.yml +74 -0
  29. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/CHANGELOG.md +510 -0
  30. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/LICENSE +27 -0
  31. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/README.md +742 -0
  32. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/bin/node-pre-gyp +4 -0
  33. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/bin/node-pre-gyp.cmd +2 -0
  34. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/contributing.md +10 -0
  35. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/build.js +51 -0
  36. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/clean.js +31 -0
  37. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/configure.js +52 -0
  38. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/info.js +38 -0
  39. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/install.js +235 -0
  40. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/main.js +125 -0
  41. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/node-pre-gyp.js +309 -0
  42. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/package.js +73 -0
  43. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/pre-binding.js +34 -0
  44. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/publish.js +81 -0
  45. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/rebuild.js +20 -0
  46. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/reinstall.js +19 -0
  47. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/reveal.js +32 -0
  48. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/testbinary.js +79 -0
  49. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/testpackage.js +53 -0
  50. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/unpublish.js +41 -0
  51. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/abi_crosswalk.json +2602 -0
  52. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/compile.js +93 -0
  53. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/handle_gyp_opts.js +102 -0
  54. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/napi.js +205 -0
  55. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/index.html +26 -0
  56. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/nw-pre-gyp/package.json +9 -0
  57. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/s3_setup.js +163 -0
  58. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/lib/util/versioning.js +335 -0
  59. package/pitch-deck-groove/node_modules/@mapbox/node-pre-gyp/package.json +62 -0
  60. package/pitch-deck-groove/node_modules/@types/node/LICENSE +21 -0
  61. package/pitch-deck-groove/node_modules/@types/node/README.md +15 -0
  62. package/pitch-deck-groove/node_modules/@types/node/assert/strict.d.ts +8 -0
  63. package/pitch-deck-groove/node_modules/@types/node/assert.d.ts +1005 -0
  64. package/pitch-deck-groove/node_modules/@types/node/async_hooks.d.ts +586 -0
  65. package/pitch-deck-groove/node_modules/@types/node/buffer.buffer.d.ts +457 -0
  66. package/pitch-deck-groove/node_modules/@types/node/buffer.d.ts +1901 -0
  67. package/pitch-deck-groove/node_modules/@types/node/child_process.d.ts +1453 -0
  68. package/pitch-deck-groove/node_modules/@types/node/cluster.d.ts +578 -0
  69. package/pitch-deck-groove/node_modules/@types/node/compatibility/disposable.d.ts +14 -0
  70. package/pitch-deck-groove/node_modules/@types/node/compatibility/index.d.ts +9 -0
  71. package/pitch-deck-groove/node_modules/@types/node/compatibility/indexable.d.ts +20 -0
  72. package/pitch-deck-groove/node_modules/@types/node/compatibility/iterators.d.ts +20 -0
  73. package/pitch-deck-groove/node_modules/@types/node/console.d.ts +452 -0
  74. package/pitch-deck-groove/node_modules/@types/node/constants.d.ts +21 -0
  75. package/pitch-deck-groove/node_modules/@types/node/crypto.d.ts +4504 -0
  76. package/pitch-deck-groove/node_modules/@types/node/dgram.d.ts +596 -0
  77. package/pitch-deck-groove/node_modules/@types/node/diagnostics_channel.d.ts +551 -0
  78. package/pitch-deck-groove/node_modules/@types/node/dns/promises.d.ts +477 -0
  79. package/pitch-deck-groove/node_modules/@types/node/dns.d.ts +860 -0
  80. package/pitch-deck-groove/node_modules/@types/node/domain.d.ts +170 -0
  81. package/pitch-deck-groove/node_modules/@types/node/events.d.ts +863 -0
  82. package/pitch-deck-groove/node_modules/@types/node/fs/promises.d.ts +1208 -0
  83. package/pitch-deck-groove/node_modules/@types/node/fs.d.ts +4332 -0
  84. package/pitch-deck-groove/node_modules/@types/node/globals.d.ts +170 -0
  85. package/pitch-deck-groove/node_modules/@types/node/globals.typedarray.d.ts +21 -0
  86. package/pitch-deck-groove/node_modules/@types/node/http.d.ts +1919 -0
  87. package/pitch-deck-groove/node_modules/@types/node/http2.d.ts +2580 -0
  88. package/pitch-deck-groove/node_modules/@types/node/https.d.ts +549 -0
  89. package/pitch-deck-groove/node_modules/@types/node/index.d.ts +92 -0
  90. package/pitch-deck-groove/node_modules/@types/node/inspector.generated.d.ts +2775 -0
  91. package/pitch-deck-groove/node_modules/@types/node/module.d.ts +503 -0
  92. package/pitch-deck-groove/node_modules/@types/node/net.d.ts +924 -0
  93. package/pitch-deck-groove/node_modules/@types/node/os.d.ts +480 -0
  94. package/pitch-deck-groove/node_modules/@types/node/package.json +145 -0
  95. package/pitch-deck-groove/node_modules/@types/node/path.d.ts +191 -0
  96. package/pitch-deck-groove/node_modules/@types/node/perf_hooks.d.ts +860 -0
  97. package/pitch-deck-groove/node_modules/@types/node/process.d.ts +1632 -0
  98. package/pitch-deck-groove/node_modules/@types/node/punycode.d.ts +117 -0
  99. package/pitch-deck-groove/node_modules/@types/node/querystring.d.ts +140 -0
  100. package/pitch-deck-groove/node_modules/@types/node/readline/promises.d.ts +154 -0
  101. package/pitch-deck-groove/node_modules/@types/node/readline.d.ts +715 -0
  102. package/pitch-deck-groove/node_modules/@types/node/repl.d.ts +430 -0
  103. package/pitch-deck-groove/node_modules/@types/node/stream/consumers.d.ts +38 -0
  104. package/pitch-deck-groove/node_modules/@types/node/stream/promises.d.ts +90 -0
  105. package/pitch-deck-groove/node_modules/@types/node/stream/web.d.ts +527 -0
  106. package/pitch-deck-groove/node_modules/@types/node/stream.d.ts +1680 -0
  107. package/pitch-deck-groove/node_modules/@types/node/string_decoder.d.ts +67 -0
  108. package/pitch-deck-groove/node_modules/@types/node/test.d.ts +1208 -0
  109. package/pitch-deck-groove/node_modules/@types/node/timers/promises.d.ts +108 -0
  110. package/pitch-deck-groove/node_modules/@types/node/timers.d.ts +286 -0
  111. package/pitch-deck-groove/node_modules/@types/node/tls.d.ts +1204 -0
  112. package/pitch-deck-groove/node_modules/@types/node/trace_events.d.ts +171 -0
  113. package/pitch-deck-groove/node_modules/@types/node/ts5.6/buffer.buffer.d.ts +455 -0
  114. package/pitch-deck-groove/node_modules/@types/node/ts5.6/globals.typedarray.d.ts +19 -0
  115. package/pitch-deck-groove/node_modules/@types/node/ts5.6/index.d.ts +92 -0
  116. package/pitch-deck-groove/node_modules/@types/node/tty.d.ts +206 -0
  117. package/pitch-deck-groove/node_modules/@types/node/url.d.ts +957 -0
  118. package/pitch-deck-groove/node_modules/@types/node/util.d.ts +2083 -0
  119. package/pitch-deck-groove/node_modules/@types/node/v8.d.ts +753 -0
  120. package/pitch-deck-groove/node_modules/@types/node/vm.d.ts +704 -0
  121. package/pitch-deck-groove/node_modules/@types/node/wasi.d.ts +160 -0
  122. package/pitch-deck-groove/node_modules/@types/node/web-globals/abortcontroller.d.ts +34 -0
  123. package/pitch-deck-groove/node_modules/@types/node/web-globals/domexception.d.ts +68 -0
  124. package/pitch-deck-groove/node_modules/@types/node/web-globals/events.d.ts +81 -0
  125. package/pitch-deck-groove/node_modules/@types/node/web-globals/fetch.d.ts +38 -0
  126. package/pitch-deck-groove/node_modules/@types/node/worker_threads.d.ts +698 -0
  127. package/pitch-deck-groove/node_modules/@types/node/zlib.d.ts +517 -0
  128. package/pitch-deck-groove/node_modules/abbrev/LICENSE +46 -0
  129. package/pitch-deck-groove/node_modules/abbrev/README.md +23 -0
  130. package/pitch-deck-groove/node_modules/abbrev/abbrev.js +61 -0
  131. package/pitch-deck-groove/node_modules/abbrev/package.json +21 -0
  132. package/pitch-deck-groove/node_modules/agent-base/README.md +145 -0
  133. package/pitch-deck-groove/node_modules/agent-base/dist/src/index.d.ts +78 -0
  134. package/pitch-deck-groove/node_modules/agent-base/dist/src/index.js +203 -0
  135. package/pitch-deck-groove/node_modules/agent-base/dist/src/index.js.map +1 -0
  136. package/pitch-deck-groove/node_modules/agent-base/dist/src/promisify.d.ts +4 -0
  137. package/pitch-deck-groove/node_modules/agent-base/dist/src/promisify.js +18 -0
  138. package/pitch-deck-groove/node_modules/agent-base/dist/src/promisify.js.map +1 -0
  139. package/pitch-deck-groove/node_modules/agent-base/package.json +64 -0
  140. package/pitch-deck-groove/node_modules/agent-base/src/index.ts +345 -0
  141. package/pitch-deck-groove/node_modules/agent-base/src/promisify.ts +33 -0
  142. package/pitch-deck-groove/node_modules/ansi-regex/index.d.ts +37 -0
  143. package/pitch-deck-groove/node_modules/ansi-regex/index.js +10 -0
  144. package/pitch-deck-groove/node_modules/ansi-regex/license +9 -0
  145. package/pitch-deck-groove/node_modules/ansi-regex/package.json +55 -0
  146. package/pitch-deck-groove/node_modules/ansi-regex/readme.md +78 -0
  147. package/pitch-deck-groove/node_modules/aproba/LICENSE +14 -0
  148. package/pitch-deck-groove/node_modules/aproba/README.md +94 -0
  149. package/pitch-deck-groove/node_modules/aproba/index.js +105 -0
  150. package/pitch-deck-groove/node_modules/aproba/package.json +35 -0
  151. package/pitch-deck-groove/node_modules/are-we-there-yet/LICENSE.md +18 -0
  152. package/pitch-deck-groove/node_modules/are-we-there-yet/README.md +208 -0
  153. package/pitch-deck-groove/node_modules/are-we-there-yet/lib/index.js +4 -0
  154. package/pitch-deck-groove/node_modules/are-we-there-yet/lib/tracker-base.js +11 -0
  155. package/pitch-deck-groove/node_modules/are-we-there-yet/lib/tracker-group.js +116 -0
  156. package/pitch-deck-groove/node_modules/are-we-there-yet/lib/tracker-stream.js +36 -0
  157. package/pitch-deck-groove/node_modules/are-we-there-yet/lib/tracker.js +32 -0
  158. package/pitch-deck-groove/node_modules/are-we-there-yet/package.json +53 -0
  159. package/pitch-deck-groove/node_modules/balanced-match/.github/FUNDING.yml +2 -0
  160. package/pitch-deck-groove/node_modules/balanced-match/LICENSE.md +21 -0
  161. package/pitch-deck-groove/node_modules/balanced-match/README.md +97 -0
  162. package/pitch-deck-groove/node_modules/balanced-match/index.js +62 -0
  163. package/pitch-deck-groove/node_modules/balanced-match/package.json +48 -0
  164. package/pitch-deck-groove/node_modules/brace-expansion/LICENSE +21 -0
  165. package/pitch-deck-groove/node_modules/brace-expansion/README.md +129 -0
  166. package/pitch-deck-groove/node_modules/brace-expansion/index.js +203 -0
  167. package/pitch-deck-groove/node_modules/brace-expansion/package.json +50 -0
  168. package/pitch-deck-groove/node_modules/canvas/CHANGELOG.md +1052 -0
  169. package/pitch-deck-groove/node_modules/canvas/Readme.md +600 -0
  170. package/pitch-deck-groove/node_modules/canvas/binding.gyp +230 -0
  171. package/pitch-deck-groove/node_modules/canvas/browser.js +35 -0
  172. package/pitch-deck-groove/node_modules/canvas/build/Makefile +352 -0
  173. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/canvas-postbuild.node.d +1 -0
  174. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/canvas.node.d +1 -0
  175. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/Backends.o.d +490 -0
  176. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/Canvas.o.d +503 -0
  177. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasGradient.o.d +474 -0
  178. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasPattern.o.d +485 -0
  179. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/CanvasRenderingContext2d.o.d +496 -0
  180. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/Image.o.d +484 -0
  181. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/ImageData.o.d +152 -0
  182. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/backend/Backend.o.d +162 -0
  183. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/backend/ImageBackend.o.d +164 -0
  184. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/backend/PdfBackend.o.d +488 -0
  185. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/backend/SvgBackend.o.d +488 -0
  186. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/bmp/BMPParser.o.d +5 -0
  187. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/closure.o.d +483 -0
  188. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/color.o.d +4 -0
  189. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/init.o.d +520 -0
  190. package/pitch-deck-groove/node_modules/canvas/build/Release/.deps/Release/obj.target/canvas/src/register_font.o.d +357 -0
  191. package/pitch-deck-groove/node_modules/canvas/build/Release/canvas-postbuild.node +0 -0
  192. package/pitch-deck-groove/node_modules/canvas/build/Release/canvas.node +0 -0
  193. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/Backends.o +0 -0
  194. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/Canvas.o +0 -0
  195. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/CanvasGradient.o +0 -0
  196. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/CanvasPattern.o +0 -0
  197. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/CanvasRenderingContext2d.o +0 -0
  198. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/Image.o +0 -0
  199. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/ImageData.o +0 -0
  200. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/backend/Backend.o +0 -0
  201. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/backend/ImageBackend.o +0 -0
  202. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/backend/PdfBackend.o +0 -0
  203. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/backend/SvgBackend.o +0 -0
  204. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/bmp/BMPParser.o +0 -0
  205. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/closure.o +0 -0
  206. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/color.o +0 -0
  207. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/init.o +0 -0
  208. package/pitch-deck-groove/node_modules/canvas/build/Release/obj.target/canvas/src/register_font.o +0 -0
  209. package/pitch-deck-groove/node_modules/canvas/build/binding.Makefile +6 -0
  210. package/pitch-deck-groove/node_modules/canvas/build/canvas-postbuild.target.mk +51 -0
  211. package/pitch-deck-groove/node_modules/canvas/build/canvas.target.mk +272 -0
  212. package/pitch-deck-groove/node_modules/canvas/build/gyp-mac-tool +772 -0
  213. package/pitch-deck-groove/node_modules/canvas/changes +19 -0
  214. package/pitch-deck-groove/node_modules/canvas/index.js +94 -0
  215. package/pitch-deck-groove/node_modules/canvas/lib/DOMMatrix.js +620 -0
  216. package/pitch-deck-groove/node_modules/canvas/lib/bindings.js +13 -0
  217. package/pitch-deck-groove/node_modules/canvas/lib/canvas.js +113 -0
  218. package/pitch-deck-groove/node_modules/canvas/lib/context2d.js +14 -0
  219. package/pitch-deck-groove/node_modules/canvas/lib/image.js +96 -0
  220. package/pitch-deck-groove/node_modules/canvas/lib/jpegstream.js +41 -0
  221. package/pitch-deck-groove/node_modules/canvas/lib/parse-font.js +101 -0
  222. package/pitch-deck-groove/node_modules/canvas/lib/pattern.js +17 -0
  223. package/pitch-deck-groove/node_modules/canvas/lib/pdfstream.js +35 -0
  224. package/pitch-deck-groove/node_modules/canvas/lib/pngstream.js +42 -0
  225. package/pitch-deck-groove/node_modules/canvas/package.json +72 -0
  226. package/pitch-deck-groove/node_modules/canvas/src/Backends.cc +18 -0
  227. package/pitch-deck-groove/node_modules/canvas/src/Backends.h +10 -0
  228. package/pitch-deck-groove/node_modules/canvas/src/Canvas.cc +965 -0
  229. package/pitch-deck-groove/node_modules/canvas/src/Canvas.h +96 -0
  230. package/pitch-deck-groove/node_modules/canvas/src/CanvasError.h +23 -0
  231. package/pitch-deck-groove/node_modules/canvas/src/CanvasGradient.cc +123 -0
  232. package/pitch-deck-groove/node_modules/canvas/src/CanvasGradient.h +22 -0
  233. package/pitch-deck-groove/node_modules/canvas/src/CanvasPattern.cc +136 -0
  234. package/pitch-deck-groove/node_modules/canvas/src/CanvasPattern.h +37 -0
  235. package/pitch-deck-groove/node_modules/canvas/src/CanvasRenderingContext2d.cc +3360 -0
  236. package/pitch-deck-groove/node_modules/canvas/src/CanvasRenderingContext2d.h +225 -0
  237. package/pitch-deck-groove/node_modules/canvas/src/Image.cc +1434 -0
  238. package/pitch-deck-groove/node_modules/canvas/src/Image.h +127 -0
  239. package/pitch-deck-groove/node_modules/canvas/src/ImageData.cc +146 -0
  240. package/pitch-deck-groove/node_modules/canvas/src/ImageData.h +27 -0
  241. package/pitch-deck-groove/node_modules/canvas/src/InstanceData.h +8 -0
  242. package/pitch-deck-groove/node_modules/canvas/src/JPEGStream.h +167 -0
  243. package/pitch-deck-groove/node_modules/canvas/src/PNG.h +292 -0
  244. package/pitch-deck-groove/node_modules/canvas/src/Point.h +11 -0
  245. package/pitch-deck-groove/node_modules/canvas/src/Util.h +9 -0
  246. package/pitch-deck-groove/node_modules/canvas/src/backend/Backend.cc +112 -0
  247. package/pitch-deck-groove/node_modules/canvas/src/backend/Backend.h +69 -0
  248. package/pitch-deck-groove/node_modules/canvas/src/backend/ImageBackend.cc +74 -0
  249. package/pitch-deck-groove/node_modules/canvas/src/backend/ImageBackend.h +26 -0
  250. package/pitch-deck-groove/node_modules/canvas/src/backend/PdfBackend.cc +53 -0
  251. package/pitch-deck-groove/node_modules/canvas/src/backend/PdfBackend.h +24 -0
  252. package/pitch-deck-groove/node_modules/canvas/src/backend/SvgBackend.cc +61 -0
  253. package/pitch-deck-groove/node_modules/canvas/src/backend/SvgBackend.h +24 -0
  254. package/pitch-deck-groove/node_modules/canvas/src/bmp/BMPParser.cc +457 -0
  255. package/pitch-deck-groove/node_modules/canvas/src/bmp/BMPParser.h +60 -0
  256. package/pitch-deck-groove/node_modules/canvas/src/bmp/LICENSE.md +24 -0
  257. package/pitch-deck-groove/node_modules/canvas/src/closure.cc +26 -0
  258. package/pitch-deck-groove/node_modules/canvas/src/closure.h +81 -0
  259. package/pitch-deck-groove/node_modules/canvas/src/color.cc +779 -0
  260. package/pitch-deck-groove/node_modules/canvas/src/color.h +30 -0
  261. package/pitch-deck-groove/node_modules/canvas/src/dll_visibility.h +20 -0
  262. package/pitch-deck-groove/node_modules/canvas/src/init.cc +94 -0
  263. package/pitch-deck-groove/node_modules/canvas/src/register_font.cc +408 -0
  264. package/pitch-deck-groove/node_modules/canvas/src/register_font.h +7 -0
  265. package/pitch-deck-groove/node_modules/canvas/types/Readme.md +3 -0
  266. package/pitch-deck-groove/node_modules/canvas/types/index.d.ts +484 -0
  267. package/pitch-deck-groove/node_modules/canvas/util/has_lib.js +119 -0
  268. package/pitch-deck-groove/node_modules/canvas/util/win_jpeg_lookup.js +21 -0
  269. package/pitch-deck-groove/node_modules/chownr/LICENSE +15 -0
  270. package/pitch-deck-groove/node_modules/chownr/README.md +3 -0
  271. package/pitch-deck-groove/node_modules/chownr/chownr.js +167 -0
  272. package/pitch-deck-groove/node_modules/chownr/package.json +32 -0
  273. package/pitch-deck-groove/node_modules/color-support/LICENSE +15 -0
  274. package/pitch-deck-groove/node_modules/color-support/README.md +129 -0
  275. package/pitch-deck-groove/node_modules/color-support/bin.js +3 -0
  276. package/pitch-deck-groove/node_modules/color-support/browser.js +14 -0
  277. package/pitch-deck-groove/node_modules/color-support/index.js +134 -0
  278. package/pitch-deck-groove/node_modules/color-support/package.json +36 -0
  279. package/pitch-deck-groove/node_modules/concat-map/.travis.yml +4 -0
  280. package/pitch-deck-groove/node_modules/concat-map/LICENSE +18 -0
  281. package/pitch-deck-groove/node_modules/concat-map/README.markdown +62 -0
  282. package/pitch-deck-groove/node_modules/concat-map/example/map.js +6 -0
  283. package/pitch-deck-groove/node_modules/concat-map/index.js +13 -0
  284. package/pitch-deck-groove/node_modules/concat-map/package.json +43 -0
  285. package/pitch-deck-groove/node_modules/concat-map/test/map.js +39 -0
  286. package/pitch-deck-groove/node_modules/console-control-strings/LICENSE +13 -0
  287. package/pitch-deck-groove/node_modules/console-control-strings/README.md +145 -0
  288. package/pitch-deck-groove/node_modules/console-control-strings/README.md~ +140 -0
  289. package/pitch-deck-groove/node_modules/console-control-strings/index.js +125 -0
  290. package/pitch-deck-groove/node_modules/console-control-strings/package.json +27 -0
  291. package/pitch-deck-groove/node_modules/core-util-is/LICENSE +19 -0
  292. package/pitch-deck-groove/node_modules/core-util-is/README.md +3 -0
  293. package/pitch-deck-groove/node_modules/core-util-is/lib/util.js +107 -0
  294. package/pitch-deck-groove/node_modules/core-util-is/package.json +38 -0
  295. package/pitch-deck-groove/node_modules/debug/LICENSE +20 -0
  296. package/pitch-deck-groove/node_modules/debug/README.md +481 -0
  297. package/pitch-deck-groove/node_modules/debug/package.json +64 -0
  298. package/pitch-deck-groove/node_modules/debug/src/browser.js +272 -0
  299. package/pitch-deck-groove/node_modules/debug/src/common.js +292 -0
  300. package/pitch-deck-groove/node_modules/debug/src/index.js +10 -0
  301. package/pitch-deck-groove/node_modules/debug/src/node.js +263 -0
  302. package/pitch-deck-groove/node_modules/decompress-response/index.d.ts +29 -0
  303. package/pitch-deck-groove/node_modules/decompress-response/index.js +40 -0
  304. package/pitch-deck-groove/node_modules/decompress-response/license +9 -0
  305. package/pitch-deck-groove/node_modules/decompress-response/package.json +50 -0
  306. package/pitch-deck-groove/node_modules/decompress-response/readme.md +52 -0
  307. package/pitch-deck-groove/node_modules/delegates/History.md +22 -0
  308. package/pitch-deck-groove/node_modules/delegates/License +20 -0
  309. package/pitch-deck-groove/node_modules/delegates/Makefile +8 -0
  310. package/pitch-deck-groove/node_modules/delegates/Readme.md +94 -0
  311. package/pitch-deck-groove/node_modules/delegates/index.js +121 -0
  312. package/pitch-deck-groove/node_modules/delegates/package.json +13 -0
  313. package/pitch-deck-groove/node_modules/delegates/test/index.js +94 -0
  314. package/pitch-deck-groove/node_modules/detect-libc/LICENSE +201 -0
  315. package/pitch-deck-groove/node_modules/detect-libc/README.md +163 -0
  316. package/pitch-deck-groove/node_modules/detect-libc/index.d.ts +14 -0
  317. package/pitch-deck-groove/node_modules/detect-libc/lib/detect-libc.js +313 -0
  318. package/pitch-deck-groove/node_modules/detect-libc/lib/elf.js +39 -0
  319. package/pitch-deck-groove/node_modules/detect-libc/lib/filesystem.js +51 -0
  320. package/pitch-deck-groove/node_modules/detect-libc/lib/process.js +24 -0
  321. package/pitch-deck-groove/node_modules/detect-libc/package.json +44 -0
  322. package/pitch-deck-groove/node_modules/emoji-regex/LICENSE-MIT.txt +20 -0
  323. package/pitch-deck-groove/node_modules/emoji-regex/README.md +73 -0
  324. package/pitch-deck-groove/node_modules/emoji-regex/es2015/index.js +6 -0
  325. package/pitch-deck-groove/node_modules/emoji-regex/es2015/text.js +6 -0
  326. package/pitch-deck-groove/node_modules/emoji-regex/index.d.ts +23 -0
  327. package/pitch-deck-groove/node_modules/emoji-regex/index.js +6 -0
  328. package/pitch-deck-groove/node_modules/emoji-regex/package.json +50 -0
  329. package/pitch-deck-groove/node_modules/emoji-regex/text.js +6 -0
  330. package/pitch-deck-groove/node_modules/fs-minipass/LICENSE +15 -0
  331. package/pitch-deck-groove/node_modules/fs-minipass/README.md +70 -0
  332. package/pitch-deck-groove/node_modules/fs-minipass/index.js +422 -0
  333. package/pitch-deck-groove/node_modules/fs-minipass/node_modules/minipass/LICENSE +15 -0
  334. package/pitch-deck-groove/node_modules/fs-minipass/node_modules/minipass/README.md +728 -0
  335. package/pitch-deck-groove/node_modules/fs-minipass/node_modules/minipass/index.d.ts +155 -0
  336. package/pitch-deck-groove/node_modules/fs-minipass/node_modules/minipass/index.js +649 -0
  337. package/pitch-deck-groove/node_modules/fs-minipass/node_modules/minipass/package.json +56 -0
  338. package/pitch-deck-groove/node_modules/fs-minipass/package.json +39 -0
  339. package/pitch-deck-groove/node_modules/fs.realpath/LICENSE +43 -0
  340. package/pitch-deck-groove/node_modules/fs.realpath/README.md +33 -0
  341. package/pitch-deck-groove/node_modules/fs.realpath/index.js +66 -0
  342. package/pitch-deck-groove/node_modules/fs.realpath/old.js +303 -0
  343. package/pitch-deck-groove/node_modules/fs.realpath/package.json +26 -0
  344. package/pitch-deck-groove/node_modules/gauge/CHANGELOG.md +163 -0
  345. package/pitch-deck-groove/node_modules/gauge/LICENSE +13 -0
  346. package/pitch-deck-groove/node_modules/gauge/README.md +402 -0
  347. package/pitch-deck-groove/node_modules/gauge/base-theme.js +14 -0
  348. package/pitch-deck-groove/node_modules/gauge/error.js +24 -0
  349. package/pitch-deck-groove/node_modules/gauge/has-color.js +4 -0
  350. package/pitch-deck-groove/node_modules/gauge/index.js +233 -0
  351. package/pitch-deck-groove/node_modules/gauge/package.json +66 -0
  352. package/pitch-deck-groove/node_modules/gauge/plumbing.js +48 -0
  353. package/pitch-deck-groove/node_modules/gauge/process.js +3 -0
  354. package/pitch-deck-groove/node_modules/gauge/progress-bar.js +35 -0
  355. package/pitch-deck-groove/node_modules/gauge/render-template.js +178 -0
  356. package/pitch-deck-groove/node_modules/gauge/set-immediate.js +7 -0
  357. package/pitch-deck-groove/node_modules/gauge/set-interval.js +3 -0
  358. package/pitch-deck-groove/node_modules/gauge/spin.js +5 -0
  359. package/pitch-deck-groove/node_modules/gauge/template-item.js +72 -0
  360. package/pitch-deck-groove/node_modules/gauge/theme-set.js +114 -0
  361. package/pitch-deck-groove/node_modules/gauge/themes.js +56 -0
  362. package/pitch-deck-groove/node_modules/gauge/wide-truncate.js +25 -0
  363. package/pitch-deck-groove/node_modules/glob/LICENSE +21 -0
  364. package/pitch-deck-groove/node_modules/glob/README.md +378 -0
  365. package/pitch-deck-groove/node_modules/glob/common.js +238 -0
  366. package/pitch-deck-groove/node_modules/glob/glob.js +790 -0
  367. package/pitch-deck-groove/node_modules/glob/package.json +55 -0
  368. package/pitch-deck-groove/node_modules/glob/sync.js +486 -0
  369. package/pitch-deck-groove/node_modules/has-unicode/LICENSE +14 -0
  370. package/pitch-deck-groove/node_modules/has-unicode/README.md +43 -0
  371. package/pitch-deck-groove/node_modules/has-unicode/index.js +16 -0
  372. package/pitch-deck-groove/node_modules/has-unicode/package.json +30 -0
  373. package/pitch-deck-groove/node_modules/https/package.json +15 -0
  374. package/pitch-deck-groove/node_modules/https-proxy-agent/README.md +137 -0
  375. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/agent.d.ts +30 -0
  376. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/agent.js +177 -0
  377. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/agent.js.map +1 -0
  378. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/index.d.ts +23 -0
  379. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/index.js +14 -0
  380. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/index.js.map +1 -0
  381. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/parse-proxy-response.d.ts +7 -0
  382. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/parse-proxy-response.js +66 -0
  383. package/pitch-deck-groove/node_modules/https-proxy-agent/dist/parse-proxy-response.js.map +1 -0
  384. package/pitch-deck-groove/node_modules/https-proxy-agent/package.json +56 -0
  385. package/pitch-deck-groove/node_modules/image-size/LICENSE +9 -0
  386. package/pitch-deck-groove/node_modules/image-size/Readme.md +184 -0
  387. package/pitch-deck-groove/node_modules/image-size/bin/image-size.js +53 -0
  388. package/pitch-deck-groove/node_modules/image-size/dist/detector.d.ts +2 -0
  389. package/pitch-deck-groove/node_modules/image-size/dist/detector.js +30 -0
  390. package/pitch-deck-groove/node_modules/image-size/dist/index.d.ts +10 -0
  391. package/pitch-deck-groove/node_modules/image-size/dist/index.js +129 -0
  392. package/pitch-deck-groove/node_modules/image-size/dist/types/bmp.d.ts +2 -0
  393. package/pitch-deck-groove/node_modules/image-size/dist/types/bmp.js +11 -0
  394. package/pitch-deck-groove/node_modules/image-size/dist/types/cur.d.ts +2 -0
  395. package/pitch-deck-groove/node_modules/image-size/dist/types/cur.js +17 -0
  396. package/pitch-deck-groove/node_modules/image-size/dist/types/dds.d.ts +2 -0
  397. package/pitch-deck-groove/node_modules/image-size/dist/types/dds.js +11 -0
  398. package/pitch-deck-groove/node_modules/image-size/dist/types/gif.d.ts +2 -0
  399. package/pitch-deck-groove/node_modules/image-size/dist/types/gif.js +12 -0
  400. package/pitch-deck-groove/node_modules/image-size/dist/types/heif.d.ts +2 -0
  401. package/pitch-deck-groove/node_modules/image-size/dist/types/heif.js +40 -0
  402. package/pitch-deck-groove/node_modules/image-size/dist/types/icns.d.ts +2 -0
  403. package/pitch-deck-groove/node_modules/image-size/dist/types/icns.js +101 -0
  404. package/pitch-deck-groove/node_modules/image-size/dist/types/ico.d.ts +2 -0
  405. package/pitch-deck-groove/node_modules/image-size/dist/types/ico.js +68 -0
  406. package/pitch-deck-groove/node_modules/image-size/dist/types/index.d.ts +23 -0
  407. package/pitch-deck-groove/node_modules/image-size/dist/types/index.js +46 -0
  408. package/pitch-deck-groove/node_modules/image-size/dist/types/interface.d.ts +13 -0
  409. package/pitch-deck-groove/node_modules/image-size/dist/types/interface.js +2 -0
  410. package/pitch-deck-groove/node_modules/image-size/dist/types/j2c.d.ts +2 -0
  411. package/pitch-deck-groove/node_modules/image-size/dist/types/j2c.js +12 -0
  412. package/pitch-deck-groove/node_modules/image-size/dist/types/jp2.d.ts +2 -0
  413. package/pitch-deck-groove/node_modules/image-size/dist/types/jp2.js +27 -0
  414. package/pitch-deck-groove/node_modules/image-size/dist/types/jpg.d.ts +2 -0
  415. package/pitch-deck-groove/node_modules/image-size/dist/types/jpg.js +123 -0
  416. package/pitch-deck-groove/node_modules/image-size/dist/types/jxl-stream.d.ts +2 -0
  417. package/pitch-deck-groove/node_modules/image-size/dist/types/jxl-stream.js +45 -0
  418. package/pitch-deck-groove/node_modules/image-size/dist/types/jxl.d.ts +2 -0
  419. package/pitch-deck-groove/node_modules/image-size/dist/types/jxl.js +59 -0
  420. package/pitch-deck-groove/node_modules/image-size/dist/types/ktx.d.ts +2 -0
  421. package/pitch-deck-groove/node_modules/image-size/dist/types/ktx.js +19 -0
  422. package/pitch-deck-groove/node_modules/image-size/dist/types/png.d.ts +2 -0
  423. package/pitch-deck-groove/node_modules/image-size/dist/types/png.js +35 -0
  424. package/pitch-deck-groove/node_modules/image-size/dist/types/pnm.d.ts +2 -0
  425. package/pitch-deck-groove/node_modules/image-size/dist/types/pnm.js +72 -0
  426. package/pitch-deck-groove/node_modules/image-size/dist/types/psd.d.ts +2 -0
  427. package/pitch-deck-groove/node_modules/image-size/dist/types/psd.js +11 -0
  428. package/pitch-deck-groove/node_modules/image-size/dist/types/svg.d.ts +2 -0
  429. package/pitch-deck-groove/node_modules/image-size/dist/types/svg.js +90 -0
  430. package/pitch-deck-groove/node_modules/image-size/dist/types/tga.d.ts +2 -0
  431. package/pitch-deck-groove/node_modules/image-size/dist/types/tga.js +15 -0
  432. package/pitch-deck-groove/node_modules/image-size/dist/types/tiff.d.ts +2 -0
  433. package/pitch-deck-groove/node_modules/image-size/dist/types/tiff.js +95 -0
  434. package/pitch-deck-groove/node_modules/image-size/dist/types/utils.d.ts +15 -0
  435. package/pitch-deck-groove/node_modules/image-size/dist/types/utils.js +75 -0
  436. package/pitch-deck-groove/node_modules/image-size/dist/types/webp.d.ts +2 -0
  437. package/pitch-deck-groove/node_modules/image-size/dist/types/webp.js +60 -0
  438. package/pitch-deck-groove/node_modules/image-size/dist/utils/bit-reader.d.ts +10 -0
  439. package/pitch-deck-groove/node_modules/image-size/dist/utils/bit-reader.js +44 -0
  440. package/pitch-deck-groove/node_modules/image-size/package.json +81 -0
  441. package/pitch-deck-groove/node_modules/immediate/LICENSE.txt +20 -0
  442. package/pitch-deck-groove/node_modules/immediate/README.md +93 -0
  443. package/pitch-deck-groove/node_modules/immediate/dist/immediate.js +75 -0
  444. package/pitch-deck-groove/node_modules/immediate/dist/immediate.min.js +1 -0
  445. package/pitch-deck-groove/node_modules/immediate/lib/browser.js +69 -0
  446. package/pitch-deck-groove/node_modules/immediate/lib/index.js +73 -0
  447. package/pitch-deck-groove/node_modules/immediate/package.json +42 -0
  448. package/pitch-deck-groove/node_modules/inflight/LICENSE +15 -0
  449. package/pitch-deck-groove/node_modules/inflight/README.md +37 -0
  450. package/pitch-deck-groove/node_modules/inflight/inflight.js +54 -0
  451. package/pitch-deck-groove/node_modules/inflight/package.json +29 -0
  452. package/pitch-deck-groove/node_modules/inherits/LICENSE +16 -0
  453. package/pitch-deck-groove/node_modules/inherits/README.md +42 -0
  454. package/pitch-deck-groove/node_modules/inherits/inherits.js +9 -0
  455. package/pitch-deck-groove/node_modules/inherits/inherits_browser.js +27 -0
  456. package/pitch-deck-groove/node_modules/inherits/package.json +29 -0
  457. package/pitch-deck-groove/node_modules/is-fullwidth-code-point/index.d.ts +17 -0
  458. package/pitch-deck-groove/node_modules/is-fullwidth-code-point/index.js +50 -0
  459. package/pitch-deck-groove/node_modules/is-fullwidth-code-point/license +9 -0
  460. package/pitch-deck-groove/node_modules/is-fullwidth-code-point/package.json +42 -0
  461. package/pitch-deck-groove/node_modules/is-fullwidth-code-point/readme.md +39 -0
  462. package/pitch-deck-groove/node_modules/isarray/.travis.yml +4 -0
  463. package/pitch-deck-groove/node_modules/isarray/Makefile +6 -0
  464. package/pitch-deck-groove/node_modules/isarray/README.md +60 -0
  465. package/pitch-deck-groove/node_modules/isarray/component.json +19 -0
  466. package/pitch-deck-groove/node_modules/isarray/index.js +5 -0
  467. package/pitch-deck-groove/node_modules/isarray/package.json +45 -0
  468. package/pitch-deck-groove/node_modules/isarray/test.js +20 -0
  469. package/pitch-deck-groove/node_modules/jszip/.codeclimate.yml +16 -0
  470. package/pitch-deck-groove/node_modules/jszip/.editorconfig +8 -0
  471. package/pitch-deck-groove/node_modules/jszip/.eslintrc.js +43 -0
  472. package/pitch-deck-groove/node_modules/jszip/.github/workflows/pr.yaml +58 -0
  473. package/pitch-deck-groove/node_modules/jszip/.jekyll-metadata +0 -0
  474. package/pitch-deck-groove/node_modules/jszip/.travis.yml +17 -0
  475. package/pitch-deck-groove/node_modules/jszip/CHANGES.md +204 -0
  476. package/pitch-deck-groove/node_modules/jszip/LICENSE.markdown +651 -0
  477. package/pitch-deck-groove/node_modules/jszip/README.markdown +33 -0
  478. package/pitch-deck-groove/node_modules/jszip/deps.js +37 -0
  479. package/pitch-deck-groove/node_modules/jszip/dist/jszip.js +11577 -0
  480. package/pitch-deck-groove/node_modules/jszip/dist/jszip.min.js +13 -0
  481. package/pitch-deck-groove/node_modules/jszip/graph.svg +601 -0
  482. package/pitch-deck-groove/node_modules/jszip/index.d.ts +330 -0
  483. package/pitch-deck-groove/node_modules/jszip/lib/base64.js +106 -0
  484. package/pitch-deck-groove/node_modules/jszip/lib/compressedObject.js +74 -0
  485. package/pitch-deck-groove/node_modules/jszip/lib/compressions.js +14 -0
  486. package/pitch-deck-groove/node_modules/jszip/lib/crc32.js +77 -0
  487. package/pitch-deck-groove/node_modules/jszip/lib/defaults.js +11 -0
  488. package/pitch-deck-groove/node_modules/jszip/lib/external.js +18 -0
  489. package/pitch-deck-groove/node_modules/jszip/lib/flate.js +85 -0
  490. package/pitch-deck-groove/node_modules/jszip/lib/generate/ZipFileWorker.js +539 -0
  491. package/pitch-deck-groove/node_modules/jszip/lib/generate/index.js +57 -0
  492. package/pitch-deck-groove/node_modules/jszip/lib/index.js +55 -0
  493. package/pitch-deck-groove/node_modules/jszip/lib/license_header.js +11 -0
  494. package/pitch-deck-groove/node_modules/jszip/lib/load.js +88 -0
  495. package/pitch-deck-groove/node_modules/jszip/lib/nodejs/NodejsStreamInputAdapter.js +74 -0
  496. package/pitch-deck-groove/node_modules/jszip/lib/nodejs/NodejsStreamOutputAdapter.js +42 -0
  497. package/pitch-deck-groove/node_modules/jszip/lib/nodejsUtils.js +57 -0
  498. package/pitch-deck-groove/node_modules/jszip/lib/object.js +384 -0
  499. package/pitch-deck-groove/node_modules/jszip/lib/readable-stream-browser.js +10 -0
  500. package/pitch-deck-groove/node_modules/jszip/lib/reader/ArrayReader.js +57 -0
  501. package/pitch-deck-groove/node_modules/jszip/lib/reader/DataReader.js +116 -0
  502. package/pitch-deck-groove/node_modules/jszip/lib/reader/NodeBufferReader.js +19 -0
  503. package/pitch-deck-groove/node_modules/jszip/lib/reader/StringReader.js +38 -0
  504. package/pitch-deck-groove/node_modules/jszip/lib/reader/Uint8ArrayReader.js +22 -0
  505. package/pitch-deck-groove/node_modules/jszip/lib/reader/readerFor.js +28 -0
  506. package/pitch-deck-groove/node_modules/jszip/lib/signature.js +7 -0
  507. package/pitch-deck-groove/node_modules/jszip/lib/stream/ConvertWorker.js +26 -0
  508. package/pitch-deck-groove/node_modules/jszip/lib/stream/Crc32Probe.js +24 -0
  509. package/pitch-deck-groove/node_modules/jszip/lib/stream/DataLengthProbe.js +29 -0
  510. package/pitch-deck-groove/node_modules/jszip/lib/stream/DataWorker.js +116 -0
  511. package/pitch-deck-groove/node_modules/jszip/lib/stream/GenericWorker.js +263 -0
  512. package/pitch-deck-groove/node_modules/jszip/lib/stream/StreamHelper.js +214 -0
  513. package/pitch-deck-groove/node_modules/jszip/lib/support.js +38 -0
  514. package/pitch-deck-groove/node_modules/jszip/lib/utf8.js +275 -0
  515. package/pitch-deck-groove/node_modules/jszip/lib/utils.js +501 -0
  516. package/pitch-deck-groove/node_modules/jszip/lib/zipEntries.js +261 -0
  517. package/pitch-deck-groove/node_modules/jszip/lib/zipEntry.js +293 -0
  518. package/pitch-deck-groove/node_modules/jszip/lib/zipObject.js +133 -0
  519. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/.travis.yml +34 -0
  520. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/CONTRIBUTING.md +38 -0
  521. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/GOVERNANCE.md +136 -0
  522. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/LICENSE +47 -0
  523. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/README.md +58 -0
  524. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/doc/wg-meetings/2015-01-30.md +60 -0
  525. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/duplex-browser.js +1 -0
  526. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/duplex.js +1 -0
  527. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/_stream_duplex.js +131 -0
  528. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/_stream_passthrough.js +47 -0
  529. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/_stream_readable.js +1019 -0
  530. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/_stream_transform.js +214 -0
  531. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/_stream_writable.js +685 -0
  532. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/BufferList.js +78 -0
  533. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/destroy.js +84 -0
  534. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/stream-browser.js +1 -0
  535. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/lib/internal/streams/stream.js +1 -0
  536. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/package.json +52 -0
  537. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/passthrough.js +1 -0
  538. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/readable-browser.js +7 -0
  539. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/readable.js +19 -0
  540. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/transform.js +1 -0
  541. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/writable-browser.js +1 -0
  542. package/pitch-deck-groove/node_modules/jszip/node_modules/readable-stream/writable.js +8 -0
  543. package/pitch-deck-groove/node_modules/jszip/node_modules/safe-buffer/LICENSE +21 -0
  544. package/pitch-deck-groove/node_modules/jszip/node_modules/safe-buffer/README.md +584 -0
  545. package/pitch-deck-groove/node_modules/jszip/node_modules/safe-buffer/index.d.ts +187 -0
  546. package/pitch-deck-groove/node_modules/jszip/node_modules/safe-buffer/index.js +62 -0
  547. package/pitch-deck-groove/node_modules/jszip/node_modules/safe-buffer/package.json +37 -0
  548. package/pitch-deck-groove/node_modules/jszip/node_modules/string_decoder/.travis.yml +50 -0
  549. package/pitch-deck-groove/node_modules/jszip/node_modules/string_decoder/LICENSE +48 -0
  550. package/pitch-deck-groove/node_modules/jszip/node_modules/string_decoder/README.md +47 -0
  551. package/pitch-deck-groove/node_modules/jszip/node_modules/string_decoder/lib/string_decoder.js +296 -0
  552. package/pitch-deck-groove/node_modules/jszip/node_modules/string_decoder/package.json +31 -0
  553. package/pitch-deck-groove/node_modules/jszip/package.json +67 -0
  554. package/pitch-deck-groove/node_modules/jszip/sponsors.md +21 -0
  555. package/pitch-deck-groove/node_modules/jszip/tsconfig.json +101 -0
  556. package/pitch-deck-groove/node_modules/jszip/vendor/FileSaver.js +247 -0
  557. package/pitch-deck-groove/node_modules/lie/README.md +62 -0
  558. package/pitch-deck-groove/node_modules/lie/dist/lie.js +350 -0
  559. package/pitch-deck-groove/node_modules/lie/dist/lie.min.js +1 -0
  560. package/pitch-deck-groove/node_modules/lie/dist/lie.polyfill.js +358 -0
  561. package/pitch-deck-groove/node_modules/lie/dist/lie.polyfill.min.js +1 -0
  562. package/pitch-deck-groove/node_modules/lie/lib/browser.js +273 -0
  563. package/pitch-deck-groove/node_modules/lie/lib/index.js +298 -0
  564. package/pitch-deck-groove/node_modules/lie/license.md +7 -0
  565. package/pitch-deck-groove/node_modules/lie/lie.d.ts +244 -0
  566. package/pitch-deck-groove/node_modules/lie/package.json +69 -0
  567. package/pitch-deck-groove/node_modules/lie/polyfill.js +4 -0
  568. package/pitch-deck-groove/node_modules/make-dir/index.d.ts +66 -0
  569. package/pitch-deck-groove/node_modules/make-dir/index.js +156 -0
  570. package/pitch-deck-groove/node_modules/make-dir/license +9 -0
  571. package/pitch-deck-groove/node_modules/make-dir/node_modules/semver/LICENSE +15 -0
  572. package/pitch-deck-groove/node_modules/make-dir/node_modules/semver/README.md +443 -0
  573. package/pitch-deck-groove/node_modules/make-dir/node_modules/semver/bin/semver.js +174 -0
  574. package/pitch-deck-groove/node_modules/make-dir/node_modules/semver/package.json +38 -0
  575. package/pitch-deck-groove/node_modules/make-dir/node_modules/semver/range.bnf +16 -0
  576. package/pitch-deck-groove/node_modules/make-dir/node_modules/semver/semver.js +1643 -0
  577. package/pitch-deck-groove/node_modules/make-dir/package.json +59 -0
  578. package/pitch-deck-groove/node_modules/make-dir/readme.md +125 -0
  579. package/pitch-deck-groove/node_modules/mimic-response/index.d.ts +17 -0
  580. package/pitch-deck-groove/node_modules/mimic-response/index.js +38 -0
  581. package/pitch-deck-groove/node_modules/mimic-response/license +9 -0
  582. package/pitch-deck-groove/node_modules/mimic-response/package.json +42 -0
  583. package/pitch-deck-groove/node_modules/mimic-response/readme.md +57 -0
  584. package/pitch-deck-groove/node_modules/minimatch/LICENSE +15 -0
  585. package/pitch-deck-groove/node_modules/minimatch/README.md +267 -0
  586. package/pitch-deck-groove/node_modules/minimatch/minimatch.js +1005 -0
  587. package/pitch-deck-groove/node_modules/minimatch/package.json +33 -0
  588. package/pitch-deck-groove/node_modules/minipass/LICENSE +15 -0
  589. package/pitch-deck-groove/node_modules/minipass/README.md +769 -0
  590. package/pitch-deck-groove/node_modules/minipass/index.d.ts +152 -0
  591. package/pitch-deck-groove/node_modules/minipass/index.js +702 -0
  592. package/pitch-deck-groove/node_modules/minipass/index.mjs +702 -0
  593. package/pitch-deck-groove/node_modules/minipass/package.json +76 -0
  594. package/pitch-deck-groove/node_modules/minizlib/LICENSE +26 -0
  595. package/pitch-deck-groove/node_modules/minizlib/README.md +60 -0
  596. package/pitch-deck-groove/node_modules/minizlib/constants.js +115 -0
  597. package/pitch-deck-groove/node_modules/minizlib/index.js +348 -0
  598. package/pitch-deck-groove/node_modules/minizlib/node_modules/minipass/LICENSE +15 -0
  599. package/pitch-deck-groove/node_modules/minizlib/node_modules/minipass/README.md +728 -0
  600. package/pitch-deck-groove/node_modules/minizlib/node_modules/minipass/index.d.ts +155 -0
  601. package/pitch-deck-groove/node_modules/minizlib/node_modules/minipass/index.js +649 -0
  602. package/pitch-deck-groove/node_modules/minizlib/node_modules/minipass/package.json +56 -0
  603. package/pitch-deck-groove/node_modules/minizlib/package.json +42 -0
  604. package/pitch-deck-groove/node_modules/mkdirp/CHANGELOG.md +15 -0
  605. package/pitch-deck-groove/node_modules/mkdirp/LICENSE +21 -0
  606. package/pitch-deck-groove/node_modules/mkdirp/bin/cmd.js +68 -0
  607. package/pitch-deck-groove/node_modules/mkdirp/index.js +31 -0
  608. package/pitch-deck-groove/node_modules/mkdirp/lib/find-made.js +29 -0
  609. package/pitch-deck-groove/node_modules/mkdirp/lib/mkdirp-manual.js +64 -0
  610. package/pitch-deck-groove/node_modules/mkdirp/lib/mkdirp-native.js +39 -0
  611. package/pitch-deck-groove/node_modules/mkdirp/lib/opts-arg.js +23 -0
  612. package/pitch-deck-groove/node_modules/mkdirp/lib/path-arg.js +29 -0
  613. package/pitch-deck-groove/node_modules/mkdirp/lib/use-native.js +10 -0
  614. package/pitch-deck-groove/node_modules/mkdirp/package.json +44 -0
  615. package/pitch-deck-groove/node_modules/mkdirp/readme.markdown +266 -0
  616. package/pitch-deck-groove/node_modules/ms/index.js +162 -0
  617. package/pitch-deck-groove/node_modules/ms/license.md +21 -0
  618. package/pitch-deck-groove/node_modules/ms/package.json +38 -0
  619. package/pitch-deck-groove/node_modules/ms/readme.md +59 -0
  620. package/pitch-deck-groove/node_modules/nan/.github/workflows/ci.yml +52 -0
  621. package/pitch-deck-groove/node_modules/nan/.pre-commit-config.yaml +8 -0
  622. package/pitch-deck-groove/node_modules/nan/CHANGELOG.md +599 -0
  623. package/pitch-deck-groove/node_modules/nan/CMakeLists.txt +138 -0
  624. package/pitch-deck-groove/node_modules/nan/LICENSE.md +9 -0
  625. package/pitch-deck-groove/node_modules/nan/README.md +456 -0
  626. package/pitch-deck-groove/node_modules/nan/doc/asyncworker.md +146 -0
  627. package/pitch-deck-groove/node_modules/nan/doc/buffers.md +54 -0
  628. package/pitch-deck-groove/node_modules/nan/doc/callback.md +76 -0
  629. package/pitch-deck-groove/node_modules/nan/doc/converters.md +41 -0
  630. package/pitch-deck-groove/node_modules/nan/doc/errors.md +226 -0
  631. package/pitch-deck-groove/node_modules/nan/doc/json.md +62 -0
  632. package/pitch-deck-groove/node_modules/nan/doc/maybe_types.md +583 -0
  633. package/pitch-deck-groove/node_modules/nan/doc/methods.md +689 -0
  634. package/pitch-deck-groove/node_modules/nan/doc/new.md +147 -0
  635. package/pitch-deck-groove/node_modules/nan/doc/node_misc.md +123 -0
  636. package/pitch-deck-groove/node_modules/nan/doc/object_wrappers.md +263 -0
  637. package/pitch-deck-groove/node_modules/nan/doc/persistent.md +296 -0
  638. package/pitch-deck-groove/node_modules/nan/doc/scopes.md +73 -0
  639. package/pitch-deck-groove/node_modules/nan/doc/script.md +58 -0
  640. package/pitch-deck-groove/node_modules/nan/doc/string_bytes.md +81 -0
  641. package/pitch-deck-groove/node_modules/nan/doc/v8_internals.md +199 -0
  642. package/pitch-deck-groove/node_modules/nan/doc/v8_misc.md +85 -0
  643. package/pitch-deck-groove/node_modules/nan/include_dirs.js +1 -0
  644. package/pitch-deck-groove/node_modules/nan/nan.h +3202 -0
  645. package/pitch-deck-groove/node_modules/nan/nan_callbacks.h +141 -0
  646. package/pitch-deck-groove/node_modules/nan/nan_callbacks_12_inl.h +690 -0
  647. package/pitch-deck-groove/node_modules/nan/nan_callbacks_pre_12_inl.h +524 -0
  648. package/pitch-deck-groove/node_modules/nan/nan_converters.h +72 -0
  649. package/pitch-deck-groove/node_modules/nan/nan_converters_43_inl.h +68 -0
  650. package/pitch-deck-groove/node_modules/nan/nan_converters_pre_43_inl.h +42 -0
  651. package/pitch-deck-groove/node_modules/nan/nan_define_own_property_helper.h +29 -0
  652. package/pitch-deck-groove/node_modules/nan/nan_implementation_12_inl.h +430 -0
  653. package/pitch-deck-groove/node_modules/nan/nan_implementation_pre_12_inl.h +263 -0
  654. package/pitch-deck-groove/node_modules/nan/nan_json.h +166 -0
  655. package/pitch-deck-groove/node_modules/nan/nan_maybe_43_inl.h +360 -0
  656. package/pitch-deck-groove/node_modules/nan/nan_maybe_pre_43_inl.h +268 -0
  657. package/pitch-deck-groove/node_modules/nan/nan_new.h +340 -0
  658. package/pitch-deck-groove/node_modules/nan/nan_object_wrap.h +156 -0
  659. package/pitch-deck-groove/node_modules/nan/nan_persistent_12_inl.h +132 -0
  660. package/pitch-deck-groove/node_modules/nan/nan_persistent_pre_12_inl.h +242 -0
  661. package/pitch-deck-groove/node_modules/nan/nan_private.h +73 -0
  662. package/pitch-deck-groove/node_modules/nan/nan_scriptorigin.h +97 -0
  663. package/pitch-deck-groove/node_modules/nan/nan_string_bytes.h +305 -0
  664. package/pitch-deck-groove/node_modules/nan/nan_typedarray_contents.h +96 -0
  665. package/pitch-deck-groove/node_modules/nan/nan_weak.h +453 -0
  666. package/pitch-deck-groove/node_modules/nan/package.json +38 -0
  667. package/pitch-deck-groove/node_modules/nan/tools/1to2.js +412 -0
  668. package/pitch-deck-groove/node_modules/nan/tools/README.md +14 -0
  669. package/pitch-deck-groove/node_modules/nan/tools/package.json +19 -0
  670. package/pitch-deck-groove/node_modules/node-fetch/LICENSE.md +22 -0
  671. package/pitch-deck-groove/node_modules/node-fetch/README.md +634 -0
  672. package/pitch-deck-groove/node_modules/node-fetch/browser.js +25 -0
  673. package/pitch-deck-groove/node_modules/node-fetch/lib/index.es.js +1777 -0
  674. package/pitch-deck-groove/node_modules/node-fetch/lib/index.js +1787 -0
  675. package/pitch-deck-groove/node_modules/node-fetch/lib/index.mjs +1775 -0
  676. package/pitch-deck-groove/node_modules/node-fetch/package.json +89 -0
  677. package/pitch-deck-groove/node_modules/nopt/CHANGELOG.md +58 -0
  678. package/pitch-deck-groove/node_modules/nopt/LICENSE +15 -0
  679. package/pitch-deck-groove/node_modules/nopt/README.md +213 -0
  680. package/pitch-deck-groove/node_modules/nopt/bin/nopt.js +54 -0
  681. package/pitch-deck-groove/node_modules/nopt/lib/nopt.js +441 -0
  682. package/pitch-deck-groove/node_modules/nopt/package.json +34 -0
  683. package/pitch-deck-groove/node_modules/npmlog/LICENSE +15 -0
  684. package/pitch-deck-groove/node_modules/npmlog/README.md +216 -0
  685. package/pitch-deck-groove/node_modules/npmlog/log.js +403 -0
  686. package/pitch-deck-groove/node_modules/npmlog/package.json +33 -0
  687. package/pitch-deck-groove/node_modules/object-assign/index.js +90 -0
  688. package/pitch-deck-groove/node_modules/object-assign/license +21 -0
  689. package/pitch-deck-groove/node_modules/object-assign/package.json +42 -0
  690. package/pitch-deck-groove/node_modules/object-assign/readme.md +61 -0
  691. package/pitch-deck-groove/node_modules/once/LICENSE +15 -0
  692. package/pitch-deck-groove/node_modules/once/README.md +79 -0
  693. package/pitch-deck-groove/node_modules/once/once.js +42 -0
  694. package/pitch-deck-groove/node_modules/once/package.json +33 -0
  695. package/pitch-deck-groove/node_modules/pako/CHANGELOG.md +164 -0
  696. package/pitch-deck-groove/node_modules/pako/LICENSE +21 -0
  697. package/pitch-deck-groove/node_modules/pako/README.md +191 -0
  698. package/pitch-deck-groove/node_modules/pako/dist/pako.js +6818 -0
  699. package/pitch-deck-groove/node_modules/pako/dist/pako.min.js +1 -0
  700. package/pitch-deck-groove/node_modules/pako/dist/pako_deflate.js +3997 -0
  701. package/pitch-deck-groove/node_modules/pako/dist/pako_deflate.min.js +1 -0
  702. package/pitch-deck-groove/node_modules/pako/dist/pako_inflate.js +3300 -0
  703. package/pitch-deck-groove/node_modules/pako/dist/pako_inflate.min.js +1 -0
  704. package/pitch-deck-groove/node_modules/pako/index.js +14 -0
  705. package/pitch-deck-groove/node_modules/pako/lib/deflate.js +400 -0
  706. package/pitch-deck-groove/node_modules/pako/lib/inflate.js +423 -0
  707. package/pitch-deck-groove/node_modules/pako/lib/utils/common.js +105 -0
  708. package/pitch-deck-groove/node_modules/pako/lib/utils/strings.js +187 -0
  709. package/pitch-deck-groove/node_modules/pako/lib/zlib/README +59 -0
  710. package/pitch-deck-groove/node_modules/pako/lib/zlib/adler32.js +51 -0
  711. package/pitch-deck-groove/node_modules/pako/lib/zlib/constants.js +68 -0
  712. package/pitch-deck-groove/node_modules/pako/lib/zlib/crc32.js +59 -0
  713. package/pitch-deck-groove/node_modules/pako/lib/zlib/deflate.js +1874 -0
  714. package/pitch-deck-groove/node_modules/pako/lib/zlib/gzheader.js +58 -0
  715. package/pitch-deck-groove/node_modules/pako/lib/zlib/inffast.js +345 -0
  716. package/pitch-deck-groove/node_modules/pako/lib/zlib/inflate.js +1556 -0
  717. package/pitch-deck-groove/node_modules/pako/lib/zlib/inftrees.js +343 -0
  718. package/pitch-deck-groove/node_modules/pako/lib/zlib/messages.js +32 -0
  719. package/pitch-deck-groove/node_modules/pako/lib/zlib/trees.js +1222 -0
  720. package/pitch-deck-groove/node_modules/pako/lib/zlib/zstream.js +47 -0
  721. package/pitch-deck-groove/node_modules/pako/package.json +44 -0
  722. package/pitch-deck-groove/node_modules/path-is-absolute/index.js +20 -0
  723. package/pitch-deck-groove/node_modules/path-is-absolute/license +21 -0
  724. package/pitch-deck-groove/node_modules/path-is-absolute/package.json +43 -0
  725. package/pitch-deck-groove/node_modules/path-is-absolute/readme.md +59 -0
  726. package/pitch-deck-groove/node_modules/pptxgenjs/LICENSE +21 -0
  727. package/pitch-deck-groove/node_modules/pptxgenjs/README.md +284 -0
  728. package/pitch-deck-groove/node_modules/pptxgenjs/dist/pptxgen.bundle.js +3 -0
  729. package/pitch-deck-groove/node_modules/pptxgenjs/dist/pptxgen.bundle.js.map +1 -0
  730. package/pitch-deck-groove/node_modules/pptxgenjs/dist/pptxgen.cjs.js +7445 -0
  731. package/pitch-deck-groove/node_modules/pptxgenjs/dist/pptxgen.es.js +7439 -0
  732. package/pitch-deck-groove/node_modules/pptxgenjs/dist/pptxgen.min.js +3 -0
  733. package/pitch-deck-groove/node_modules/pptxgenjs/dist/pptxgen.min.js.map +1 -0
  734. package/pitch-deck-groove/node_modules/pptxgenjs/package.json +89 -0
  735. package/pitch-deck-groove/node_modules/pptxgenjs/types/index.d.ts +2670 -0
  736. package/pitch-deck-groove/node_modules/process-nextick-args/index.js +45 -0
  737. package/pitch-deck-groove/node_modules/process-nextick-args/license.md +19 -0
  738. package/pitch-deck-groove/node_modules/process-nextick-args/package.json +25 -0
  739. package/pitch-deck-groove/node_modules/process-nextick-args/readme.md +18 -0
  740. package/pitch-deck-groove/node_modules/queue/LICENSE +8 -0
  741. package/pitch-deck-groove/node_modules/queue/index.d.ts +173 -0
  742. package/pitch-deck-groove/node_modules/queue/index.js +195 -0
  743. package/pitch-deck-groove/node_modules/queue/package.json +43 -0
  744. package/pitch-deck-groove/node_modules/queue/readme.md +221 -0
  745. package/pitch-deck-groove/node_modules/readable-stream/CONTRIBUTING.md +38 -0
  746. package/pitch-deck-groove/node_modules/readable-stream/GOVERNANCE.md +136 -0
  747. package/pitch-deck-groove/node_modules/readable-stream/LICENSE +47 -0
  748. package/pitch-deck-groove/node_modules/readable-stream/README.md +106 -0
  749. package/pitch-deck-groove/node_modules/readable-stream/errors-browser.js +127 -0
  750. package/pitch-deck-groove/node_modules/readable-stream/errors.js +116 -0
  751. package/pitch-deck-groove/node_modules/readable-stream/experimentalWarning.js +17 -0
  752. package/pitch-deck-groove/node_modules/readable-stream/lib/_stream_duplex.js +126 -0
  753. package/pitch-deck-groove/node_modules/readable-stream/lib/_stream_passthrough.js +37 -0
  754. package/pitch-deck-groove/node_modules/readable-stream/lib/_stream_readable.js +1027 -0
  755. package/pitch-deck-groove/node_modules/readable-stream/lib/_stream_transform.js +190 -0
  756. package/pitch-deck-groove/node_modules/readable-stream/lib/_stream_writable.js +641 -0
  757. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/async_iterator.js +180 -0
  758. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/buffer_list.js +183 -0
  759. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/destroy.js +96 -0
  760. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/end-of-stream.js +86 -0
  761. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/from-browser.js +3 -0
  762. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/from.js +52 -0
  763. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/pipeline.js +86 -0
  764. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/state.js +22 -0
  765. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/stream-browser.js +1 -0
  766. package/pitch-deck-groove/node_modules/readable-stream/lib/internal/streams/stream.js +1 -0
  767. package/pitch-deck-groove/node_modules/readable-stream/package.json +68 -0
  768. package/pitch-deck-groove/node_modules/readable-stream/readable-browser.js +9 -0
  769. package/pitch-deck-groove/node_modules/readable-stream/readable.js +16 -0
  770. package/pitch-deck-groove/node_modules/rimraf/CHANGELOG.md +65 -0
  771. package/pitch-deck-groove/node_modules/rimraf/LICENSE +15 -0
  772. package/pitch-deck-groove/node_modules/rimraf/README.md +101 -0
  773. package/pitch-deck-groove/node_modules/rimraf/bin.js +68 -0
  774. package/pitch-deck-groove/node_modules/rimraf/package.json +32 -0
  775. package/pitch-deck-groove/node_modules/rimraf/rimraf.js +360 -0
  776. package/pitch-deck-groove/node_modules/safe-buffer/LICENSE +21 -0
  777. package/pitch-deck-groove/node_modules/safe-buffer/README.md +584 -0
  778. package/pitch-deck-groove/node_modules/safe-buffer/index.d.ts +187 -0
  779. package/pitch-deck-groove/node_modules/safe-buffer/index.js +65 -0
  780. package/pitch-deck-groove/node_modules/safe-buffer/package.json +51 -0
  781. package/pitch-deck-groove/node_modules/semver/LICENSE +15 -0
  782. package/pitch-deck-groove/node_modules/semver/README.md +665 -0
  783. package/pitch-deck-groove/node_modules/semver/bin/semver.js +191 -0
  784. package/pitch-deck-groove/node_modules/semver/classes/comparator.js +143 -0
  785. package/pitch-deck-groove/node_modules/semver/classes/index.js +7 -0
  786. package/pitch-deck-groove/node_modules/semver/classes/range.js +557 -0
  787. package/pitch-deck-groove/node_modules/semver/classes/semver.js +333 -0
  788. package/pitch-deck-groove/node_modules/semver/functions/clean.js +8 -0
  789. package/pitch-deck-groove/node_modules/semver/functions/cmp.js +54 -0
  790. package/pitch-deck-groove/node_modules/semver/functions/coerce.js +62 -0
  791. package/pitch-deck-groove/node_modules/semver/functions/compare-build.js +9 -0
  792. package/pitch-deck-groove/node_modules/semver/functions/compare-loose.js +5 -0
  793. package/pitch-deck-groove/node_modules/semver/functions/compare.js +7 -0
  794. package/pitch-deck-groove/node_modules/semver/functions/diff.js +60 -0
  795. package/pitch-deck-groove/node_modules/semver/functions/eq.js +5 -0
  796. package/pitch-deck-groove/node_modules/semver/functions/gt.js +5 -0
  797. package/pitch-deck-groove/node_modules/semver/functions/gte.js +5 -0
  798. package/pitch-deck-groove/node_modules/semver/functions/inc.js +21 -0
  799. package/pitch-deck-groove/node_modules/semver/functions/lt.js +5 -0
  800. package/pitch-deck-groove/node_modules/semver/functions/lte.js +5 -0
  801. package/pitch-deck-groove/node_modules/semver/functions/major.js +5 -0
  802. package/pitch-deck-groove/node_modules/semver/functions/minor.js +5 -0
  803. package/pitch-deck-groove/node_modules/semver/functions/neq.js +5 -0
  804. package/pitch-deck-groove/node_modules/semver/functions/parse.js +18 -0
  805. package/pitch-deck-groove/node_modules/semver/functions/patch.js +5 -0
  806. package/pitch-deck-groove/node_modules/semver/functions/prerelease.js +8 -0
  807. package/pitch-deck-groove/node_modules/semver/functions/rcompare.js +5 -0
  808. package/pitch-deck-groove/node_modules/semver/functions/rsort.js +5 -0
  809. package/pitch-deck-groove/node_modules/semver/functions/satisfies.js +12 -0
  810. package/pitch-deck-groove/node_modules/semver/functions/sort.js +5 -0
  811. package/pitch-deck-groove/node_modules/semver/functions/valid.js +8 -0
  812. package/pitch-deck-groove/node_modules/semver/index.js +91 -0
  813. package/pitch-deck-groove/node_modules/semver/internal/constants.js +37 -0
  814. package/pitch-deck-groove/node_modules/semver/internal/debug.js +11 -0
  815. package/pitch-deck-groove/node_modules/semver/internal/identifiers.js +29 -0
  816. package/pitch-deck-groove/node_modules/semver/internal/lrucache.js +42 -0
  817. package/pitch-deck-groove/node_modules/semver/internal/parse-options.js +17 -0
  818. package/pitch-deck-groove/node_modules/semver/internal/re.js +223 -0
  819. package/pitch-deck-groove/node_modules/semver/package.json +78 -0
  820. package/pitch-deck-groove/node_modules/semver/preload.js +4 -0
  821. package/pitch-deck-groove/node_modules/semver/range.bnf +16 -0
  822. package/pitch-deck-groove/node_modules/semver/ranges/gtr.js +6 -0
  823. package/pitch-deck-groove/node_modules/semver/ranges/intersects.js +9 -0
  824. package/pitch-deck-groove/node_modules/semver/ranges/ltr.js +6 -0
  825. package/pitch-deck-groove/node_modules/semver/ranges/max-satisfying.js +27 -0
  826. package/pitch-deck-groove/node_modules/semver/ranges/min-satisfying.js +26 -0
  827. package/pitch-deck-groove/node_modules/semver/ranges/min-version.js +63 -0
  828. package/pitch-deck-groove/node_modules/semver/ranges/outside.js +82 -0
  829. package/pitch-deck-groove/node_modules/semver/ranges/simplify.js +49 -0
  830. package/pitch-deck-groove/node_modules/semver/ranges/subset.js +249 -0
  831. package/pitch-deck-groove/node_modules/semver/ranges/to-comparators.js +10 -0
  832. package/pitch-deck-groove/node_modules/semver/ranges/valid.js +13 -0
  833. package/pitch-deck-groove/node_modules/set-blocking/CHANGELOG.md +26 -0
  834. package/pitch-deck-groove/node_modules/set-blocking/LICENSE.txt +14 -0
  835. package/pitch-deck-groove/node_modules/set-blocking/README.md +31 -0
  836. package/pitch-deck-groove/node_modules/set-blocking/index.js +7 -0
  837. package/pitch-deck-groove/node_modules/set-blocking/package.json +42 -0
  838. package/pitch-deck-groove/node_modules/setimmediate/LICENSE.txt +20 -0
  839. package/pitch-deck-groove/node_modules/setimmediate/package.json +30 -0
  840. package/pitch-deck-groove/node_modules/setimmediate/setImmediate.js +186 -0
  841. package/pitch-deck-groove/node_modules/signal-exit/LICENSE.txt +16 -0
  842. package/pitch-deck-groove/node_modules/signal-exit/README.md +39 -0
  843. package/pitch-deck-groove/node_modules/signal-exit/index.js +202 -0
  844. package/pitch-deck-groove/node_modules/signal-exit/package.json +38 -0
  845. package/pitch-deck-groove/node_modules/signal-exit/signals.js +53 -0
  846. package/pitch-deck-groove/node_modules/simple-concat/.travis.yml +3 -0
  847. package/pitch-deck-groove/node_modules/simple-concat/LICENSE +20 -0
  848. package/pitch-deck-groove/node_modules/simple-concat/README.md +44 -0
  849. package/pitch-deck-groove/node_modules/simple-concat/index.js +15 -0
  850. package/pitch-deck-groove/node_modules/simple-concat/package.json +47 -0
  851. package/pitch-deck-groove/node_modules/simple-concat/test/basic.js +41 -0
  852. package/pitch-deck-groove/node_modules/simple-get/LICENSE +20 -0
  853. package/pitch-deck-groove/node_modules/simple-get/README.md +319 -0
  854. package/pitch-deck-groove/node_modules/simple-get/index.js +107 -0
  855. package/pitch-deck-groove/node_modules/simple-get/package.json +53 -0
  856. package/pitch-deck-groove/node_modules/string-width/index.d.ts +29 -0
  857. package/pitch-deck-groove/node_modules/string-width/index.js +47 -0
  858. package/pitch-deck-groove/node_modules/string-width/license +9 -0
  859. package/pitch-deck-groove/node_modules/string-width/package.json +56 -0
  860. package/pitch-deck-groove/node_modules/string-width/readme.md +50 -0
  861. package/pitch-deck-groove/node_modules/string_decoder/LICENSE +48 -0
  862. package/pitch-deck-groove/node_modules/string_decoder/README.md +47 -0
  863. package/pitch-deck-groove/node_modules/string_decoder/lib/string_decoder.js +296 -0
  864. package/pitch-deck-groove/node_modules/string_decoder/package.json +34 -0
  865. package/pitch-deck-groove/node_modules/strip-ansi/index.d.ts +17 -0
  866. package/pitch-deck-groove/node_modules/strip-ansi/index.js +4 -0
  867. package/pitch-deck-groove/node_modules/strip-ansi/license +9 -0
  868. package/pitch-deck-groove/node_modules/strip-ansi/package.json +54 -0
  869. package/pitch-deck-groove/node_modules/strip-ansi/readme.md +46 -0
  870. package/pitch-deck-groove/node_modules/tar/LICENSE +15 -0
  871. package/pitch-deck-groove/node_modules/tar/README.md +1080 -0
  872. package/pitch-deck-groove/node_modules/tar/index.js +18 -0
  873. package/pitch-deck-groove/node_modules/tar/lib/create.js +111 -0
  874. package/pitch-deck-groove/node_modules/tar/lib/extract.js +113 -0
  875. package/pitch-deck-groove/node_modules/tar/lib/get-write-flag.js +20 -0
  876. package/pitch-deck-groove/node_modules/tar/lib/header.js +304 -0
  877. package/pitch-deck-groove/node_modules/tar/lib/high-level-opt.js +29 -0
  878. package/pitch-deck-groove/node_modules/tar/lib/large-numbers.js +104 -0
  879. package/pitch-deck-groove/node_modules/tar/lib/list.js +139 -0
  880. package/pitch-deck-groove/node_modules/tar/lib/mkdir.js +229 -0
  881. package/pitch-deck-groove/node_modules/tar/lib/mode-fix.js +27 -0
  882. package/pitch-deck-groove/node_modules/tar/lib/normalize-unicode.js +12 -0
  883. package/pitch-deck-groove/node_modules/tar/lib/normalize-windows-path.js +8 -0
  884. package/pitch-deck-groove/node_modules/tar/lib/pack.js +432 -0
  885. package/pitch-deck-groove/node_modules/tar/lib/parse.js +552 -0
  886. package/pitch-deck-groove/node_modules/tar/lib/path-reservations.js +156 -0
  887. package/pitch-deck-groove/node_modules/tar/lib/pax.js +150 -0
  888. package/pitch-deck-groove/node_modules/tar/lib/read-entry.js +107 -0
  889. package/pitch-deck-groove/node_modules/tar/lib/replace.js +246 -0
  890. package/pitch-deck-groove/node_modules/tar/lib/strip-absolute-path.js +24 -0
  891. package/pitch-deck-groove/node_modules/tar/lib/strip-trailing-slashes.js +13 -0
  892. package/pitch-deck-groove/node_modules/tar/lib/types.js +44 -0
  893. package/pitch-deck-groove/node_modules/tar/lib/unpack.js +923 -0
  894. package/pitch-deck-groove/node_modules/tar/lib/update.js +40 -0
  895. package/pitch-deck-groove/node_modules/tar/lib/warn-mixin.js +24 -0
  896. package/pitch-deck-groove/node_modules/tar/lib/winchars.js +23 -0
  897. package/pitch-deck-groove/node_modules/tar/lib/write-entry.js +546 -0
  898. package/pitch-deck-groove/node_modules/tar/package.json +70 -0
  899. package/pitch-deck-groove/node_modules/tr46/index.js +193 -0
  900. package/pitch-deck-groove/node_modules/tr46/lib/.gitkeep +0 -0
  901. package/pitch-deck-groove/node_modules/tr46/lib/mappingTable.json +1 -0
  902. package/pitch-deck-groove/node_modules/tr46/package.json +31 -0
  903. package/pitch-deck-groove/node_modules/undici-types/README.md +6 -0
  904. package/pitch-deck-groove/node_modules/undici-types/agent.d.ts +31 -0
  905. package/pitch-deck-groove/node_modules/undici-types/api.d.ts +43 -0
  906. package/pitch-deck-groove/node_modules/undici-types/balanced-pool.d.ts +18 -0
  907. package/pitch-deck-groove/node_modules/undici-types/cache.d.ts +36 -0
  908. package/pitch-deck-groove/node_modules/undici-types/client.d.ts +97 -0
  909. package/pitch-deck-groove/node_modules/undici-types/connector.d.ts +34 -0
  910. package/pitch-deck-groove/node_modules/undici-types/content-type.d.ts +21 -0
  911. package/pitch-deck-groove/node_modules/undici-types/cookies.d.ts +28 -0
  912. package/pitch-deck-groove/node_modules/undici-types/diagnostics-channel.d.ts +67 -0
  913. package/pitch-deck-groove/node_modules/undici-types/dispatcher.d.ts +241 -0
  914. package/pitch-deck-groove/node_modules/undici-types/errors.d.ts +128 -0
  915. package/pitch-deck-groove/node_modules/undici-types/fetch.d.ts +209 -0
  916. package/pitch-deck-groove/node_modules/undici-types/file.d.ts +39 -0
  917. package/pitch-deck-groove/node_modules/undici-types/filereader.d.ts +54 -0
  918. package/pitch-deck-groove/node_modules/undici-types/formdata.d.ts +108 -0
  919. package/pitch-deck-groove/node_modules/undici-types/global-dispatcher.d.ts +9 -0
  920. package/pitch-deck-groove/node_modules/undici-types/global-origin.d.ts +7 -0
  921. package/pitch-deck-groove/node_modules/undici-types/handlers.d.ts +9 -0
  922. package/pitch-deck-groove/node_modules/undici-types/header.d.ts +4 -0
  923. package/pitch-deck-groove/node_modules/undici-types/index.d.ts +63 -0
  924. package/pitch-deck-groove/node_modules/undici-types/interceptors.d.ts +5 -0
  925. package/pitch-deck-groove/node_modules/undici-types/mock-agent.d.ts +50 -0
  926. package/pitch-deck-groove/node_modules/undici-types/mock-client.d.ts +25 -0
  927. package/pitch-deck-groove/node_modules/undici-types/mock-errors.d.ts +12 -0
  928. package/pitch-deck-groove/node_modules/undici-types/mock-interceptor.d.ts +93 -0
  929. package/pitch-deck-groove/node_modules/undici-types/mock-pool.d.ts +25 -0
  930. package/pitch-deck-groove/node_modules/undici-types/package.json +55 -0
  931. package/pitch-deck-groove/node_modules/undici-types/patch.d.ts +71 -0
  932. package/pitch-deck-groove/node_modules/undici-types/pool-stats.d.ts +19 -0
  933. package/pitch-deck-groove/node_modules/undici-types/pool.d.ts +28 -0
  934. package/pitch-deck-groove/node_modules/undici-types/proxy-agent.d.ts +30 -0
  935. package/pitch-deck-groove/node_modules/undici-types/readable.d.ts +61 -0
  936. package/pitch-deck-groove/node_modules/undici-types/webidl.d.ts +220 -0
  937. package/pitch-deck-groove/node_modules/undici-types/websocket.d.ts +131 -0
  938. package/pitch-deck-groove/node_modules/util-deprecate/History.md +16 -0
  939. package/pitch-deck-groove/node_modules/util-deprecate/LICENSE +24 -0
  940. package/pitch-deck-groove/node_modules/util-deprecate/README.md +53 -0
  941. package/pitch-deck-groove/node_modules/util-deprecate/browser.js +67 -0
  942. package/pitch-deck-groove/node_modules/util-deprecate/node.js +6 -0
  943. package/pitch-deck-groove/node_modules/util-deprecate/package.json +27 -0
  944. package/pitch-deck-groove/node_modules/webidl-conversions/LICENSE.md +12 -0
  945. package/pitch-deck-groove/node_modules/webidl-conversions/README.md +53 -0
  946. package/pitch-deck-groove/node_modules/webidl-conversions/lib/index.js +189 -0
  947. package/pitch-deck-groove/node_modules/webidl-conversions/package.json +23 -0
  948. package/pitch-deck-groove/node_modules/whatwg-url/LICENSE.txt +21 -0
  949. package/pitch-deck-groove/node_modules/whatwg-url/README.md +67 -0
  950. package/pitch-deck-groove/node_modules/whatwg-url/lib/URL-impl.js +200 -0
  951. package/pitch-deck-groove/node_modules/whatwg-url/lib/URL.js +196 -0
  952. package/pitch-deck-groove/node_modules/whatwg-url/lib/public-api.js +11 -0
  953. package/pitch-deck-groove/node_modules/whatwg-url/lib/url-state-machine.js +1297 -0
  954. package/pitch-deck-groove/node_modules/whatwg-url/lib/utils.js +20 -0
  955. package/pitch-deck-groove/node_modules/whatwg-url/package.json +32 -0
  956. package/pitch-deck-groove/node_modules/wide-align/LICENSE +14 -0
  957. package/pitch-deck-groove/node_modules/wide-align/README.md +47 -0
  958. package/pitch-deck-groove/node_modules/wide-align/align.js +65 -0
  959. package/pitch-deck-groove/node_modules/wide-align/package.json +33 -0
  960. package/pitch-deck-groove/node_modules/wrappy/LICENSE +15 -0
  961. package/pitch-deck-groove/node_modules/wrappy/README.md +36 -0
  962. package/pitch-deck-groove/node_modules/wrappy/package.json +29 -0
  963. package/pitch-deck-groove/node_modules/wrappy/wrappy.js +33 -0
  964. package/pitch-deck-groove/node_modules/yallist/LICENSE +15 -0
  965. package/pitch-deck-groove/node_modules/yallist/README.md +204 -0
  966. package/pitch-deck-groove/node_modules/yallist/iterator.js +8 -0
  967. package/pitch-deck-groove/node_modules/yallist/package.json +29 -0
  968. package/pitch-deck-groove/node_modules/yallist/yallist.js +426 -0
  969. package/pitch-deck-groove/package-lock.json +763 -0
  970. package/pitch-deck-groove/package.json +13 -0
  971. package/pitch-deck-groove/slides.json +239 -0
  972. package/node_modules/@groove-dev/gui/dist/assets/index-D5zShz2P.js +0 -633
  973. package/node_modules/@groove-dev/gui/dist/assets/index-E07lphaH.css +0 -1
  974. package/packages/gui/dist/assets/index-D5zShz2P.js +0 -633
  975. package/packages/gui/dist/assets/index-E07lphaH.css +0 -1
@@ -0,0 +1,3360 @@
1
+ // Copyright (c) 2010 LearnBoost <tj@learnboost.com>
2
+
3
+ #include "CanvasRenderingContext2d.h"
4
+
5
+ #include <algorithm>
6
+ #include "backend/ImageBackend.h"
7
+ #include <cairo-pdf.h>
8
+ #include "Canvas.h"
9
+ #include "CanvasGradient.h"
10
+ #include "CanvasPattern.h"
11
+ #include <cmath>
12
+ #include <cstdlib>
13
+ #include "Image.h"
14
+ #include "ImageData.h"
15
+ #include <limits>
16
+ #include <map>
17
+ #include "Point.h"
18
+ #include <string>
19
+ #include "Util.h"
20
+ #include <vector>
21
+
22
+ using namespace v8;
23
+
24
+ Nan::Persistent<FunctionTemplate> Context2d::constructor;
25
+
26
+ /*
27
+ * Rectangle arg assertions.
28
+ */
29
+
30
+ #define RECT_ARGS \
31
+ double args[4]; \
32
+ if(!checkArgs(info, args, 4)) \
33
+ return; \
34
+ double x = args[0]; \
35
+ double y = args[1]; \
36
+ double width = args[2]; \
37
+ double height = args[3];
38
+
39
+ #define CHECK_RECEIVER(prop) \
40
+ if (!Context2d::constructor.Get(info.GetIsolate())->HasInstance(info.This())) { \
41
+ Nan::ThrowTypeError("Method " #prop " called on incompatible receiver"); \
42
+ return; \
43
+ }
44
+
45
+ constexpr double twoPi = M_PI * 2.;
46
+
47
+ /*
48
+ * Simple helper macro for a rather verbose function call.
49
+ */
50
+
51
+ #define PANGO_LAYOUT_GET_METRICS(LAYOUT) pango_context_get_metrics( \
52
+ pango_layout_get_context(LAYOUT), \
53
+ pango_layout_get_font_description(LAYOUT), \
54
+ pango_context_get_language(pango_layout_get_context(LAYOUT)))
55
+
56
+ inline static bool checkArgs(const Nan::FunctionCallbackInfo<Value> &info, double *args, int argsNum, int offset = 0){
57
+ int argsEnd = offset + argsNum;
58
+ bool areArgsValid = true;
59
+
60
+ for (int i = offset; i < argsEnd; i++) {
61
+ double val = Nan::To<double>(info[i]).FromMaybe(0);
62
+
63
+ if (areArgsValid) {
64
+ if (!std::isfinite(val)) {
65
+ // We should continue the loop instead of returning immediately
66
+ // See https://html.spec.whatwg.org/multipage/canvas.html
67
+
68
+ areArgsValid = false;
69
+ continue;
70
+ }
71
+
72
+ args[i - offset] = val;
73
+ }
74
+ }
75
+
76
+ return areArgsValid;
77
+ }
78
+
79
+ Nan::Persistent<Function> Context2d::_DOMMatrix;
80
+ Nan::Persistent<Function> Context2d::_parseFont;
81
+
82
+ /*
83
+ * Initialize Context2d.
84
+ */
85
+
86
+ void
87
+ Context2d::Initialize(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE target) {
88
+ Nan::HandleScope scope;
89
+
90
+ // Constructor
91
+ Local<FunctionTemplate> ctor = Nan::New<FunctionTemplate>(Context2d::New);
92
+ constructor.Reset(ctor);
93
+ ctor->InstanceTemplate()->SetInternalFieldCount(1);
94
+ ctor->SetClassName(Nan::New("CanvasRenderingContext2D").ToLocalChecked());
95
+
96
+ // Prototype
97
+ Local<ObjectTemplate> proto = ctor->PrototypeTemplate();
98
+ Nan::SetPrototypeMethod(ctor, "drawImage", DrawImage);
99
+ Nan::SetPrototypeMethod(ctor, "putImageData", PutImageData);
100
+ Nan::SetPrototypeMethod(ctor, "getImageData", GetImageData);
101
+ Nan::SetPrototypeMethod(ctor, "createImageData", CreateImageData);
102
+ Nan::SetPrototypeMethod(ctor, "addPage", AddPage);
103
+ Nan::SetPrototypeMethod(ctor, "save", Save);
104
+ Nan::SetPrototypeMethod(ctor, "restore", Restore);
105
+ Nan::SetPrototypeMethod(ctor, "rotate", Rotate);
106
+ Nan::SetPrototypeMethod(ctor, "translate", Translate);
107
+ Nan::SetPrototypeMethod(ctor, "transform", Transform);
108
+ Nan::SetPrototypeMethod(ctor, "getTransform", GetTransform);
109
+ Nan::SetPrototypeMethod(ctor, "resetTransform", ResetTransform);
110
+ Nan::SetPrototypeMethod(ctor, "setTransform", SetTransform);
111
+ Nan::SetPrototypeMethod(ctor, "isPointInPath", IsPointInPath);
112
+ Nan::SetPrototypeMethod(ctor, "scale", Scale);
113
+ Nan::SetPrototypeMethod(ctor, "clip", Clip);
114
+ Nan::SetPrototypeMethod(ctor, "fill", Fill);
115
+ Nan::SetPrototypeMethod(ctor, "stroke", Stroke);
116
+ Nan::SetPrototypeMethod(ctor, "fillText", FillText);
117
+ Nan::SetPrototypeMethod(ctor, "strokeText", StrokeText);
118
+ Nan::SetPrototypeMethod(ctor, "fillRect", FillRect);
119
+ Nan::SetPrototypeMethod(ctor, "strokeRect", StrokeRect);
120
+ Nan::SetPrototypeMethod(ctor, "clearRect", ClearRect);
121
+ Nan::SetPrototypeMethod(ctor, "rect", Rect);
122
+ Nan::SetPrototypeMethod(ctor, "roundRect", RoundRect);
123
+ Nan::SetPrototypeMethod(ctor, "measureText", MeasureText);
124
+ Nan::SetPrototypeMethod(ctor, "moveTo", MoveTo);
125
+ Nan::SetPrototypeMethod(ctor, "lineTo", LineTo);
126
+ Nan::SetPrototypeMethod(ctor, "bezierCurveTo", BezierCurveTo);
127
+ Nan::SetPrototypeMethod(ctor, "quadraticCurveTo", QuadraticCurveTo);
128
+ Nan::SetPrototypeMethod(ctor, "beginPath", BeginPath);
129
+ Nan::SetPrototypeMethod(ctor, "closePath", ClosePath);
130
+ Nan::SetPrototypeMethod(ctor, "arc", Arc);
131
+ Nan::SetPrototypeMethod(ctor, "arcTo", ArcTo);
132
+ Nan::SetPrototypeMethod(ctor, "ellipse", Ellipse);
133
+ Nan::SetPrototypeMethod(ctor, "setLineDash", SetLineDash);
134
+ Nan::SetPrototypeMethod(ctor, "getLineDash", GetLineDash);
135
+ Nan::SetPrototypeMethod(ctor, "createPattern", CreatePattern);
136
+ Nan::SetPrototypeMethod(ctor, "createLinearGradient", CreateLinearGradient);
137
+ Nan::SetPrototypeMethod(ctor, "createRadialGradient", CreateRadialGradient);
138
+ Nan::SetAccessor(proto, Nan::New("pixelFormat").ToLocalChecked(), GetFormat);
139
+ Nan::SetAccessor(proto, Nan::New("patternQuality").ToLocalChecked(), GetPatternQuality, SetPatternQuality);
140
+ Nan::SetAccessor(proto, Nan::New("imageSmoothingEnabled").ToLocalChecked(), GetImageSmoothingEnabled, SetImageSmoothingEnabled);
141
+ Nan::SetAccessor(proto, Nan::New("globalCompositeOperation").ToLocalChecked(), GetGlobalCompositeOperation, SetGlobalCompositeOperation);
142
+ Nan::SetAccessor(proto, Nan::New("globalAlpha").ToLocalChecked(), GetGlobalAlpha, SetGlobalAlpha);
143
+ Nan::SetAccessor(proto, Nan::New("shadowColor").ToLocalChecked(), GetShadowColor, SetShadowColor);
144
+ Nan::SetAccessor(proto, Nan::New("miterLimit").ToLocalChecked(), GetMiterLimit, SetMiterLimit);
145
+ Nan::SetAccessor(proto, Nan::New("lineWidth").ToLocalChecked(), GetLineWidth, SetLineWidth);
146
+ Nan::SetAccessor(proto, Nan::New("lineCap").ToLocalChecked(), GetLineCap, SetLineCap);
147
+ Nan::SetAccessor(proto, Nan::New("lineJoin").ToLocalChecked(), GetLineJoin, SetLineJoin);
148
+ Nan::SetAccessor(proto, Nan::New("lineDashOffset").ToLocalChecked(), GetLineDashOffset, SetLineDashOffset);
149
+ Nan::SetAccessor(proto, Nan::New("shadowOffsetX").ToLocalChecked(), GetShadowOffsetX, SetShadowOffsetX);
150
+ Nan::SetAccessor(proto, Nan::New("shadowOffsetY").ToLocalChecked(), GetShadowOffsetY, SetShadowOffsetY);
151
+ Nan::SetAccessor(proto, Nan::New("shadowBlur").ToLocalChecked(), GetShadowBlur, SetShadowBlur);
152
+ Nan::SetAccessor(proto, Nan::New("antialias").ToLocalChecked(), GetAntiAlias, SetAntiAlias);
153
+ Nan::SetAccessor(proto, Nan::New("textDrawingMode").ToLocalChecked(), GetTextDrawingMode, SetTextDrawingMode);
154
+ Nan::SetAccessor(proto, Nan::New("quality").ToLocalChecked(), GetQuality, SetQuality);
155
+ Nan::SetAccessor(proto, Nan::New("currentTransform").ToLocalChecked(), GetCurrentTransform, SetCurrentTransform);
156
+ Nan::SetAccessor(proto, Nan::New("fillStyle").ToLocalChecked(), GetFillStyle, SetFillStyle);
157
+ Nan::SetAccessor(proto, Nan::New("strokeStyle").ToLocalChecked(), GetStrokeStyle, SetStrokeStyle);
158
+ Nan::SetAccessor(proto, Nan::New("font").ToLocalChecked(), GetFont, SetFont);
159
+ Nan::SetAccessor(proto, Nan::New("textBaseline").ToLocalChecked(), GetTextBaseline, SetTextBaseline);
160
+ Nan::SetAccessor(proto, Nan::New("textAlign").ToLocalChecked(), GetTextAlign, SetTextAlign);
161
+ Local<Context> ctx = Nan::GetCurrentContext();
162
+ Nan::Set(target, Nan::New("CanvasRenderingContext2d").ToLocalChecked(), ctor->GetFunction(ctx).ToLocalChecked());
163
+ Nan::Set(target, Nan::New("CanvasRenderingContext2dInit").ToLocalChecked(), Nan::New<Function>(SaveExternalModules));
164
+ }
165
+
166
+ /*
167
+ * Create a cairo context.
168
+ */
169
+
170
+ Context2d::Context2d(Canvas *canvas) {
171
+ _canvas = canvas;
172
+ _context = canvas->createCairoContext();
173
+ _layout = pango_cairo_create_layout(_context);
174
+
175
+ // As of January 2023, Pango rounds glyph positions which renders text wider
176
+ // or narrower than the browser. See #2184 for more information
177
+ #if PANGO_VERSION_CHECK(1, 44, 0)
178
+ pango_context_set_round_glyph_positions(pango_layout_get_context(_layout), FALSE);
179
+ #endif
180
+
181
+ states.emplace();
182
+ state = &states.top();
183
+ pango_layout_set_font_description(_layout, state->fontDescription);
184
+ }
185
+
186
+ /*
187
+ * Destroy cairo context.
188
+ */
189
+
190
+ Context2d::~Context2d() {
191
+ g_object_unref(_layout);
192
+ cairo_destroy(_context);
193
+ _resetPersistentHandles();
194
+ }
195
+
196
+ /*
197
+ * Reset canvas state.
198
+ */
199
+
200
+ void Context2d::resetState() {
201
+ states.pop();
202
+ states.emplace();
203
+ pango_layout_set_font_description(_layout, state->fontDescription);
204
+ _resetPersistentHandles();
205
+ }
206
+
207
+ void Context2d::_resetPersistentHandles() {
208
+ _fillStyle.Reset();
209
+ _strokeStyle.Reset();
210
+ }
211
+
212
+ /*
213
+ * Save cairo / canvas state.
214
+ */
215
+
216
+ void
217
+ Context2d::save() {
218
+ cairo_save(_context);
219
+ states.emplace(states.top());
220
+ state = &states.top();
221
+ }
222
+
223
+ /*
224
+ * Restore cairo / canvas state.
225
+ */
226
+
227
+ void
228
+ Context2d::restore() {
229
+ if (states.size() > 1) {
230
+ cairo_restore(_context);
231
+ states.pop();
232
+ state = &states.top();
233
+ pango_layout_set_font_description(_layout, state->fontDescription);
234
+ }
235
+ }
236
+
237
+ /*
238
+ * Save flat path.
239
+ */
240
+
241
+ void
242
+ Context2d::savePath() {
243
+ _path = cairo_copy_path_flat(_context);
244
+ cairo_new_path(_context);
245
+ }
246
+
247
+ /*
248
+ * Restore flat path.
249
+ */
250
+
251
+ void
252
+ Context2d::restorePath() {
253
+ cairo_new_path(_context);
254
+ cairo_append_path(_context, _path);
255
+ cairo_path_destroy(_path);
256
+ }
257
+
258
+ /*
259
+ * Create temporary surface for gradient or pattern transparency
260
+ */
261
+ cairo_pattern_t*
262
+ create_transparent_gradient(cairo_pattern_t *source, float alpha) {
263
+ double x0;
264
+ double y0;
265
+ double x1;
266
+ double y1;
267
+ double r0;
268
+ double r1;
269
+ int count;
270
+ int i;
271
+ double offset;
272
+ double r;
273
+ double g;
274
+ double b;
275
+ double a;
276
+ cairo_pattern_t *newGradient;
277
+ cairo_pattern_type_t type = cairo_pattern_get_type(source);
278
+ cairo_pattern_get_color_stop_count(source, &count);
279
+ if (type == CAIRO_PATTERN_TYPE_LINEAR) {
280
+ cairo_pattern_get_linear_points (source, &x0, &y0, &x1, &y1);
281
+ newGradient = cairo_pattern_create_linear(x0, y0, x1, y1);
282
+ } else if (type == CAIRO_PATTERN_TYPE_RADIAL) {
283
+ cairo_pattern_get_radial_circles(source, &x0, &y0, &r0, &x1, &y1, &r1);
284
+ newGradient = cairo_pattern_create_radial(x0, y0, r0, x1, y1, r1);
285
+ } else {
286
+ Nan::ThrowError("Unexpected gradient type");
287
+ return NULL;
288
+ }
289
+ for ( i = 0; i < count; i++ ) {
290
+ cairo_pattern_get_color_stop_rgba(source, i, &offset, &r, &g, &b, &a);
291
+ cairo_pattern_add_color_stop_rgba(newGradient, offset, r, g, b, a * alpha);
292
+ }
293
+ return newGradient;
294
+ }
295
+
296
+ cairo_pattern_t*
297
+ create_transparent_pattern(cairo_pattern_t *source, float alpha) {
298
+ cairo_surface_t *surface;
299
+ cairo_pattern_get_surface(source, &surface);
300
+ int width = cairo_image_surface_get_width(surface);
301
+ int height = cairo_image_surface_get_height(surface);
302
+ cairo_surface_t *mask_surface = cairo_image_surface_create(
303
+ CAIRO_FORMAT_ARGB32,
304
+ width,
305
+ height);
306
+ cairo_t *mask_context = cairo_create(mask_surface);
307
+ if (cairo_status(mask_context) != CAIRO_STATUS_SUCCESS) {
308
+ Nan::ThrowError("Failed to initialize context");
309
+ return NULL;
310
+ }
311
+ cairo_set_source(mask_context, source);
312
+ cairo_paint_with_alpha(mask_context, alpha);
313
+ cairo_destroy(mask_context);
314
+ cairo_pattern_t* newPattern = cairo_pattern_create_for_surface(mask_surface);
315
+ cairo_surface_destroy(mask_surface);
316
+ return newPattern;
317
+ }
318
+
319
+ /*
320
+ * Fill and apply shadow.
321
+ */
322
+
323
+ void
324
+ Context2d::setFillRule(v8::Local<v8::Value> value) {
325
+ cairo_fill_rule_t rule = CAIRO_FILL_RULE_WINDING;
326
+ if (value->IsString()) {
327
+ Nan::Utf8String str(value);
328
+ if (std::strcmp(*str, "evenodd") == 0) {
329
+ rule = CAIRO_FILL_RULE_EVEN_ODD;
330
+ }
331
+ }
332
+ cairo_set_fill_rule(_context, rule);
333
+ }
334
+
335
+ void
336
+ Context2d::fill(bool preserve) {
337
+ cairo_pattern_t *new_pattern;
338
+ bool needsRestore = false;
339
+ if (state->fillPattern) {
340
+ if (state->globalAlpha < 1) {
341
+ new_pattern = create_transparent_pattern(state->fillPattern, state->globalAlpha);
342
+ if (new_pattern == NULL) {
343
+ // failed to allocate; Nan::ThrowError has already been called, so return from this fn.
344
+ return;
345
+ }
346
+ cairo_set_source(_context, new_pattern);
347
+ cairo_pattern_destroy(new_pattern);
348
+ } else {
349
+ cairo_pattern_set_filter(state->fillPattern, state->patternQuality);
350
+ cairo_set_source(_context, state->fillPattern);
351
+ }
352
+ repeat_type_t repeat = Pattern::get_repeat_type_for_cairo_pattern(state->fillPattern);
353
+ if (repeat == NO_REPEAT) {
354
+ cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_NONE);
355
+ } else if (repeat == REPEAT) {
356
+ cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
357
+ } else {
358
+ cairo_save(_context);
359
+ cairo_path_t *savedPath = cairo_copy_path(_context);
360
+ cairo_surface_t *patternSurface = nullptr;
361
+ cairo_pattern_get_surface(cairo_get_source(_context), &patternSurface);
362
+
363
+ double width, height;
364
+ if (repeat == REPEAT_X) {
365
+ double x1, x2;
366
+ cairo_path_extents(_context, &x1, nullptr, &x2, nullptr);
367
+ width = x2 - x1;
368
+ height = cairo_image_surface_get_height(patternSurface);
369
+ } else {
370
+ double y1, y2;
371
+ cairo_path_extents(_context, nullptr, &y1, nullptr, &y2);
372
+ width = cairo_image_surface_get_width(patternSurface);
373
+ height = y2 - y1;
374
+ }
375
+
376
+ cairo_new_path(_context);
377
+ cairo_rectangle(_context, 0, 0, width, height);
378
+ cairo_clip(_context);
379
+ cairo_append_path(_context, savedPath);
380
+ cairo_path_destroy(savedPath);
381
+ cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
382
+ needsRestore = true;
383
+ }
384
+ } else if (state->fillGradient) {
385
+ if (state->globalAlpha < 1) {
386
+ new_pattern = create_transparent_gradient(state->fillGradient, state->globalAlpha);
387
+ if (new_pattern == NULL) {
388
+ // failed to recognize gradient; Nan::ThrowError has already been called, so return from this fn.
389
+ return;
390
+ }
391
+ cairo_pattern_set_filter(new_pattern, state->patternQuality);
392
+ cairo_set_source(_context, new_pattern);
393
+ cairo_pattern_destroy(new_pattern);
394
+ } else {
395
+ cairo_pattern_set_filter(state->fillGradient, state->patternQuality);
396
+ cairo_set_source(_context, state->fillGradient);
397
+ }
398
+ } else {
399
+ setSourceRGBA(state->fill);
400
+ }
401
+ if (preserve) {
402
+ hasShadow()
403
+ ? shadow(cairo_fill_preserve)
404
+ : cairo_fill_preserve(_context);
405
+ } else {
406
+ hasShadow()
407
+ ? shadow(cairo_fill)
408
+ : cairo_fill(_context);
409
+ }
410
+ if (needsRestore) {
411
+ cairo_restore(_context);
412
+ }
413
+ }
414
+
415
+ /*
416
+ * Stroke and apply shadow.
417
+ */
418
+
419
+ void
420
+ Context2d::stroke(bool preserve) {
421
+ cairo_pattern_t *new_pattern;
422
+ if (state->strokePattern) {
423
+ if (state->globalAlpha < 1) {
424
+ new_pattern = create_transparent_pattern(state->strokePattern, state->globalAlpha);
425
+ if (new_pattern == NULL) {
426
+ // failed to allocate; Nan::ThrowError has already been called, so return from this fn.
427
+ return;
428
+ }
429
+ cairo_set_source(_context, new_pattern);
430
+ cairo_pattern_destroy(new_pattern);
431
+ } else {
432
+ cairo_pattern_set_filter(state->strokePattern, state->patternQuality);
433
+ cairo_set_source(_context, state->strokePattern);
434
+ }
435
+ repeat_type_t repeat = Pattern::get_repeat_type_for_cairo_pattern(state->strokePattern);
436
+ if (NO_REPEAT == repeat) {
437
+ cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_NONE);
438
+ } else {
439
+ cairo_pattern_set_extend(cairo_get_source(_context), CAIRO_EXTEND_REPEAT);
440
+ }
441
+ } else if (state->strokeGradient) {
442
+ if (state->globalAlpha < 1) {
443
+ new_pattern = create_transparent_gradient(state->strokeGradient, state->globalAlpha);
444
+ if (new_pattern == NULL) {
445
+ // failed to recognize gradient; Nan::ThrowError has already been called, so return from this fn.
446
+ return;
447
+ }
448
+ cairo_pattern_set_filter(new_pattern, state->patternQuality);
449
+ cairo_set_source(_context, new_pattern);
450
+ cairo_pattern_destroy(new_pattern);
451
+ } else {
452
+ cairo_pattern_set_filter(state->strokeGradient, state->patternQuality);
453
+ cairo_set_source(_context, state->strokeGradient);
454
+ }
455
+ } else {
456
+ setSourceRGBA(state->stroke);
457
+ }
458
+
459
+ if (preserve) {
460
+ hasShadow()
461
+ ? shadow(cairo_stroke_preserve)
462
+ : cairo_stroke_preserve(_context);
463
+ } else {
464
+ hasShadow()
465
+ ? shadow(cairo_stroke)
466
+ : cairo_stroke(_context);
467
+ }
468
+ }
469
+
470
+ /*
471
+ * Apply shadow with the given draw fn.
472
+ */
473
+
474
+ void
475
+ Context2d::shadow(void (fn)(cairo_t *cr)) {
476
+ cairo_path_t *path = cairo_copy_path_flat(_context);
477
+ cairo_save(_context);
478
+
479
+ // shadowOffset is unaffected by current transform
480
+ cairo_matrix_t path_matrix;
481
+ cairo_get_matrix(_context, &path_matrix);
482
+ cairo_identity_matrix(_context);
483
+
484
+ // Apply shadow
485
+ cairo_push_group(_context);
486
+
487
+ // No need to invoke blur if shadowBlur is 0
488
+ if (state->shadowBlur) {
489
+ // find out extent of path
490
+ double x1, y1, x2, y2;
491
+ if (fn == cairo_fill || fn == cairo_fill_preserve) {
492
+ cairo_fill_extents(_context, &x1, &y1, &x2, &y2);
493
+ } else {
494
+ cairo_stroke_extents(_context, &x1, &y1, &x2, &y2);
495
+ }
496
+
497
+ // create new image surface that size + padding for blurring
498
+ double dx = x2-x1, dy = y2-y1;
499
+ cairo_user_to_device_distance(_context, &dx, &dy);
500
+ int pad = state->shadowBlur * 2;
501
+ cairo_surface_t *shadow_surface = cairo_image_surface_create(
502
+ CAIRO_FORMAT_ARGB32,
503
+ dx + 2 * pad,
504
+ dy + 2 * pad);
505
+ cairo_t *shadow_context = cairo_create(shadow_surface);
506
+
507
+ // transform path to the right place
508
+ cairo_translate(shadow_context, pad-x1, pad-y1);
509
+ cairo_transform(shadow_context, &path_matrix);
510
+
511
+ // set lineCap lineJoin lineDash
512
+ cairo_set_line_cap(shadow_context, cairo_get_line_cap(_context));
513
+ cairo_set_line_join(shadow_context, cairo_get_line_join(_context));
514
+
515
+ double offset;
516
+ int dashes = cairo_get_dash_count(_context);
517
+ std::vector<double> a(dashes);
518
+ cairo_get_dash(_context, a.data(), &offset);
519
+ cairo_set_dash(shadow_context, a.data(), dashes, offset);
520
+
521
+ // draw the path and blur
522
+ cairo_set_line_width(shadow_context, cairo_get_line_width(_context));
523
+ cairo_new_path(shadow_context);
524
+ cairo_append_path(shadow_context, path);
525
+ setSourceRGBA(shadow_context, state->shadow);
526
+ fn(shadow_context);
527
+ blur(shadow_surface, state->shadowBlur);
528
+
529
+ // paint to original context
530
+ cairo_set_source_surface(_context, shadow_surface,
531
+ x1 - pad + state->shadowOffsetX + 1,
532
+ y1 - pad + state->shadowOffsetY + 1);
533
+ cairo_paint(_context);
534
+ cairo_destroy(shadow_context);
535
+ cairo_surface_destroy(shadow_surface);
536
+ } else {
537
+ // Offset first, then apply path's transform
538
+ cairo_translate(
539
+ _context
540
+ , state->shadowOffsetX
541
+ , state->shadowOffsetY);
542
+ cairo_transform(_context, &path_matrix);
543
+
544
+ // Apply shadow
545
+ cairo_new_path(_context);
546
+ cairo_append_path(_context, path);
547
+ setSourceRGBA(state->shadow);
548
+
549
+ fn(_context);
550
+ }
551
+
552
+ // Paint the shadow
553
+ cairo_pop_group_to_source(_context);
554
+ cairo_paint(_context);
555
+
556
+ // Restore state
557
+ cairo_restore(_context);
558
+ cairo_new_path(_context);
559
+ cairo_append_path(_context, path);
560
+ fn(_context);
561
+
562
+ cairo_path_destroy(path);
563
+ }
564
+
565
+ /*
566
+ * Set source RGBA for the current context
567
+ */
568
+
569
+ void
570
+ Context2d::setSourceRGBA(rgba_t color) {
571
+ setSourceRGBA(_context, color);
572
+ }
573
+
574
+ /*
575
+ * Set source RGBA
576
+ */
577
+
578
+ void
579
+ Context2d::setSourceRGBA(cairo_t *ctx, rgba_t color) {
580
+ cairo_set_source_rgba(
581
+ ctx
582
+ , color.r
583
+ , color.g
584
+ , color.b
585
+ , color.a * state->globalAlpha);
586
+ }
587
+
588
+ /*
589
+ * Check if the context has a drawable shadow.
590
+ */
591
+
592
+ bool
593
+ Context2d::hasShadow() {
594
+ return state->shadow.a
595
+ && (state->shadowBlur || state->shadowOffsetX || state->shadowOffsetY);
596
+ }
597
+
598
+ /*
599
+ * Blur the given surface with the given radius.
600
+ */
601
+
602
+ void
603
+ Context2d::blur(cairo_surface_t *surface, int radius) {
604
+ // Steve Hanov, 2009
605
+ // Released into the public domain.
606
+ radius = radius * 0.57735f + 0.5f;
607
+ // get width, height
608
+ int width = cairo_image_surface_get_width( surface );
609
+ int height = cairo_image_surface_get_height( surface );
610
+ unsigned* precalc =
611
+ (unsigned*)malloc(width*height*sizeof(unsigned));
612
+ cairo_surface_flush( surface );
613
+ unsigned char* src = cairo_image_surface_get_data( surface );
614
+ double mul=1.f/((radius*2)*(radius*2));
615
+ int channel;
616
+
617
+ // The number of times to perform the averaging. According to wikipedia,
618
+ // three iterations is good enough to pass for a gaussian.
619
+ const int MAX_ITERATIONS = 3;
620
+ int iteration;
621
+
622
+ for ( iteration = 0; iteration < MAX_ITERATIONS; iteration++ ) {
623
+ for( channel = 0; channel < 4; channel++ ) {
624
+ int x,y;
625
+
626
+ // precomputation step.
627
+ unsigned char* pix = src;
628
+ unsigned* pre = precalc;
629
+
630
+ pix += channel;
631
+ for (y=0;y<height;y++) {
632
+ for (x=0;x<width;x++) {
633
+ int tot=pix[0];
634
+ if (x>0) tot+=pre[-1];
635
+ if (y>0) tot+=pre[-width];
636
+ if (x>0 && y>0) tot-=pre[-width-1];
637
+ *pre++=tot;
638
+ pix += 4;
639
+ }
640
+ }
641
+
642
+ // blur step.
643
+ pix = src + (int)radius * width * 4 + (int)radius * 4 + channel;
644
+ for (y=radius;y<height-radius;y++) {
645
+ for (x=radius;x<width-radius;x++) {
646
+ int l = x < radius ? 0 : x - radius;
647
+ int t = y < radius ? 0 : y - radius;
648
+ int r = x + radius >= width ? width - 1 : x + radius;
649
+ int b = y + radius >= height ? height - 1 : y + radius;
650
+ int tot = precalc[r+b*width] + precalc[l+t*width] -
651
+ precalc[l+b*width] - precalc[r+t*width];
652
+ *pix=(unsigned char)(tot*mul);
653
+ pix += 4;
654
+ }
655
+ pix += (int)radius * 2 * 4;
656
+ }
657
+ }
658
+ }
659
+
660
+ cairo_surface_mark_dirty(surface);
661
+ free(precalc);
662
+ }
663
+
664
+ /*
665
+ * Initialize a new Context2d with the given canvas.
666
+ */
667
+
668
+ NAN_METHOD(Context2d::New) {
669
+ if (!info.IsConstructCall()) {
670
+ return Nan::ThrowTypeError("Class constructors cannot be invoked without 'new'");
671
+ }
672
+
673
+ if (!info[0]->IsObject())
674
+ return Nan::ThrowTypeError("Canvas expected");
675
+ Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
676
+ if (!Nan::New(Canvas::constructor)->HasInstance(obj))
677
+ return Nan::ThrowTypeError("Canvas expected");
678
+ Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
679
+
680
+ bool isImageBackend = canvas->backend()->getName() == "image";
681
+ if (isImageBackend) {
682
+ cairo_format_t format = ImageBackend::DEFAULT_FORMAT;
683
+ if (info[1]->IsObject()) {
684
+ Local<Object> ctxAttributes = Nan::To<Object>(info[1]).ToLocalChecked();
685
+
686
+ Local<Value> pixelFormat = Nan::Get(ctxAttributes, Nan::New("pixelFormat").ToLocalChecked()).ToLocalChecked();
687
+ if (pixelFormat->IsString()) {
688
+ Nan::Utf8String utf8PixelFormat(pixelFormat);
689
+ if (!strcmp(*utf8PixelFormat, "RGBA32")) format = CAIRO_FORMAT_ARGB32;
690
+ else if (!strcmp(*utf8PixelFormat, "RGB24")) format = CAIRO_FORMAT_RGB24;
691
+ else if (!strcmp(*utf8PixelFormat, "A8")) format = CAIRO_FORMAT_A8;
692
+ else if (!strcmp(*utf8PixelFormat, "RGB16_565")) format = CAIRO_FORMAT_RGB16_565;
693
+ else if (!strcmp(*utf8PixelFormat, "A1")) format = CAIRO_FORMAT_A1;
694
+ #ifdef CAIRO_FORMAT_RGB30
695
+ else if (!strcmp(utf8PixelFormat, "RGB30")) format = CAIRO_FORMAT_RGB30;
696
+ #endif
697
+ }
698
+
699
+ // alpha: false forces use of RGB24
700
+ Local<Value> alpha = Nan::Get(ctxAttributes, Nan::New("alpha").ToLocalChecked()).ToLocalChecked();
701
+ if (alpha->IsBoolean() && !Nan::To<bool>(alpha).FromMaybe(false)) {
702
+ format = CAIRO_FORMAT_RGB24;
703
+ }
704
+ }
705
+ static_cast<ImageBackend*>(canvas->backend())->setFormat(format);
706
+ }
707
+
708
+ Context2d *context = new Context2d(canvas);
709
+
710
+ context->Wrap(info.This());
711
+ info.GetReturnValue().Set(info.This());
712
+ }
713
+
714
+ /*
715
+ * Save some external modules as private references.
716
+ */
717
+
718
+ NAN_METHOD(Context2d::SaveExternalModules) {
719
+ _DOMMatrix.Reset(Nan::To<Function>(info[0]).ToLocalChecked());
720
+ _parseFont.Reset(Nan::To<Function>(info[1]).ToLocalChecked());
721
+ }
722
+
723
+ /*
724
+ * Get format (string).
725
+ */
726
+
727
+ NAN_GETTER(Context2d::GetFormat) {
728
+ CHECK_RECEIVER(Context2d.GetFormat);
729
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
730
+ std::string pixelFormatString;
731
+ switch (context->canvas()->backend()->getFormat()) {
732
+ case CAIRO_FORMAT_ARGB32: pixelFormatString = "RGBA32"; break;
733
+ case CAIRO_FORMAT_RGB24: pixelFormatString = "RGB24"; break;
734
+ case CAIRO_FORMAT_A8: pixelFormatString = "A8"; break;
735
+ case CAIRO_FORMAT_A1: pixelFormatString = "A1"; break;
736
+ case CAIRO_FORMAT_RGB16_565: pixelFormatString = "RGB16_565"; break;
737
+ #ifdef CAIRO_FORMAT_RGB30
738
+ case CAIRO_FORMAT_RGB30: pixelFormatString = "RGB30"; break;
739
+ #endif
740
+ default: return info.GetReturnValue().SetNull();
741
+ }
742
+ info.GetReturnValue().Set(Nan::New<String>(pixelFormatString).ToLocalChecked());
743
+ }
744
+
745
+ /*
746
+ * Create a new page.
747
+ */
748
+
749
+ NAN_METHOD(Context2d::AddPage) {
750
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
751
+ if (context->canvas()->backend()->getName() != "pdf") {
752
+ return Nan::ThrowError("only PDF canvases support .addPage()");
753
+ }
754
+ cairo_show_page(context->context());
755
+ int width = Nan::To<int32_t>(info[0]).FromMaybe(0);
756
+ int height = Nan::To<int32_t>(info[1]).FromMaybe(0);
757
+ if (width < 1) width = context->canvas()->getWidth();
758
+ if (height < 1) height = context->canvas()->getHeight();
759
+ cairo_pdf_surface_set_size(context->canvas()->surface(), width, height);
760
+ return;
761
+ }
762
+
763
+ /*
764
+ * Put image data.
765
+ *
766
+ * - imageData, dx, dy
767
+ * - imageData, dx, dy, sx, sy, sw, sh
768
+ *
769
+ */
770
+
771
+ NAN_METHOD(Context2d::PutImageData) {
772
+ if (!info[0]->IsObject())
773
+ return Nan::ThrowTypeError("ImageData expected");
774
+ Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
775
+ if (!Nan::New(ImageData::constructor)->HasInstance(obj))
776
+ return Nan::ThrowTypeError("ImageData expected");
777
+
778
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
779
+ ImageData *imageData = Nan::ObjectWrap::Unwrap<ImageData>(obj);
780
+
781
+ uint8_t *src = imageData->data();
782
+ uint8_t *dst = context->canvas()->data();
783
+
784
+ int dstStride = context->canvas()->stride();
785
+ int Bpp = dstStride / context->canvas()->getWidth();
786
+ int srcStride = Bpp * imageData->width();
787
+
788
+ int sx = 0
789
+ , sy = 0
790
+ , sw = 0
791
+ , sh = 0
792
+ , dx = Nan::To<int32_t>(info[1]).FromMaybe(0)
793
+ , dy = Nan::To<int32_t>(info[2]).FromMaybe(0)
794
+ , rows
795
+ , cols;
796
+
797
+ switch (info.Length()) {
798
+ // imageData, dx, dy
799
+ case 3:
800
+ sw = imageData->width();
801
+ sh = imageData->height();
802
+ break;
803
+ // imageData, dx, dy, sx, sy, sw, sh
804
+ case 7:
805
+ sx = Nan::To<int32_t>(info[3]).FromMaybe(0);
806
+ sy = Nan::To<int32_t>(info[4]).FromMaybe(0);
807
+ sw = Nan::To<int32_t>(info[5]).FromMaybe(0);
808
+ sh = Nan::To<int32_t>(info[6]).FromMaybe(0);
809
+ // fix up negative height, width
810
+ if (sw < 0) sx += sw, sw = -sw;
811
+ if (sh < 0) sy += sh, sh = -sh;
812
+ // clamp the left edge
813
+ if (sx < 0) sw += sx, sx = 0;
814
+ if (sy < 0) sh += sy, sy = 0;
815
+ // clamp the right edge
816
+ if (sx + sw > imageData->width()) sw = imageData->width() - sx;
817
+ if (sy + sh > imageData->height()) sh = imageData->height() - sy;
818
+ // start destination at source offset
819
+ dx += sx;
820
+ dy += sy;
821
+ break;
822
+ default:
823
+ return Nan::ThrowError("invalid arguments");
824
+ }
825
+
826
+ // chop off outlying source data
827
+ if (dx < 0) sw += dx, sx -= dx, dx = 0;
828
+ if (dy < 0) sh += dy, sy -= dy, dy = 0;
829
+ // clamp width at canvas size
830
+ // Need to wrap std::min calls using parens to prevent macro expansion on
831
+ // windows. See http://stackoverflow.com/questions/5004858/stdmin-gives-error
832
+ cols = (std::min)(sw, context->canvas()->getWidth() - dx);
833
+ rows = (std::min)(sh, context->canvas()->getHeight() - dy);
834
+
835
+ if (cols <= 0 || rows <= 0) return;
836
+
837
+ switch (context->canvas()->backend()->getFormat()) {
838
+ case CAIRO_FORMAT_ARGB32: {
839
+ src += sy * srcStride + sx * 4;
840
+ dst += dstStride * dy + 4 * dx;
841
+ for (int y = 0; y < rows; ++y) {
842
+ uint8_t *dstRow = dst;
843
+ uint8_t *srcRow = src;
844
+ for (int x = 0; x < cols; ++x) {
845
+ // rgba
846
+ uint8_t r = *srcRow++;
847
+ uint8_t g = *srcRow++;
848
+ uint8_t b = *srcRow++;
849
+ uint8_t a = *srcRow++;
850
+
851
+ // argb
852
+ // performance optimization: fully transparent/opaque pixels can be
853
+ // processed more efficiently.
854
+ if (a == 0) {
855
+ *dstRow++ = 0;
856
+ *dstRow++ = 0;
857
+ *dstRow++ = 0;
858
+ *dstRow++ = 0;
859
+ } else if (a == 255) {
860
+ *dstRow++ = b;
861
+ *dstRow++ = g;
862
+ *dstRow++ = r;
863
+ *dstRow++ = a;
864
+ } else {
865
+ float alpha = (float)a / 255;
866
+ *dstRow++ = b * alpha;
867
+ *dstRow++ = g * alpha;
868
+ *dstRow++ = r * alpha;
869
+ *dstRow++ = a;
870
+ }
871
+ }
872
+ dst += dstStride;
873
+ src += srcStride;
874
+ }
875
+ break;
876
+ }
877
+ case CAIRO_FORMAT_RGB24: {
878
+ src += sy * srcStride + sx * 4;
879
+ dst += dstStride * dy + 4 * dx;
880
+ for (int y = 0; y < rows; ++y) {
881
+ uint8_t *dstRow = dst;
882
+ uint8_t *srcRow = src;
883
+ for (int x = 0; x < cols; ++x) {
884
+ // rgba
885
+ uint8_t r = *srcRow++;
886
+ uint8_t g = *srcRow++;
887
+ uint8_t b = *srcRow++;
888
+ srcRow++;
889
+
890
+ // argb
891
+ *dstRow++ = b;
892
+ *dstRow++ = g;
893
+ *dstRow++ = r;
894
+ *dstRow++ = 255;
895
+ }
896
+ dst += dstStride;
897
+ src += srcStride;
898
+ }
899
+ break;
900
+ }
901
+ case CAIRO_FORMAT_A8: {
902
+ src += sy * srcStride + sx;
903
+ dst += dstStride * dy + dx;
904
+ if (srcStride == dstStride && cols == dstStride) {
905
+ // fast path: strides are the same and doing a full-width put
906
+ memcpy(dst, src, cols * rows);
907
+ } else {
908
+ for (int y = 0; y < rows; ++y) {
909
+ memcpy(dst, src, cols);
910
+ dst += dstStride;
911
+ src += srcStride;
912
+ }
913
+ }
914
+ break;
915
+ }
916
+ case CAIRO_FORMAT_A1: {
917
+ // TODO Should this be totally packed, or maintain a stride divisible by 4?
918
+ Nan::ThrowError("putImageData for CANVAS_FORMAT_A1 is not yet implemented");
919
+ break;
920
+ }
921
+ case CAIRO_FORMAT_RGB16_565: {
922
+ src += sy * srcStride + sx * 2;
923
+ dst += dstStride * dy + 2 * dx;
924
+ for (int y = 0; y < rows; ++y) {
925
+ memcpy(dst, src, cols * 2);
926
+ dst += dstStride;
927
+ src += srcStride;
928
+ }
929
+ break;
930
+ }
931
+ #ifdef CAIRO_FORMAT_RGB30
932
+ case CAIRO_FORMAT_RGB30: {
933
+ // TODO
934
+ Nan::ThrowError("putImageData for CANVAS_FORMAT_RGB30 is not yet implemented");
935
+ break;
936
+ }
937
+ #endif
938
+ default: {
939
+ Nan::ThrowError("Invalid pixel format or not an image canvas");
940
+ return;
941
+ }
942
+ }
943
+
944
+ cairo_surface_mark_dirty_rectangle(
945
+ context->canvas()->surface()
946
+ , dx
947
+ , dy
948
+ , cols
949
+ , rows);
950
+ }
951
+
952
+ /*
953
+ * Get image data.
954
+ *
955
+ * - sx, sy, sw, sh
956
+ *
957
+ */
958
+
959
+ NAN_METHOD(Context2d::GetImageData) {
960
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
961
+ Canvas *canvas = context->canvas();
962
+
963
+ int sx = Nan::To<int32_t>(info[0]).FromMaybe(0);
964
+ int sy = Nan::To<int32_t>(info[1]).FromMaybe(0);
965
+ int sw = Nan::To<int32_t>(info[2]).FromMaybe(0);
966
+ int sh = Nan::To<int32_t>(info[3]).FromMaybe(0);
967
+
968
+ if (!sw)
969
+ return Nan::ThrowError("IndexSizeError: The source width is 0.");
970
+ if (!sh)
971
+ return Nan::ThrowError("IndexSizeError: The source height is 0.");
972
+
973
+ int width = canvas->getWidth();
974
+ int height = canvas->getHeight();
975
+
976
+ if (!width)
977
+ return Nan::ThrowTypeError("Canvas width is 0");
978
+ if (!height)
979
+ return Nan::ThrowTypeError("Canvas height is 0");
980
+
981
+ // WebKit and Firefox have this behavior:
982
+ // Flip the coordinates so the origin is top/left-most:
983
+ if (sw < 0) {
984
+ sx += sw;
985
+ sw = -sw;
986
+ }
987
+ if (sh < 0) {
988
+ sy += sh;
989
+ sh = -sh;
990
+ }
991
+
992
+ if (sx + sw > width) sw = width - sx;
993
+ if (sy + sh > height) sh = height - sy;
994
+
995
+ // WebKit/moz functionality. node-canvas used to return in either case.
996
+ if (sw <= 0) sw = 1;
997
+ if (sh <= 0) sh = 1;
998
+
999
+ // Non-compliant. "Pixels outside the canvas must be returned as transparent
1000
+ // black." This instead clips the returned array to the canvas area.
1001
+ if (sx < 0) {
1002
+ sw += sx;
1003
+ sx = 0;
1004
+ }
1005
+ if (sy < 0) {
1006
+ sh += sy;
1007
+ sy = 0;
1008
+ }
1009
+
1010
+ int srcStride = canvas->stride();
1011
+ int bpp = srcStride / width;
1012
+ int size = sw * sh * bpp;
1013
+ int dstStride = sw * bpp;
1014
+
1015
+ uint8_t *src = canvas->data();
1016
+
1017
+ Local<ArrayBuffer> buffer = ArrayBuffer::New(Isolate::GetCurrent(), size);
1018
+ Local<TypedArray> dataArray;
1019
+
1020
+ if (canvas->backend()->getFormat() == CAIRO_FORMAT_RGB16_565) {
1021
+ dataArray = Uint16Array::New(buffer, 0, size >> 1);
1022
+ } else {
1023
+ dataArray = Uint8ClampedArray::New(buffer, 0, size);
1024
+ }
1025
+
1026
+ Nan::TypedArrayContents<uint8_t> typedArrayContents(dataArray);
1027
+ uint8_t* dst = *typedArrayContents;
1028
+
1029
+ switch (canvas->backend()->getFormat()) {
1030
+ case CAIRO_FORMAT_ARGB32: {
1031
+ // Rearrange alpha (argb -> rgba), undo alpha pre-multiplication,
1032
+ // and store in big-endian format
1033
+ for (int y = 0; y < sh; ++y) {
1034
+ uint32_t *row = (uint32_t *)(src + srcStride * (y + sy));
1035
+ for (int x = 0; x < sw; ++x) {
1036
+ int bx = x * 4;
1037
+ uint32_t *pixel = row + x + sx;
1038
+ uint8_t a = *pixel >> 24;
1039
+ uint8_t r = *pixel >> 16;
1040
+ uint8_t g = *pixel >> 8;
1041
+ uint8_t b = *pixel;
1042
+ dst[bx + 3] = a;
1043
+
1044
+ // Performance optimization: fully transparent/opaque pixels can be
1045
+ // processed more efficiently.
1046
+ if (a == 0 || a == 255) {
1047
+ dst[bx + 0] = r;
1048
+ dst[bx + 1] = g;
1049
+ dst[bx + 2] = b;
1050
+ } else {
1051
+ // Undo alpha pre-multiplication
1052
+ float alphaR = (float)255 / a;
1053
+ dst[bx + 0] = (int)((float)r * alphaR);
1054
+ dst[bx + 1] = (int)((float)g * alphaR);
1055
+ dst[bx + 2] = (int)((float)b * alphaR);
1056
+ }
1057
+
1058
+ }
1059
+ dst += dstStride;
1060
+ }
1061
+ break;
1062
+ }
1063
+ case CAIRO_FORMAT_RGB24: {
1064
+ // Rearrange alpha (argb -> rgba) and store in big-endian format
1065
+ for (int y = 0; y < sh; ++y) {
1066
+ uint32_t *row = (uint32_t *)(src + srcStride * (y + sy));
1067
+ for (int x = 0; x < sw; ++x) {
1068
+ int bx = x * 4;
1069
+ uint32_t *pixel = row + x + sx;
1070
+ uint8_t r = *pixel >> 16;
1071
+ uint8_t g = *pixel >> 8;
1072
+ uint8_t b = *pixel;
1073
+
1074
+ dst[bx + 0] = r;
1075
+ dst[bx + 1] = g;
1076
+ dst[bx + 2] = b;
1077
+ dst[bx + 3] = 255;
1078
+ }
1079
+ dst += dstStride;
1080
+ }
1081
+ break;
1082
+ }
1083
+ case CAIRO_FORMAT_A8: {
1084
+ for (int y = 0; y < sh; ++y) {
1085
+ uint8_t *row = (uint8_t *)(src + srcStride * (y + sy));
1086
+ memcpy(dst, row + sx, dstStride);
1087
+ dst += dstStride;
1088
+ }
1089
+ break;
1090
+ }
1091
+ case CAIRO_FORMAT_A1: {
1092
+ // TODO Should this be totally packed, or maintain a stride divisible by 4?
1093
+ Nan::ThrowError("getImageData for CANVAS_FORMAT_A1 is not yet implemented");
1094
+ break;
1095
+ }
1096
+ case CAIRO_FORMAT_RGB16_565: {
1097
+ for (int y = 0; y < sh; ++y) {
1098
+ uint16_t *row = (uint16_t *)(src + srcStride * (y + sy));
1099
+ memcpy(dst, row + sx, dstStride);
1100
+ dst += dstStride;
1101
+ }
1102
+ break;
1103
+ }
1104
+ #ifdef CAIRO_FORMAT_RGB30
1105
+ case CAIRO_FORMAT_RGB30: {
1106
+ // TODO
1107
+ Nan::ThrowError("getImageData for CANVAS_FORMAT_RGB30 is not yet implemented");
1108
+ break;
1109
+ }
1110
+ #endif
1111
+ default: {
1112
+ // Unlikely
1113
+ Nan::ThrowError("Invalid pixel format or not an image canvas");
1114
+ return;
1115
+ }
1116
+ }
1117
+
1118
+ const int argc = 3;
1119
+ Local<Int32> swHandle = Nan::New(sw);
1120
+ Local<Int32> shHandle = Nan::New(sh);
1121
+ Local<Value> argv[argc] = { dataArray, swHandle, shHandle };
1122
+
1123
+ Local<Function> ctor = Nan::GetFunction(Nan::New(ImageData::constructor)).ToLocalChecked();
1124
+ Local<Object> instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked();
1125
+
1126
+ info.GetReturnValue().Set(instance);
1127
+ }
1128
+
1129
+ /**
1130
+ * Create `ImageData` with the given dimensions or
1131
+ * `ImageData` instance for dimensions.
1132
+ */
1133
+
1134
+ NAN_METHOD(Context2d::CreateImageData){
1135
+ Isolate *iso = Isolate::GetCurrent();
1136
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1137
+ Canvas *canvas = context->canvas();
1138
+ int32_t width, height;
1139
+
1140
+ if (info[0]->IsObject()) {
1141
+ Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
1142
+ width = Nan::To<int32_t>(Nan::Get(obj, Nan::New("width").ToLocalChecked()).ToLocalChecked()).FromMaybe(0);
1143
+ height = Nan::To<int32_t>(Nan::Get(obj, Nan::New("height").ToLocalChecked()).ToLocalChecked()).FromMaybe(0);
1144
+ } else {
1145
+ width = Nan::To<int32_t>(info[0]).FromMaybe(0);
1146
+ height = Nan::To<int32_t>(info[1]).FromMaybe(0);
1147
+ }
1148
+
1149
+ int stride = canvas->stride();
1150
+ double Bpp = static_cast<double>(stride) / canvas->getWidth();
1151
+ int nBytes = static_cast<int>(Bpp * width * height + .5);
1152
+
1153
+ Local<ArrayBuffer> ab = ArrayBuffer::New(iso, nBytes);
1154
+ Local<Object> arr;
1155
+
1156
+ if (canvas->backend()->getFormat() == CAIRO_FORMAT_RGB16_565)
1157
+ arr = Uint16Array::New(ab, 0, nBytes / 2);
1158
+ else
1159
+ arr = Uint8ClampedArray::New(ab, 0, nBytes);
1160
+
1161
+ const int argc = 3;
1162
+ Local<Value> argv[argc] = { arr, Nan::New(width), Nan::New(height) };
1163
+
1164
+ Local<Function> ctor = Nan::GetFunction(Nan::New(ImageData::constructor)).ToLocalChecked();
1165
+ Local<Object> instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked();
1166
+
1167
+ info.GetReturnValue().Set(instance);
1168
+ }
1169
+
1170
+ /*
1171
+ * Take a transform matrix and return its components
1172
+ * 0: angle, 1: scaleX, 2: scaleY, 3: skewX, 4: translateX, 5: translateY
1173
+ */
1174
+ void decompose_matrix(cairo_matrix_t matrix, double *destination) {
1175
+ double denom = pow(matrix.xx, 2) + pow(matrix.yx, 2);
1176
+ destination[0] = atan2(matrix.yx, matrix.xx);
1177
+ destination[1] = sqrt(denom);
1178
+ destination[2] = (matrix.xx * matrix.yy - matrix.xy * matrix.yx) / destination[1];
1179
+ destination[3] = atan2(matrix.xx * matrix.xy + matrix.yx * matrix.yy, denom);
1180
+ destination[4] = matrix.x0;
1181
+ destination[5] = matrix.y0;
1182
+ }
1183
+
1184
+ /*
1185
+ * Draw image src image to the destination (context).
1186
+ *
1187
+ * - dx, dy
1188
+ * - dx, dy, dw, dh
1189
+ * - sx, sy, sw, sh, dx, dy, dw, dh
1190
+ *
1191
+ */
1192
+
1193
+ NAN_METHOD(Context2d::DrawImage) {
1194
+ int infoLen = info.Length();
1195
+ if (infoLen != 3 && infoLen != 5 && infoLen != 9)
1196
+ return Nan::ThrowTypeError("Invalid arguments");
1197
+
1198
+ if (!info[0]->IsObject())
1199
+ return Nan::ThrowTypeError("The first argument must be an object");
1200
+
1201
+ double args[8];
1202
+ if(!checkArgs(info, args, infoLen - 1, 1))
1203
+ return;
1204
+
1205
+ double sx = 0
1206
+ , sy = 0
1207
+ , sw = 0
1208
+ , sh = 0
1209
+ , dx = 0
1210
+ , dy = 0
1211
+ , dw = 0
1212
+ , dh = 0
1213
+ , source_w = 0
1214
+ , source_h = 0;
1215
+
1216
+ cairo_surface_t *surface;
1217
+
1218
+ Local<Object> obj = Nan::To<Object>(info[0]).ToLocalChecked();
1219
+
1220
+ // Image
1221
+ if (Nan::New(Image::constructor)->HasInstance(obj)) {
1222
+ Image *img = Nan::ObjectWrap::Unwrap<Image>(obj);
1223
+ if (!img->isComplete()) {
1224
+ return Nan::ThrowError("Image given has not completed loading");
1225
+ }
1226
+ source_w = sw = img->width;
1227
+ source_h = sh = img->height;
1228
+ surface = img->surface();
1229
+
1230
+ // Canvas
1231
+ } else if (Nan::New(Canvas::constructor)->HasInstance(obj)) {
1232
+ Canvas *canvas = Nan::ObjectWrap::Unwrap<Canvas>(obj);
1233
+ source_w = sw = canvas->getWidth();
1234
+ source_h = sh = canvas->getHeight();
1235
+ surface = canvas->surface();
1236
+
1237
+ // Invalid
1238
+ } else {
1239
+ return Nan::ThrowTypeError("Image or Canvas expected");
1240
+ }
1241
+
1242
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1243
+ cairo_t *ctx = context->context();
1244
+
1245
+ // Arguments
1246
+ switch (infoLen) {
1247
+ // img, sx, sy, sw, sh, dx, dy, dw, dh
1248
+ case 9:
1249
+ sx = args[0];
1250
+ sy = args[1];
1251
+ sw = args[2];
1252
+ sh = args[3];
1253
+ dx = args[4];
1254
+ dy = args[5];
1255
+ dw = args[6];
1256
+ dh = args[7];
1257
+ break;
1258
+ // img, dx, dy, dw, dh
1259
+ case 5:
1260
+ dx = args[0];
1261
+ dy = args[1];
1262
+ dw = args[2];
1263
+ dh = args[3];
1264
+ break;
1265
+ // img, dx, dy
1266
+ case 3:
1267
+ dx = args[0];
1268
+ dy = args[1];
1269
+ dw = sw;
1270
+ dh = sh;
1271
+ break;
1272
+ }
1273
+
1274
+ if (!(sw && sh && dw && dh))
1275
+ return;
1276
+
1277
+ // Start draw
1278
+ cairo_save(ctx);
1279
+
1280
+ cairo_matrix_t matrix;
1281
+ double transforms[6];
1282
+ cairo_get_matrix(context->context(), &matrix);
1283
+ decompose_matrix(matrix, transforms);
1284
+ // extract the scale value from the current transform so that we know how many pixels we
1285
+ // need for our extra canvas in the drawImage operation.
1286
+ double current_scale_x = std::abs(transforms[1]);
1287
+ double current_scale_y = std::abs(transforms[2]);
1288
+ double extra_dx = 0;
1289
+ double extra_dy = 0;
1290
+ double fx = dw / sw * current_scale_x; // transforms[1] is scale on X
1291
+ double fy = dh / sh * current_scale_y; // transforms[2] is scale on X
1292
+ bool needScale = dw != sw || dh != sh;
1293
+ bool needCut = sw != source_w || sh != source_h || sx < 0 || sy < 0;
1294
+ bool sameCanvas = surface == context->canvas()->surface();
1295
+ bool needsExtraSurface = sameCanvas || needCut || needScale;
1296
+ cairo_surface_t *surfTemp = NULL;
1297
+ cairo_t *ctxTemp = NULL;
1298
+
1299
+ if (needsExtraSurface) {
1300
+ // we want to create the extra surface as small as possible.
1301
+ // fx and fy are the total scaling we need to apply to sw, sh.
1302
+ // from sw and sh we want to remove the part that is outside the source_w and soruce_h
1303
+ double real_w = sw;
1304
+ double real_h = sh;
1305
+ double translate_x = 0;
1306
+ double translate_y = 0;
1307
+ // if sx or sy are negative, a part of the area represented by sw and sh is empty
1308
+ // because there are empty pixels, so we cut it out.
1309
+ // On the other hand if sx or sy are positive, but sw and sh extend outside the real
1310
+ // source pixels, we cut the area in that case too.
1311
+ if (sx < 0) {
1312
+ extra_dx = -sx * fx;
1313
+ real_w = sw + sx;
1314
+ } else if (sx + sw > source_w) {
1315
+ real_w = sw - (sx + sw - source_w);
1316
+ }
1317
+ if (sy < 0) {
1318
+ extra_dy = -sy * fy;
1319
+ real_h = sh + sy;
1320
+ } else if (sy + sh > source_h) {
1321
+ real_h = sh - (sy + sh - source_h);
1322
+ }
1323
+ // if after cutting we are still bigger than source pixels, we restrict again
1324
+ if (real_w > source_w) {
1325
+ real_w = source_w;
1326
+ }
1327
+ if (real_h > source_h) {
1328
+ real_h = source_h;
1329
+ }
1330
+ // TODO: find a way to limit the surfTemp to real_w and real_h if fx and fy are bigger than 1.
1331
+ // there are no more pixel than the one available in the source, no need to create a bigger surface.
1332
+ surfTemp = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, round(real_w * fx), round(real_h * fy));
1333
+ ctxTemp = cairo_create(surfTemp);
1334
+ cairo_scale(ctxTemp, fx, fy);
1335
+ if (sx > 0) {
1336
+ translate_x = sx;
1337
+ }
1338
+ if (sy > 0) {
1339
+ translate_y = sy;
1340
+ }
1341
+ cairo_set_source_surface(ctxTemp, surface, -translate_x, -translate_y);
1342
+ cairo_pattern_set_filter(cairo_get_source(ctxTemp), context->state->imageSmoothingEnabled ? context->state->patternQuality : CAIRO_FILTER_NEAREST);
1343
+ cairo_pattern_set_extend(cairo_get_source(ctxTemp), CAIRO_EXTEND_REFLECT);
1344
+ cairo_paint_with_alpha(ctxTemp, 1);
1345
+ surface = surfTemp;
1346
+ }
1347
+ // apply shadow if there is one
1348
+ if (context->hasShadow()) {
1349
+ if(context->state->shadowBlur) {
1350
+ // we need to create a new surface in order to blur
1351
+ int pad = context->state->shadowBlur * 2;
1352
+ cairo_surface_t *shadow_surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, dw + 2 * pad, dh + 2 * pad);
1353
+ cairo_t *shadow_context = cairo_create(shadow_surface);
1354
+
1355
+ // mask and blur
1356
+ context->setSourceRGBA(shadow_context, context->state->shadow);
1357
+ cairo_mask_surface(shadow_context, surface, pad, pad);
1358
+ context->blur(shadow_surface, context->state->shadowBlur);
1359
+
1360
+ // paint
1361
+ // @note: ShadowBlur looks different in each browser. This implementation matches chrome as close as possible.
1362
+ // The 1.4 offset comes from visual tests with Chrome. I have read the spec and part of the shadowBlur
1363
+ // implementation, and its not immediately clear why an offset is necessary, but without it, the result
1364
+ // in chrome is different.
1365
+ cairo_set_source_surface(ctx, shadow_surface,
1366
+ dx + context->state->shadowOffsetX - pad + 1.4,
1367
+ dy + context->state->shadowOffsetY - pad + 1.4);
1368
+ cairo_paint(ctx);
1369
+ // cleanup
1370
+ cairo_destroy(shadow_context);
1371
+ cairo_surface_destroy(shadow_surface);
1372
+ } else {
1373
+ context->setSourceRGBA(context->state->shadow);
1374
+ cairo_mask_surface(ctx, surface,
1375
+ dx + (context->state->shadowOffsetX),
1376
+ dy + (context->state->shadowOffsetY));
1377
+ }
1378
+ }
1379
+
1380
+ double scaled_dx = dx;
1381
+ double scaled_dy = dy;
1382
+
1383
+ if (needsExtraSurface && (current_scale_x != 1 || current_scale_y != 1)) {
1384
+ // in this case our surface contains already current_scale_x, we need to scale back
1385
+ cairo_scale(ctx, 1 / current_scale_x, 1 / current_scale_y);
1386
+ scaled_dx *= current_scale_x;
1387
+ scaled_dy *= current_scale_y;
1388
+ }
1389
+ // Paint
1390
+ cairo_set_source_surface(ctx, surface, scaled_dx + extra_dx, scaled_dy + extra_dy);
1391
+ cairo_pattern_set_filter(cairo_get_source(ctx), context->state->imageSmoothingEnabled ? context->state->patternQuality : CAIRO_FILTER_NEAREST);
1392
+ cairo_pattern_set_extend(cairo_get_source(ctx), CAIRO_EXTEND_NONE);
1393
+ cairo_paint_with_alpha(ctx, context->state->globalAlpha);
1394
+
1395
+ cairo_restore(ctx);
1396
+
1397
+ if (needsExtraSurface) {
1398
+ cairo_destroy(ctxTemp);
1399
+ cairo_surface_destroy(surfTemp);
1400
+ }
1401
+ }
1402
+
1403
+ /*
1404
+ * Get global alpha.
1405
+ */
1406
+
1407
+ NAN_GETTER(Context2d::GetGlobalAlpha) {
1408
+ CHECK_RECEIVER(Context2d.GetGlobalAlpha);
1409
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1410
+ info.GetReturnValue().Set(Nan::New<Number>(context->state->globalAlpha));
1411
+ }
1412
+
1413
+ /*
1414
+ * Set global alpha.
1415
+ */
1416
+
1417
+ NAN_SETTER(Context2d::SetGlobalAlpha) {
1418
+ CHECK_RECEIVER(Context2d.SetGlobalAlpha);
1419
+ double n = Nan::To<double>(value).FromMaybe(0);
1420
+ if (n >= 0 && n <= 1) {
1421
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1422
+ context->state->globalAlpha = n;
1423
+ }
1424
+ }
1425
+
1426
+ /*
1427
+ * Get global composite operation.
1428
+ */
1429
+
1430
+ NAN_GETTER(Context2d::GetGlobalCompositeOperation) {
1431
+ CHECK_RECEIVER(Context2d.GetGlobalCompositeOperation);
1432
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1433
+ cairo_t *ctx = context->context();
1434
+
1435
+ const char *op = "source-over";
1436
+ switch (cairo_get_operator(ctx)) {
1437
+ // composite modes:
1438
+ case CAIRO_OPERATOR_CLEAR: op = "clear"; break;
1439
+ case CAIRO_OPERATOR_SOURCE: op = "copy"; break;
1440
+ case CAIRO_OPERATOR_DEST: op = "destination"; break;
1441
+ case CAIRO_OPERATOR_OVER: op = "source-over"; break;
1442
+ case CAIRO_OPERATOR_DEST_OVER: op = "destination-over"; break;
1443
+ case CAIRO_OPERATOR_IN: op = "source-in"; break;
1444
+ case CAIRO_OPERATOR_DEST_IN: op = "destination-in"; break;
1445
+ case CAIRO_OPERATOR_OUT: op = "source-out"; break;
1446
+ case CAIRO_OPERATOR_DEST_OUT: op = "destination-out"; break;
1447
+ case CAIRO_OPERATOR_ATOP: op = "source-atop"; break;
1448
+ case CAIRO_OPERATOR_DEST_ATOP: op = "destination-atop"; break;
1449
+ case CAIRO_OPERATOR_XOR: op = "xor"; break;
1450
+ case CAIRO_OPERATOR_ADD: op = "lighter"; break;
1451
+ // blend modes:
1452
+ // Note: "source-over" and "normal" are synonyms. Chrome and FF both report
1453
+ // "source-over" after setting gCO to "normal".
1454
+ // case CAIRO_OPERATOR_OVER: op = "normal";
1455
+ case CAIRO_OPERATOR_MULTIPLY: op = "multiply"; break;
1456
+ case CAIRO_OPERATOR_SCREEN: op = "screen"; break;
1457
+ case CAIRO_OPERATOR_OVERLAY: op = "overlay"; break;
1458
+ case CAIRO_OPERATOR_DARKEN: op = "darken"; break;
1459
+ case CAIRO_OPERATOR_LIGHTEN: op = "lighten"; break;
1460
+ case CAIRO_OPERATOR_COLOR_DODGE: op = "color-dodge"; break;
1461
+ case CAIRO_OPERATOR_COLOR_BURN: op = "color-burn"; break;
1462
+ case CAIRO_OPERATOR_HARD_LIGHT: op = "hard-light"; break;
1463
+ case CAIRO_OPERATOR_SOFT_LIGHT: op = "soft-light"; break;
1464
+ case CAIRO_OPERATOR_DIFFERENCE: op = "difference"; break;
1465
+ case CAIRO_OPERATOR_EXCLUSION: op = "exclusion"; break;
1466
+ case CAIRO_OPERATOR_HSL_HUE: op = "hue"; break;
1467
+ case CAIRO_OPERATOR_HSL_SATURATION: op = "saturation"; break;
1468
+ case CAIRO_OPERATOR_HSL_COLOR: op = "color"; break;
1469
+ case CAIRO_OPERATOR_HSL_LUMINOSITY: op = "luminosity"; break;
1470
+ // non-standard:
1471
+ case CAIRO_OPERATOR_SATURATE: op = "saturate"; break;
1472
+ }
1473
+
1474
+ info.GetReturnValue().Set(Nan::New(op).ToLocalChecked());
1475
+ }
1476
+
1477
+ /*
1478
+ * Set pattern quality.
1479
+ */
1480
+
1481
+ NAN_SETTER(Context2d::SetPatternQuality) {
1482
+ CHECK_RECEIVER(Context2d.SetPatternQuality);
1483
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1484
+ Nan::Utf8String quality(Nan::To<String>(value).ToLocalChecked());
1485
+ if (0 == strcmp("fast", *quality)) {
1486
+ context->state->patternQuality = CAIRO_FILTER_FAST;
1487
+ } else if (0 == strcmp("good", *quality)) {
1488
+ context->state->patternQuality = CAIRO_FILTER_GOOD;
1489
+ } else if (0 == strcmp("best", *quality)) {
1490
+ context->state->patternQuality = CAIRO_FILTER_BEST;
1491
+ } else if (0 == strcmp("nearest", *quality)) {
1492
+ context->state->patternQuality = CAIRO_FILTER_NEAREST;
1493
+ } else if (0 == strcmp("bilinear", *quality)) {
1494
+ context->state->patternQuality = CAIRO_FILTER_BILINEAR;
1495
+ }
1496
+ }
1497
+
1498
+ /*
1499
+ * Get pattern quality.
1500
+ */
1501
+
1502
+ NAN_GETTER(Context2d::GetPatternQuality) {
1503
+ CHECK_RECEIVER(Context2d.GetPatternQuality);
1504
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1505
+ const char *quality;
1506
+ switch (context->state->patternQuality) {
1507
+ case CAIRO_FILTER_FAST: quality = "fast"; break;
1508
+ case CAIRO_FILTER_BEST: quality = "best"; break;
1509
+ case CAIRO_FILTER_NEAREST: quality = "nearest"; break;
1510
+ case CAIRO_FILTER_BILINEAR: quality = "bilinear"; break;
1511
+ default: quality = "good";
1512
+ }
1513
+ info.GetReturnValue().Set(Nan::New(quality).ToLocalChecked());
1514
+ }
1515
+
1516
+ /*
1517
+ * Set ImageSmoothingEnabled value.
1518
+ */
1519
+
1520
+ NAN_SETTER(Context2d::SetImageSmoothingEnabled) {
1521
+ CHECK_RECEIVER(Context2d.SetImageSmoothingEnabled);
1522
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1523
+ context->state->imageSmoothingEnabled = Nan::To<bool>(value).FromMaybe(false);
1524
+ }
1525
+
1526
+ /*
1527
+ * Get pattern quality.
1528
+ */
1529
+
1530
+ NAN_GETTER(Context2d::GetImageSmoothingEnabled) {
1531
+ CHECK_RECEIVER(Context2d.GetImageSmoothingEnabled);
1532
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1533
+ info.GetReturnValue().Set(Nan::New<Boolean>(context->state->imageSmoothingEnabled));
1534
+ }
1535
+
1536
+ /*
1537
+ * Set global composite operation.
1538
+ */
1539
+
1540
+ NAN_SETTER(Context2d::SetGlobalCompositeOperation) {
1541
+ CHECK_RECEIVER(Context2d.SetGlobalCompositeOperation);
1542
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1543
+ cairo_t *ctx = context->context();
1544
+ Nan::Utf8String opStr(Nan::To<String>(value).ToLocalChecked()); // Unlike CSS colors, this *is* case-sensitive
1545
+ const std::map<std::string, cairo_operator_t> blendmodes = {
1546
+ // composite modes:
1547
+ {"clear", CAIRO_OPERATOR_CLEAR},
1548
+ {"copy", CAIRO_OPERATOR_SOURCE},
1549
+ {"destination", CAIRO_OPERATOR_DEST}, // this seems to have been omitted from the spec
1550
+ {"source-over", CAIRO_OPERATOR_OVER},
1551
+ {"destination-over", CAIRO_OPERATOR_DEST_OVER},
1552
+ {"source-in", CAIRO_OPERATOR_IN},
1553
+ {"destination-in", CAIRO_OPERATOR_DEST_IN},
1554
+ {"source-out", CAIRO_OPERATOR_OUT},
1555
+ {"destination-out", CAIRO_OPERATOR_DEST_OUT},
1556
+ {"source-atop", CAIRO_OPERATOR_ATOP},
1557
+ {"destination-atop", CAIRO_OPERATOR_DEST_ATOP},
1558
+ {"xor", CAIRO_OPERATOR_XOR},
1559
+ {"lighter", CAIRO_OPERATOR_ADD},
1560
+ // blend modes:
1561
+ {"normal", CAIRO_OPERATOR_OVER},
1562
+ {"multiply", CAIRO_OPERATOR_MULTIPLY},
1563
+ {"screen", CAIRO_OPERATOR_SCREEN},
1564
+ {"overlay", CAIRO_OPERATOR_OVERLAY},
1565
+ {"darken", CAIRO_OPERATOR_DARKEN},
1566
+ {"lighten", CAIRO_OPERATOR_LIGHTEN},
1567
+ {"color-dodge", CAIRO_OPERATOR_COLOR_DODGE},
1568
+ {"color-burn", CAIRO_OPERATOR_COLOR_BURN},
1569
+ {"hard-light", CAIRO_OPERATOR_HARD_LIGHT},
1570
+ {"soft-light", CAIRO_OPERATOR_SOFT_LIGHT},
1571
+ {"difference", CAIRO_OPERATOR_DIFFERENCE},
1572
+ {"exclusion", CAIRO_OPERATOR_EXCLUSION},
1573
+ {"hue", CAIRO_OPERATOR_HSL_HUE},
1574
+ {"saturation", CAIRO_OPERATOR_HSL_SATURATION},
1575
+ {"color", CAIRO_OPERATOR_HSL_COLOR},
1576
+ {"luminosity", CAIRO_OPERATOR_HSL_LUMINOSITY},
1577
+ // non-standard:
1578
+ {"saturate", CAIRO_OPERATOR_SATURATE}
1579
+ };
1580
+ auto op = blendmodes.find(*opStr);
1581
+ if (op != blendmodes.end()) cairo_set_operator(ctx, op->second);
1582
+ }
1583
+
1584
+ /*
1585
+ * Get shadow offset x.
1586
+ */
1587
+
1588
+ NAN_GETTER(Context2d::GetShadowOffsetX) {
1589
+ CHECK_RECEIVER(Context2d.GetShadowOffsetX);
1590
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1591
+ info.GetReturnValue().Set(Nan::New<Number>(context->state->shadowOffsetX));
1592
+ }
1593
+
1594
+ /*
1595
+ * Set shadow offset x.
1596
+ */
1597
+
1598
+ NAN_SETTER(Context2d::SetShadowOffsetX) {
1599
+ CHECK_RECEIVER(Context2d.SetShadowOffsetX);
1600
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1601
+ context->state->shadowOffsetX = Nan::To<double>(value).FromMaybe(0);
1602
+ }
1603
+
1604
+ /*
1605
+ * Get shadow offset y.
1606
+ */
1607
+
1608
+ NAN_GETTER(Context2d::GetShadowOffsetY) {
1609
+ CHECK_RECEIVER(Context2d.GetShadowOffsetY);
1610
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1611
+ info.GetReturnValue().Set(Nan::New<Number>(context->state->shadowOffsetY));
1612
+ }
1613
+
1614
+ /*
1615
+ * Set shadow offset y.
1616
+ */
1617
+
1618
+ NAN_SETTER(Context2d::SetShadowOffsetY) {
1619
+ CHECK_RECEIVER(Context2d.SetShadowOffsetY);
1620
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1621
+ context->state->shadowOffsetY = Nan::To<double>(value).FromMaybe(0);
1622
+ }
1623
+
1624
+ /*
1625
+ * Get shadow blur.
1626
+ */
1627
+
1628
+ NAN_GETTER(Context2d::GetShadowBlur) {
1629
+ CHECK_RECEIVER(Context2d.GetShadowBlur);
1630
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1631
+ info.GetReturnValue().Set(Nan::New<Number>(context->state->shadowBlur));
1632
+ }
1633
+
1634
+ /*
1635
+ * Set shadow blur.
1636
+ */
1637
+
1638
+ NAN_SETTER(Context2d::SetShadowBlur) {
1639
+ CHECK_RECEIVER(Context2d.SetShadowBlur);
1640
+ int n = Nan::To<double>(value).FromMaybe(0);
1641
+ if (n >= 0) {
1642
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1643
+ context->state->shadowBlur = n;
1644
+ }
1645
+ }
1646
+
1647
+ /*
1648
+ * Get current antialiasing setting.
1649
+ */
1650
+
1651
+ NAN_GETTER(Context2d::GetAntiAlias) {
1652
+ CHECK_RECEIVER(Context2d.GetAntiAlias);
1653
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1654
+ const char *aa;
1655
+ switch (cairo_get_antialias(context->context())) {
1656
+ case CAIRO_ANTIALIAS_NONE: aa = "none"; break;
1657
+ case CAIRO_ANTIALIAS_GRAY: aa = "gray"; break;
1658
+ case CAIRO_ANTIALIAS_SUBPIXEL: aa = "subpixel"; break;
1659
+ default: aa = "default";
1660
+ }
1661
+ info.GetReturnValue().Set(Nan::New(aa).ToLocalChecked());
1662
+ }
1663
+
1664
+ /*
1665
+ * Set antialiasing.
1666
+ */
1667
+
1668
+ NAN_SETTER(Context2d::SetAntiAlias) {
1669
+ CHECK_RECEIVER(Context2d.SetAntiAlias);
1670
+ Nan::Utf8String str(Nan::To<String>(value).ToLocalChecked());
1671
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1672
+ cairo_t *ctx = context->context();
1673
+ cairo_antialias_t a;
1674
+ if (0 == strcmp("none", *str)) {
1675
+ a = CAIRO_ANTIALIAS_NONE;
1676
+ } else if (0 == strcmp("default", *str)) {
1677
+ a = CAIRO_ANTIALIAS_DEFAULT;
1678
+ } else if (0 == strcmp("gray", *str)) {
1679
+ a = CAIRO_ANTIALIAS_GRAY;
1680
+ } else if (0 == strcmp("subpixel", *str)) {
1681
+ a = CAIRO_ANTIALIAS_SUBPIXEL;
1682
+ } else {
1683
+ a = cairo_get_antialias(ctx);
1684
+ }
1685
+ cairo_set_antialias(ctx, a);
1686
+ }
1687
+
1688
+ /*
1689
+ * Get text drawing mode.
1690
+ */
1691
+
1692
+ NAN_GETTER(Context2d::GetTextDrawingMode) {
1693
+ CHECK_RECEIVER(Context2d.GetTextDrawingMode);
1694
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1695
+ const char *mode;
1696
+ if (context->state->textDrawingMode == TEXT_DRAW_PATHS) {
1697
+ mode = "path";
1698
+ } else if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) {
1699
+ mode = "glyph";
1700
+ } else {
1701
+ mode = "unknown";
1702
+ }
1703
+ info.GetReturnValue().Set(Nan::New(mode).ToLocalChecked());
1704
+ }
1705
+
1706
+ /*
1707
+ * Set text drawing mode.
1708
+ */
1709
+
1710
+ NAN_SETTER(Context2d::SetTextDrawingMode) {
1711
+ CHECK_RECEIVER(Context2d.SetTextDrawingMode);
1712
+ Nan::Utf8String str(Nan::To<String>(value).ToLocalChecked());
1713
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1714
+ if (0 == strcmp("path", *str)) {
1715
+ context->state->textDrawingMode = TEXT_DRAW_PATHS;
1716
+ } else if (0 == strcmp("glyph", *str)) {
1717
+ context->state->textDrawingMode = TEXT_DRAW_GLYPHS;
1718
+ }
1719
+ }
1720
+
1721
+ /*
1722
+ * Get filter.
1723
+ */
1724
+
1725
+ NAN_GETTER(Context2d::GetQuality) {
1726
+ CHECK_RECEIVER(Context2d.GetQuality);
1727
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1728
+ const char *filter;
1729
+ switch (cairo_pattern_get_filter(cairo_get_source(context->context()))) {
1730
+ case CAIRO_FILTER_FAST: filter = "fast"; break;
1731
+ case CAIRO_FILTER_BEST: filter = "best"; break;
1732
+ case CAIRO_FILTER_NEAREST: filter = "nearest"; break;
1733
+ case CAIRO_FILTER_BILINEAR: filter = "bilinear"; break;
1734
+ default: filter = "good";
1735
+ }
1736
+ info.GetReturnValue().Set(Nan::New(filter).ToLocalChecked());
1737
+ }
1738
+
1739
+ /*
1740
+ * Set filter.
1741
+ */
1742
+
1743
+ NAN_SETTER(Context2d::SetQuality) {
1744
+ CHECK_RECEIVER(Context2d.SetQuality);
1745
+ Nan::Utf8String str(Nan::To<String>(value).ToLocalChecked());
1746
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1747
+ cairo_filter_t filter;
1748
+ if (0 == strcmp("fast", *str)) {
1749
+ filter = CAIRO_FILTER_FAST;
1750
+ } else if (0 == strcmp("best", *str)) {
1751
+ filter = CAIRO_FILTER_BEST;
1752
+ } else if (0 == strcmp("nearest", *str)) {
1753
+ filter = CAIRO_FILTER_NEAREST;
1754
+ } else if (0 == strcmp("bilinear", *str)) {
1755
+ filter = CAIRO_FILTER_BILINEAR;
1756
+ } else {
1757
+ filter = CAIRO_FILTER_GOOD;
1758
+ }
1759
+ cairo_pattern_set_filter(cairo_get_source(context->context()), filter);
1760
+ }
1761
+
1762
+ /*
1763
+ * Helper for get current transform matrix
1764
+ */
1765
+
1766
+ Local<Object>
1767
+ get_current_transform(Context2d *context) {
1768
+ Isolate *iso = Isolate::GetCurrent();
1769
+
1770
+ Local<Float64Array> arr = Float64Array::New(ArrayBuffer::New(iso, 48), 0, 6);
1771
+ Nan::TypedArrayContents<double> dest(arr);
1772
+ cairo_matrix_t matrix;
1773
+ cairo_get_matrix(context->context(), &matrix);
1774
+ (*dest)[0] = matrix.xx;
1775
+ (*dest)[1] = matrix.yx;
1776
+ (*dest)[2] = matrix.xy;
1777
+ (*dest)[3] = matrix.yy;
1778
+ (*dest)[4] = matrix.x0;
1779
+ (*dest)[5] = matrix.y0;
1780
+
1781
+ const int argc = 1;
1782
+ Local<Value> argv[argc] = { arr };
1783
+ return Nan::NewInstance(context->_DOMMatrix.Get(iso), argc, argv).ToLocalChecked();
1784
+ }
1785
+
1786
+ /*
1787
+ * Helper for get/set transform.
1788
+ */
1789
+
1790
+ void parse_matrix_from_object(cairo_matrix_t &matrix, Local<Object> mat) {
1791
+ cairo_matrix_init(&matrix,
1792
+ Nan::To<double>(Nan::Get(mat, Nan::New("a").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
1793
+ Nan::To<double>(Nan::Get(mat, Nan::New("b").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
1794
+ Nan::To<double>(Nan::Get(mat, Nan::New("c").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
1795
+ Nan::To<double>(Nan::Get(mat, Nan::New("d").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
1796
+ Nan::To<double>(Nan::Get(mat, Nan::New("e").ToLocalChecked()).ToLocalChecked()).FromMaybe(0),
1797
+ Nan::To<double>(Nan::Get(mat, Nan::New("f").ToLocalChecked()).ToLocalChecked()).FromMaybe(0)
1798
+ );
1799
+ }
1800
+
1801
+
1802
+ /*
1803
+ * Get current transform.
1804
+ */
1805
+
1806
+ NAN_GETTER(Context2d::GetCurrentTransform) {
1807
+ CHECK_RECEIVER(Context2d.GetCurrentTransform);
1808
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1809
+ Local<Object> instance = get_current_transform(context);
1810
+
1811
+ info.GetReturnValue().Set(instance);
1812
+ }
1813
+
1814
+ /*
1815
+ * Set current transform.
1816
+ */
1817
+
1818
+ NAN_SETTER(Context2d::SetCurrentTransform) {
1819
+ CHECK_RECEIVER(Context2d.SetCurrentTransform);
1820
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1821
+ Local<Context> ctx = Nan::GetCurrentContext();
1822
+ Local<Object> mat = Nan::To<Object>(value).ToLocalChecked();
1823
+
1824
+ #if NODE_MAJOR_VERSION >= 8
1825
+ if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) {
1826
+ return Nan::ThrowTypeError("Expected DOMMatrix");
1827
+ }
1828
+ #endif
1829
+
1830
+ cairo_matrix_t matrix;
1831
+ parse_matrix_from_object(matrix, mat);
1832
+
1833
+ cairo_transform(context->context(), &matrix);
1834
+ }
1835
+
1836
+ /*
1837
+ * Get current fill style.
1838
+ */
1839
+
1840
+ NAN_GETTER(Context2d::GetFillStyle) {
1841
+ CHECK_RECEIVER(Context2d.GetFillStyle);
1842
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1843
+ Isolate *iso = Isolate::GetCurrent();
1844
+ Local<Value> style;
1845
+
1846
+ if (context->_fillStyle.IsEmpty())
1847
+ style = context->_getFillColor();
1848
+ else
1849
+ style = context->_fillStyle.Get(iso);
1850
+
1851
+ info.GetReturnValue().Set(style);
1852
+ }
1853
+
1854
+ /*
1855
+ * Set current fill style.
1856
+ */
1857
+
1858
+ NAN_SETTER(Context2d::SetFillStyle) {
1859
+ CHECK_RECEIVER(Context2d.SetFillStyle);
1860
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1861
+
1862
+ if (value->IsString()) {
1863
+ MaybeLocal<String> mstr = Nan::To<String>(value);
1864
+ if (mstr.IsEmpty()) return;
1865
+ Local<String> str = mstr.ToLocalChecked();
1866
+ context->_fillStyle.Reset();
1867
+ context->_setFillColor(str);
1868
+ } else if (value->IsObject()) {
1869
+ Local<Object> obj = Nan::To<Object>(value).ToLocalChecked();
1870
+ if (Nan::New(Gradient::constructor)->HasInstance(obj)) {
1871
+ context->_fillStyle.Reset(value);
1872
+ Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(obj);
1873
+ context->state->fillGradient = grad->pattern();
1874
+ } else if (Nan::New(Pattern::constructor)->HasInstance(obj)) {
1875
+ context->_fillStyle.Reset(value);
1876
+ Pattern *pattern = Nan::ObjectWrap::Unwrap<Pattern>(obj);
1877
+ context->state->fillPattern = pattern->pattern();
1878
+ }
1879
+ }
1880
+ }
1881
+
1882
+ /*
1883
+ * Get current stroke style.
1884
+ */
1885
+
1886
+ NAN_GETTER(Context2d::GetStrokeStyle) {
1887
+ CHECK_RECEIVER(Context2d.GetStrokeStyle);
1888
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1889
+ Local<Value> style;
1890
+
1891
+ if (context->_strokeStyle.IsEmpty())
1892
+ style = context->_getStrokeColor();
1893
+ else
1894
+ style = context->_strokeStyle.Get(Isolate::GetCurrent());
1895
+
1896
+ info.GetReturnValue().Set(style);
1897
+ }
1898
+
1899
+ /*
1900
+ * Set current stroke style.
1901
+ */
1902
+
1903
+ NAN_SETTER(Context2d::SetStrokeStyle) {
1904
+ CHECK_RECEIVER(Context2d.SetStrokeStyle);
1905
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1906
+
1907
+ if (value->IsString()) {
1908
+ MaybeLocal<String> mstr = Nan::To<String>(value);
1909
+ if (mstr.IsEmpty()) return;
1910
+ Local<String> str = mstr.ToLocalChecked();
1911
+ context->_strokeStyle.Reset();
1912
+ context->_setStrokeColor(str);
1913
+ } else if (value->IsObject()) {
1914
+ Local<Object> obj = Nan::To<Object>(value).ToLocalChecked();
1915
+ if (Nan::New(Gradient::constructor)->HasInstance(obj)) {
1916
+ context->_strokeStyle.Reset(value);
1917
+ Gradient *grad = Nan::ObjectWrap::Unwrap<Gradient>(obj);
1918
+ context->state->strokeGradient = grad->pattern();
1919
+ } else if (Nan::New(Pattern::constructor)->HasInstance(obj)) {
1920
+ context->_strokeStyle.Reset(value);
1921
+ Pattern *pattern = Nan::ObjectWrap::Unwrap<Pattern>(obj);
1922
+ context->state->strokePattern = pattern->pattern();
1923
+ }
1924
+ }
1925
+ }
1926
+
1927
+ /*
1928
+ * Get miter limit.
1929
+ */
1930
+
1931
+ NAN_GETTER(Context2d::GetMiterLimit) {
1932
+ CHECK_RECEIVER(Context2d.GetMiterLimit);
1933
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1934
+ info.GetReturnValue().Set(Nan::New<Number>(cairo_get_miter_limit(context->context())));
1935
+ }
1936
+
1937
+ /*
1938
+ * Set miter limit.
1939
+ */
1940
+
1941
+ NAN_SETTER(Context2d::SetMiterLimit) {
1942
+ CHECK_RECEIVER(Context2d.SetMiterLimit);
1943
+ double n = Nan::To<double>(value).FromMaybe(0);
1944
+ if (n > 0) {
1945
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1946
+ cairo_set_miter_limit(context->context(), n);
1947
+ }
1948
+ }
1949
+
1950
+ /*
1951
+ * Get line width.
1952
+ */
1953
+
1954
+ NAN_GETTER(Context2d::GetLineWidth) {
1955
+ CHECK_RECEIVER(Context2d.GetLineWidth);
1956
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1957
+ info.GetReturnValue().Set(Nan::New<Number>(cairo_get_line_width(context->context())));
1958
+ }
1959
+
1960
+ /*
1961
+ * Set line width.
1962
+ */
1963
+
1964
+ NAN_SETTER(Context2d::SetLineWidth) {
1965
+ CHECK_RECEIVER(Context2d.SetLineWidth);
1966
+ double n = Nan::To<double>(value).FromMaybe(0);
1967
+ if (n > 0 && n != std::numeric_limits<double>::infinity()) {
1968
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1969
+ cairo_set_line_width(context->context(), n);
1970
+ }
1971
+ }
1972
+
1973
+ /*
1974
+ * Get line join.
1975
+ */
1976
+
1977
+ NAN_GETTER(Context2d::GetLineJoin) {
1978
+ CHECK_RECEIVER(Context2d.GetLineJoin);
1979
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1980
+ const char *join;
1981
+ switch (cairo_get_line_join(context->context())) {
1982
+ case CAIRO_LINE_JOIN_BEVEL: join = "bevel"; break;
1983
+ case CAIRO_LINE_JOIN_ROUND: join = "round"; break;
1984
+ default: join = "miter";
1985
+ }
1986
+ info.GetReturnValue().Set(Nan::New(join).ToLocalChecked());
1987
+ }
1988
+
1989
+ /*
1990
+ * Set line join.
1991
+ */
1992
+
1993
+ NAN_SETTER(Context2d::SetLineJoin) {
1994
+ CHECK_RECEIVER(Context2d.SetLineJoin);
1995
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1996
+ cairo_t *ctx = context->context();
1997
+ Nan::Utf8String type(Nan::To<String>(value).ToLocalChecked());
1998
+ if (0 == strcmp("round", *type)) {
1999
+ cairo_set_line_join(ctx, CAIRO_LINE_JOIN_ROUND);
2000
+ } else if (0 == strcmp("bevel", *type)) {
2001
+ cairo_set_line_join(ctx, CAIRO_LINE_JOIN_BEVEL);
2002
+ } else {
2003
+ cairo_set_line_join(ctx, CAIRO_LINE_JOIN_MITER);
2004
+ }
2005
+ }
2006
+
2007
+ /*
2008
+ * Get line cap.
2009
+ */
2010
+
2011
+ NAN_GETTER(Context2d::GetLineCap) {
2012
+ CHECK_RECEIVER(Context2d.GetLineCap);
2013
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2014
+ const char *cap;
2015
+ switch (cairo_get_line_cap(context->context())) {
2016
+ case CAIRO_LINE_CAP_ROUND: cap = "round"; break;
2017
+ case CAIRO_LINE_CAP_SQUARE: cap = "square"; break;
2018
+ default: cap = "butt";
2019
+ }
2020
+ info.GetReturnValue().Set(Nan::New(cap).ToLocalChecked());
2021
+ }
2022
+
2023
+ /*
2024
+ * Set line cap.
2025
+ */
2026
+
2027
+ NAN_SETTER(Context2d::SetLineCap) {
2028
+ CHECK_RECEIVER(Context2d.SetLineCap);
2029
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2030
+ cairo_t *ctx = context->context();
2031
+ Nan::Utf8String type(Nan::To<String>(value).ToLocalChecked());
2032
+ if (0 == strcmp("round", *type)) {
2033
+ cairo_set_line_cap(ctx, CAIRO_LINE_CAP_ROUND);
2034
+ } else if (0 == strcmp("square", *type)) {
2035
+ cairo_set_line_cap(ctx, CAIRO_LINE_CAP_SQUARE);
2036
+ } else {
2037
+ cairo_set_line_cap(ctx, CAIRO_LINE_CAP_BUTT);
2038
+ }
2039
+ }
2040
+
2041
+ /*
2042
+ * Check if the given point is within the current path.
2043
+ */
2044
+
2045
+ NAN_METHOD(Context2d::IsPointInPath) {
2046
+ if (info[0]->IsNumber() && info[1]->IsNumber()) {
2047
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2048
+ cairo_t *ctx = context->context();
2049
+ double x = Nan::To<double>(info[0]).FromMaybe(0)
2050
+ , y = Nan::To<double>(info[1]).FromMaybe(0);
2051
+ context->setFillRule(info[2]);
2052
+ info.GetReturnValue().Set(Nan::New<Boolean>(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y)));
2053
+ return;
2054
+ }
2055
+ info.GetReturnValue().Set(Nan::False());
2056
+ }
2057
+
2058
+ /*
2059
+ * Set shadow color.
2060
+ */
2061
+
2062
+ NAN_SETTER(Context2d::SetShadowColor) {
2063
+ CHECK_RECEIVER(Context2d.SetShadowColor);
2064
+ short ok;
2065
+ Nan::Utf8String str(Nan::To<String>(value).ToLocalChecked());
2066
+ uint32_t rgba = rgba_from_string(*str, &ok);
2067
+ if (ok) {
2068
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2069
+ context->state->shadow = rgba_create(rgba);
2070
+ }
2071
+ }
2072
+
2073
+ /*
2074
+ * Get shadow color.
2075
+ */
2076
+
2077
+ NAN_GETTER(Context2d::GetShadowColor) {
2078
+ CHECK_RECEIVER(Context2d.GetShadowColor);
2079
+ char buf[64];
2080
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2081
+ rgba_to_string(context->state->shadow, buf, sizeof(buf));
2082
+ info.GetReturnValue().Set(Nan::New<String>(buf).ToLocalChecked());
2083
+ }
2084
+
2085
+ /*
2086
+ * Set fill color, used internally for fillStyle=
2087
+ */
2088
+
2089
+ void Context2d::_setFillColor(Local<Value> arg) {
2090
+ short ok;
2091
+ Nan::Utf8String str(arg);
2092
+ uint32_t rgba = rgba_from_string(*str, &ok);
2093
+ if (!ok) return;
2094
+ state->fillPattern = state->fillGradient = NULL;
2095
+ state->fill = rgba_create(rgba);
2096
+ }
2097
+
2098
+ /*
2099
+ * Get fill color.
2100
+ */
2101
+
2102
+ Local<Value> Context2d::_getFillColor() {
2103
+ char buf[64];
2104
+ rgba_to_string(state->fill, buf, sizeof(buf));
2105
+ return Nan::New<String>(buf).ToLocalChecked();
2106
+ }
2107
+
2108
+ /*
2109
+ * Set stroke color, used internally for strokeStyle=
2110
+ */
2111
+
2112
+ void Context2d::_setStrokeColor(Local<Value> arg) {
2113
+ short ok;
2114
+ Nan::Utf8String str(arg);
2115
+ uint32_t rgba = rgba_from_string(*str, &ok);
2116
+ if (!ok) return;
2117
+ state->strokePattern = state->strokeGradient = NULL;
2118
+ state->stroke = rgba_create(rgba);
2119
+ }
2120
+
2121
+ /*
2122
+ * Get stroke color.
2123
+ */
2124
+
2125
+ Local<Value> Context2d::_getStrokeColor() {
2126
+ char buf[64];
2127
+ rgba_to_string(state->stroke, buf, sizeof(buf));
2128
+ return Nan::New<String>(buf).ToLocalChecked();
2129
+ }
2130
+
2131
+ NAN_METHOD(Context2d::CreatePattern) {
2132
+ Local<Value> image = info[0];
2133
+ Local<Value> repetition = info[1];
2134
+
2135
+ if (!Nan::To<bool>(repetition).FromMaybe(false))
2136
+ repetition = Nan::New("repeat").ToLocalChecked();
2137
+
2138
+ const int argc = 2;
2139
+ Local<Value> argv[argc] = { image, repetition };
2140
+
2141
+ Local<Function> ctor = Nan::GetFunction(Nan::New(Pattern::constructor)).ToLocalChecked();
2142
+ Local<Object> instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked();
2143
+
2144
+ info.GetReturnValue().Set(instance);
2145
+ }
2146
+
2147
+ NAN_METHOD(Context2d::CreateLinearGradient) {
2148
+ const int argc = 4;
2149
+ Local<Value> argv[argc] = { info[0], info[1], info[2], info[3] };
2150
+
2151
+ Local<Function> ctor = Nan::GetFunction(Nan::New(Gradient::constructor)).ToLocalChecked();
2152
+ Local<Object> instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked();
2153
+
2154
+ info.GetReturnValue().Set(instance);
2155
+ }
2156
+
2157
+ NAN_METHOD(Context2d::CreateRadialGradient) {
2158
+ const int argc = 6;
2159
+ Local<Value> argv[argc] = { info[0], info[1], info[2], info[3], info[4], info[5] };
2160
+
2161
+ Local<Function> ctor = Nan::GetFunction(Nan::New(Gradient::constructor)).ToLocalChecked();
2162
+ Local<Object> instance = Nan::NewInstance(ctor, argc, argv).ToLocalChecked();
2163
+
2164
+ info.GetReturnValue().Set(instance);
2165
+ }
2166
+
2167
+ /*
2168
+ * Bezier curve.
2169
+ */
2170
+
2171
+ NAN_METHOD(Context2d::BezierCurveTo) {
2172
+ double args[6];
2173
+ if(!checkArgs(info, args, 6))
2174
+ return;
2175
+
2176
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2177
+ cairo_curve_to(context->context()
2178
+ , args[0]
2179
+ , args[1]
2180
+ , args[2]
2181
+ , args[3]
2182
+ , args[4]
2183
+ , args[5]);
2184
+ }
2185
+
2186
+ /*
2187
+ * Quadratic curve approximation from libsvg-cairo.
2188
+ */
2189
+
2190
+ NAN_METHOD(Context2d::QuadraticCurveTo) {
2191
+ double args[4];
2192
+ if(!checkArgs(info, args, 4))
2193
+ return;
2194
+
2195
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2196
+ cairo_t *ctx = context->context();
2197
+
2198
+ double x, y
2199
+ , x1 = args[0]
2200
+ , y1 = args[1]
2201
+ , x2 = args[2]
2202
+ , y2 = args[3];
2203
+
2204
+ cairo_get_current_point(ctx, &x, &y);
2205
+
2206
+ if (0 == x && 0 == y) {
2207
+ x = x1;
2208
+ y = y1;
2209
+ }
2210
+
2211
+ cairo_curve_to(ctx
2212
+ , x + 2.0 / 3.0 * (x1 - x), y + 2.0 / 3.0 * (y1 - y)
2213
+ , x2 + 2.0 / 3.0 * (x1 - x2), y2 + 2.0 / 3.0 * (y1 - y2)
2214
+ , x2
2215
+ , y2);
2216
+ }
2217
+
2218
+ /*
2219
+ * Save state.
2220
+ */
2221
+
2222
+ NAN_METHOD(Context2d::Save) {
2223
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2224
+ context->save();
2225
+ }
2226
+
2227
+ /*
2228
+ * Restore state.
2229
+ */
2230
+
2231
+ NAN_METHOD(Context2d::Restore) {
2232
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2233
+ context->restore();
2234
+ }
2235
+
2236
+ /*
2237
+ * Creates a new subpath.
2238
+ */
2239
+
2240
+ NAN_METHOD(Context2d::BeginPath) {
2241
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2242
+ cairo_new_path(context->context());
2243
+ }
2244
+
2245
+ /*
2246
+ * Marks the subpath as closed.
2247
+ */
2248
+
2249
+ NAN_METHOD(Context2d::ClosePath) {
2250
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2251
+ cairo_close_path(context->context());
2252
+ }
2253
+
2254
+ /*
2255
+ * Rotate transformation.
2256
+ */
2257
+
2258
+ NAN_METHOD(Context2d::Rotate) {
2259
+ double args[1];
2260
+ if(!checkArgs(info, args, 1))
2261
+ return;
2262
+
2263
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2264
+ cairo_rotate(context->context(), args[0]);
2265
+ }
2266
+
2267
+ /*
2268
+ * Modify the CTM.
2269
+ */
2270
+
2271
+ NAN_METHOD(Context2d::Transform) {
2272
+ double args[6];
2273
+ if(!checkArgs(info, args, 6))
2274
+ return;
2275
+
2276
+ cairo_matrix_t matrix;
2277
+ cairo_matrix_init(&matrix
2278
+ , args[0]
2279
+ , args[1]
2280
+ , args[2]
2281
+ , args[3]
2282
+ , args[4]
2283
+ , args[5]);
2284
+
2285
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2286
+ cairo_transform(context->context(), &matrix);
2287
+ }
2288
+
2289
+ /*
2290
+ * Get the CTM
2291
+ */
2292
+
2293
+ NAN_METHOD(Context2d::GetTransform) {
2294
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2295
+ Local<Object> instance = get_current_transform(context);
2296
+
2297
+ info.GetReturnValue().Set(instance);
2298
+ }
2299
+
2300
+ /*
2301
+ * Reset the CTM, used internally by setTransform().
2302
+ */
2303
+
2304
+ NAN_METHOD(Context2d::ResetTransform) {
2305
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2306
+ cairo_identity_matrix(context->context());
2307
+ }
2308
+
2309
+ /*
2310
+ * Reset transform matrix to identity, then apply the given args.
2311
+ */
2312
+
2313
+ NAN_METHOD(Context2d::SetTransform) {
2314
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2315
+ if (info.Length() == 1) {
2316
+ Local<Object> mat = Nan::To<Object>(info[0]).ToLocalChecked();
2317
+
2318
+ #if NODE_MAJOR_VERSION >= 8
2319
+ Local<Context> ctx = Nan::GetCurrentContext();
2320
+ if (!mat->InstanceOf(ctx, _DOMMatrix.Get(Isolate::GetCurrent())).ToChecked()) {
2321
+ return Nan::ThrowTypeError("Expected DOMMatrix");
2322
+ }
2323
+ #endif
2324
+
2325
+ cairo_matrix_t matrix;
2326
+ parse_matrix_from_object(matrix, mat);
2327
+
2328
+ cairo_set_matrix(context->context(), &matrix);
2329
+ } else {
2330
+ cairo_identity_matrix(context->context());
2331
+ Context2d::Transform(info);
2332
+ }
2333
+ }
2334
+
2335
+ /*
2336
+ * Translate transformation.
2337
+ */
2338
+
2339
+ NAN_METHOD(Context2d::Translate) {
2340
+ double args[2];
2341
+ if(!checkArgs(info, args, 2))
2342
+ return;
2343
+
2344
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2345
+ cairo_translate(context->context(), args[0], args[1]);
2346
+ }
2347
+
2348
+ /*
2349
+ * Scale transformation.
2350
+ */
2351
+
2352
+ NAN_METHOD(Context2d::Scale) {
2353
+ double args[2];
2354
+ if(!checkArgs(info, args, 2))
2355
+ return;
2356
+
2357
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2358
+ cairo_scale(context->context(), args[0], args[1]);
2359
+ }
2360
+
2361
+ /*
2362
+ * Use path as clipping region.
2363
+ */
2364
+
2365
+ NAN_METHOD(Context2d::Clip) {
2366
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2367
+ context->setFillRule(info[0]);
2368
+ cairo_t *ctx = context->context();
2369
+ cairo_clip_preserve(ctx);
2370
+ }
2371
+
2372
+ /*
2373
+ * Fill the path.
2374
+ */
2375
+
2376
+ NAN_METHOD(Context2d::Fill) {
2377
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2378
+ context->setFillRule(info[0]);
2379
+ context->fill(true);
2380
+ }
2381
+
2382
+ /*
2383
+ * Stroke the path.
2384
+ */
2385
+
2386
+ NAN_METHOD(Context2d::Stroke) {
2387
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2388
+ context->stroke(true);
2389
+ }
2390
+
2391
+ /*
2392
+ * Helper for fillText/strokeText
2393
+ */
2394
+
2395
+ double
2396
+ get_text_scale(PangoLayout *layout, double maxWidth) {
2397
+
2398
+ PangoRectangle logical_rect;
2399
+ pango_layout_get_pixel_extents(layout, NULL, &logical_rect);
2400
+
2401
+ if (logical_rect.width > maxWidth) {
2402
+ return maxWidth / logical_rect.width;
2403
+ } else {
2404
+ return 1.0;
2405
+ }
2406
+ }
2407
+
2408
+ void
2409
+ paintText(const Nan::FunctionCallbackInfo<Value> &info, bool stroke) {
2410
+ int argsNum = info.Length() >= 4 ? 3 : 2;
2411
+
2412
+ if (argsNum == 3 && info[3]->IsUndefined())
2413
+ argsNum = 2;
2414
+
2415
+ double args[3];
2416
+ if(!checkArgs(info, args, argsNum, 1))
2417
+ return;
2418
+
2419
+ Nan::Utf8String str(Nan::To<String>(info[0]).ToLocalChecked());
2420
+ double x = args[0];
2421
+ double y = args[1];
2422
+ double scaled_by = 1;
2423
+
2424
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2425
+ PangoLayout *layout = context->layout();
2426
+
2427
+ pango_layout_set_text(layout, *str, -1);
2428
+ pango_cairo_update_layout(context->context(), layout);
2429
+
2430
+ if (argsNum == 3) {
2431
+ scaled_by = get_text_scale(layout, args[2]);
2432
+ cairo_save(context->context());
2433
+ cairo_scale(context->context(), scaled_by, 1);
2434
+ }
2435
+
2436
+ context->savePath();
2437
+ if (context->state->textDrawingMode == TEXT_DRAW_GLYPHS) {
2438
+ if (stroke == true) { context->stroke(); } else { context->fill(); }
2439
+ context->setTextPath(x / scaled_by, y);
2440
+ } else if (context->state->textDrawingMode == TEXT_DRAW_PATHS) {
2441
+ context->setTextPath(x / scaled_by, y);
2442
+ if (stroke == true) { context->stroke(); } else { context->fill(); }
2443
+ }
2444
+ context->restorePath();
2445
+ if (argsNum == 3) {
2446
+ cairo_restore(context->context());
2447
+ }
2448
+ }
2449
+
2450
+ /*
2451
+ * Fill text at (x, y).
2452
+ */
2453
+
2454
+ NAN_METHOD(Context2d::FillText) {
2455
+ paintText(info, false);
2456
+ }
2457
+
2458
+ /*
2459
+ * Stroke text at (x ,y).
2460
+ */
2461
+
2462
+ NAN_METHOD(Context2d::StrokeText) {
2463
+ paintText(info, true);
2464
+ }
2465
+
2466
+ /*
2467
+ * Gets the baseline adjustment in device pixels
2468
+ */
2469
+ inline double getBaselineAdjustment(PangoLayout* layout, short baseline) {
2470
+ PangoRectangle logical_rect;
2471
+ pango_layout_line_get_extents(pango_layout_get_line(layout, 0), NULL, &logical_rect);
2472
+
2473
+ double scale = 1.0 / PANGO_SCALE;
2474
+ double ascent = scale * pango_layout_get_baseline(layout);
2475
+ double descent = scale * logical_rect.height - ascent;
2476
+
2477
+ switch (baseline) {
2478
+ case TEXT_BASELINE_ALPHABETIC:
2479
+ return ascent;
2480
+ case TEXT_BASELINE_MIDDLE:
2481
+ return (ascent + descent) / 2.0;
2482
+ case TEXT_BASELINE_BOTTOM:
2483
+ return ascent + descent;
2484
+ default:
2485
+ return 0;
2486
+ }
2487
+ }
2488
+
2489
+ /*
2490
+ * Set text path for the string in the layout at (x, y).
2491
+ * This function is called by paintText and won't behave correctly
2492
+ * if is not called from there.
2493
+ * it needs pango_layout_set_text and pango_cairo_update_layout to be called before
2494
+ */
2495
+
2496
+ void
2497
+ Context2d::setTextPath(double x, double y) {
2498
+ PangoRectangle logical_rect;
2499
+
2500
+ switch (state->textAlignment) {
2501
+ case TEXT_ALIGNMENT_CENTER:
2502
+ pango_layout_get_pixel_extents(_layout, NULL, &logical_rect);
2503
+ x -= logical_rect.width / 2;
2504
+ break;
2505
+ case TEXT_ALIGNMENT_END:
2506
+ case TEXT_ALIGNMENT_RIGHT:
2507
+ pango_layout_get_pixel_extents(_layout, NULL, &logical_rect);
2508
+ x -= logical_rect.width;
2509
+ break;
2510
+ }
2511
+
2512
+ y -= getBaselineAdjustment(_layout, state->textBaseline);
2513
+
2514
+ cairo_move_to(_context, x, y);
2515
+ if (state->textDrawingMode == TEXT_DRAW_PATHS) {
2516
+ pango_cairo_layout_path(_context, _layout);
2517
+ } else if (state->textDrawingMode == TEXT_DRAW_GLYPHS) {
2518
+ pango_cairo_show_layout(_context, _layout);
2519
+ }
2520
+ }
2521
+
2522
+ /*
2523
+ * Adds a point to the current subpath.
2524
+ */
2525
+
2526
+ NAN_METHOD(Context2d::LineTo) {
2527
+ double args[2];
2528
+ if(!checkArgs(info, args, 2))
2529
+ return;
2530
+
2531
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2532
+ cairo_line_to(context->context(), args[0], args[1]);
2533
+ }
2534
+
2535
+ /*
2536
+ * Creates a new subpath at the given point.
2537
+ */
2538
+
2539
+ NAN_METHOD(Context2d::MoveTo) {
2540
+ double args[2];
2541
+ if(!checkArgs(info, args, 2))
2542
+ return;
2543
+
2544
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2545
+ cairo_move_to(context->context(), args[0], args[1]);
2546
+ }
2547
+
2548
+ /*
2549
+ * Get font.
2550
+ */
2551
+
2552
+ NAN_GETTER(Context2d::GetFont) {
2553
+ CHECK_RECEIVER(Context2d.GetFont);
2554
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2555
+
2556
+ info.GetReturnValue().Set(Nan::New(context->state->font).ToLocalChecked());
2557
+ }
2558
+
2559
+ /*
2560
+ * Set font:
2561
+ * - weight
2562
+ * - style
2563
+ * - size
2564
+ * - unit
2565
+ * - family
2566
+ */
2567
+
2568
+ NAN_SETTER(Context2d::SetFont) {
2569
+ CHECK_RECEIVER(Context2d.SetFont);
2570
+ if (!value->IsString()) return;
2571
+
2572
+ Isolate *iso = Isolate::GetCurrent();
2573
+ Local<Context> ctx = Nan::GetCurrentContext();
2574
+
2575
+ Local<String> str = Nan::To<String>(value).ToLocalChecked();
2576
+ if (!str->Length()) return;
2577
+
2578
+ const int argc = 1;
2579
+ Local<Value> argv[argc] = { value };
2580
+
2581
+ Local<Value> mparsed = Nan::Call(_parseFont.Get(iso), ctx->Global(), argc, argv).ToLocalChecked();
2582
+ // parseFont returns undefined for invalid CSS font strings
2583
+ if (mparsed->IsUndefined()) return;
2584
+ Local<Object> font = Nan::To<Object>(mparsed).ToLocalChecked();
2585
+
2586
+ Nan::Utf8String weight(Nan::Get(font, Nan::New("weight").ToLocalChecked()).ToLocalChecked());
2587
+ Nan::Utf8String style(Nan::Get(font, Nan::New("style").ToLocalChecked()).ToLocalChecked());
2588
+ double size = Nan::To<double>(Nan::Get(font, Nan::New("size").ToLocalChecked()).ToLocalChecked()).FromMaybe(0);
2589
+ Nan::Utf8String unit(Nan::Get(font, Nan::New("unit").ToLocalChecked()).ToLocalChecked());
2590
+ Nan::Utf8String family(Nan::Get(font, Nan::New("family").ToLocalChecked()).ToLocalChecked());
2591
+
2592
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2593
+
2594
+ PangoFontDescription *desc = pango_font_description_copy(context->state->fontDescription);
2595
+ pango_font_description_free(context->state->fontDescription);
2596
+
2597
+ pango_font_description_set_style(desc, Canvas::GetStyleFromCSSString(*style));
2598
+ pango_font_description_set_weight(desc, Canvas::GetWeightFromCSSString(*weight));
2599
+
2600
+ if (strlen(*family) > 0) {
2601
+ // See #1643 - Pango understands "sans" whereas CSS uses "sans-serif"
2602
+ std::string s1(*family);
2603
+ std::string s2("sans-serif");
2604
+ if (streq_casein(s1, s2)) {
2605
+ pango_font_description_set_family(desc, "sans");
2606
+ } else {
2607
+ pango_font_description_set_family(desc, *family);
2608
+ }
2609
+ }
2610
+
2611
+ PangoFontDescription *sys_desc = Canvas::ResolveFontDescription(desc);
2612
+ pango_font_description_free(desc);
2613
+
2614
+ if (size > 0) pango_font_description_set_absolute_size(sys_desc, size * PANGO_SCALE);
2615
+
2616
+ context->state->fontDescription = sys_desc;
2617
+ pango_layout_set_font_description(context->_layout, sys_desc);
2618
+
2619
+ context->state->font = *Nan::Utf8String(value);
2620
+ }
2621
+
2622
+ /*
2623
+ * Get text baseline.
2624
+ */
2625
+
2626
+ NAN_GETTER(Context2d::GetTextBaseline) {
2627
+ CHECK_RECEIVER(Context2d.GetTextBaseline);
2628
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2629
+ const char* baseline;
2630
+ switch (context->state->textBaseline) {
2631
+ default:
2632
+ case TEXT_BASELINE_ALPHABETIC: baseline = "alphabetic"; break;
2633
+ case TEXT_BASELINE_TOP: baseline = "top"; break;
2634
+ case TEXT_BASELINE_BOTTOM: baseline = "bottom"; break;
2635
+ case TEXT_BASELINE_MIDDLE: baseline = "middle"; break;
2636
+ case TEXT_BASELINE_IDEOGRAPHIC: baseline = "ideographic"; break;
2637
+ case TEXT_BASELINE_HANGING: baseline = "hanging"; break;
2638
+ }
2639
+ info.GetReturnValue().Set(Nan::New(baseline).ToLocalChecked());
2640
+ }
2641
+
2642
+ /*
2643
+ * Set text baseline.
2644
+ */
2645
+
2646
+ NAN_SETTER(Context2d::SetTextBaseline) {
2647
+ CHECK_RECEIVER(Context2d.SetTextBaseline);
2648
+ if (!value->IsString()) return;
2649
+
2650
+ Nan::Utf8String opStr(Nan::To<String>(value).ToLocalChecked());
2651
+ const std::map<std::string, text_baseline_t> modes = {
2652
+ {"alphabetic", TEXT_BASELINE_ALPHABETIC},
2653
+ {"top", TEXT_BASELINE_TOP},
2654
+ {"bottom", TEXT_BASELINE_BOTTOM},
2655
+ {"middle", TEXT_BASELINE_MIDDLE},
2656
+ {"ideographic", TEXT_BASELINE_IDEOGRAPHIC},
2657
+ {"hanging", TEXT_BASELINE_HANGING}
2658
+ };
2659
+ auto op = modes.find(*opStr);
2660
+ if (op == modes.end()) return;
2661
+
2662
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2663
+ context->state->textBaseline = op->second;
2664
+ }
2665
+
2666
+ /*
2667
+ * Get text align.
2668
+ */
2669
+
2670
+ NAN_GETTER(Context2d::GetTextAlign) {
2671
+ CHECK_RECEIVER(Context2d.GetTextAlign);
2672
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2673
+ const char* align;
2674
+ switch (context->state->textAlignment) {
2675
+ default:
2676
+ // TODO the default is supposed to be "start"
2677
+ case TEXT_ALIGNMENT_LEFT: align = "left"; break;
2678
+ case TEXT_ALIGNMENT_START: align = "start"; break;
2679
+ case TEXT_ALIGNMENT_CENTER: align = "center"; break;
2680
+ case TEXT_ALIGNMENT_RIGHT: align = "right"; break;
2681
+ case TEXT_ALIGNMENT_END: align = "end"; break;
2682
+ }
2683
+ info.GetReturnValue().Set(Nan::New(align).ToLocalChecked());
2684
+ }
2685
+
2686
+ /*
2687
+ * Set text align.
2688
+ */
2689
+
2690
+ NAN_SETTER(Context2d::SetTextAlign) {
2691
+ CHECK_RECEIVER(Context2d.SetTextAlign);
2692
+ if (!value->IsString()) return;
2693
+
2694
+ Nan::Utf8String opStr(Nan::To<String>(value).ToLocalChecked());
2695
+ const std::map<std::string, text_align_t> modes = {
2696
+ {"center", TEXT_ALIGNMENT_CENTER},
2697
+ {"left", TEXT_ALIGNMENT_LEFT},
2698
+ {"start", TEXT_ALIGNMENT_START},
2699
+ {"right", TEXT_ALIGNMENT_RIGHT},
2700
+ {"end", TEXT_ALIGNMENT_END}
2701
+ };
2702
+ auto op = modes.find(*opStr);
2703
+ if (op == modes.end()) return;
2704
+
2705
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2706
+ context->state->textAlignment = op->second;
2707
+ }
2708
+
2709
+ /*
2710
+ * Return the given text extents.
2711
+ * TODO: Support for:
2712
+ * hangingBaseline, ideographicBaseline,
2713
+ * fontBoundingBoxAscent, fontBoundingBoxDescent
2714
+ */
2715
+
2716
+ NAN_METHOD(Context2d::MeasureText) {
2717
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2718
+ cairo_t *ctx = context->context();
2719
+
2720
+ Nan::Utf8String str(Nan::To<String>(info[0]).ToLocalChecked());
2721
+ Local<Object> obj = Nan::New<Object>();
2722
+
2723
+ PangoRectangle _ink_rect, _logical_rect;
2724
+ float_rectangle ink_rect, logical_rect;
2725
+ PangoFontMetrics *metrics;
2726
+ PangoLayout *layout = context->layout();
2727
+
2728
+ pango_layout_set_text(layout, *str, -1);
2729
+ pango_cairo_update_layout(ctx, layout);
2730
+
2731
+ // Normally you could use pango_layout_get_pixel_extents and be done, or use
2732
+ // pango_extents_to_pixels, but both of those round the pixels, so we have to
2733
+ // divide by PANGO_SCALE manually
2734
+ pango_layout_get_extents(layout, &_ink_rect, &_logical_rect);
2735
+
2736
+ float inverse_pango_scale = 1. / PANGO_SCALE;
2737
+
2738
+ logical_rect.x = _logical_rect.x * inverse_pango_scale;
2739
+ logical_rect.y = _logical_rect.y * inverse_pango_scale;
2740
+ logical_rect.width = _logical_rect.width * inverse_pango_scale;
2741
+ logical_rect.height = _logical_rect.height * inverse_pango_scale;
2742
+
2743
+ ink_rect.x = _ink_rect.x * inverse_pango_scale;
2744
+ ink_rect.y = _ink_rect.y * inverse_pango_scale;
2745
+ ink_rect.width = _ink_rect.width * inverse_pango_scale;
2746
+ ink_rect.height = _ink_rect.height * inverse_pango_scale;
2747
+
2748
+ metrics = PANGO_LAYOUT_GET_METRICS(layout);
2749
+
2750
+ double x_offset;
2751
+ switch (context->state->textAlignment) {
2752
+ case TEXT_ALIGNMENT_CENTER:
2753
+ x_offset = logical_rect.width / 2.;
2754
+ break;
2755
+ case TEXT_ALIGNMENT_END:
2756
+ case TEXT_ALIGNMENT_RIGHT:
2757
+ x_offset = logical_rect.width;
2758
+ break;
2759
+ case TEXT_ALIGNMENT_START:
2760
+ case TEXT_ALIGNMENT_LEFT:
2761
+ default:
2762
+ x_offset = 0.0;
2763
+ }
2764
+
2765
+ cairo_matrix_t matrix;
2766
+ cairo_get_matrix(ctx, &matrix);
2767
+ double y_offset = getBaselineAdjustment(layout, context->state->textBaseline);
2768
+
2769
+ Nan::Set(obj,
2770
+ Nan::New<String>("width").ToLocalChecked(),
2771
+ Nan::New<Number>(logical_rect.width)).Check();
2772
+ Nan::Set(obj,
2773
+ Nan::New<String>("actualBoundingBoxLeft").ToLocalChecked(),
2774
+ Nan::New<Number>(PANGO_LBEARING(ink_rect) + x_offset)).Check();
2775
+ Nan::Set(obj,
2776
+ Nan::New<String>("actualBoundingBoxRight").ToLocalChecked(),
2777
+ Nan::New<Number>(PANGO_RBEARING(ink_rect) - x_offset)).Check();
2778
+ Nan::Set(obj,
2779
+ Nan::New<String>("actualBoundingBoxAscent").ToLocalChecked(),
2780
+ Nan::New<Number>(y_offset + PANGO_ASCENT(ink_rect))).Check();
2781
+ Nan::Set(obj,
2782
+ Nan::New<String>("actualBoundingBoxDescent").ToLocalChecked(),
2783
+ Nan::New<Number>(PANGO_DESCENT(ink_rect) - y_offset)).Check();
2784
+ Nan::Set(obj,
2785
+ Nan::New<String>("emHeightAscent").ToLocalChecked(),
2786
+ Nan::New<Number>(-(PANGO_ASCENT(logical_rect) - y_offset))).Check();
2787
+ Nan::Set(obj,
2788
+ Nan::New<String>("emHeightDescent").ToLocalChecked(),
2789
+ Nan::New<Number>(PANGO_DESCENT(logical_rect) - y_offset)).Check();
2790
+ Nan::Set(obj,
2791
+ Nan::New<String>("alphabeticBaseline").ToLocalChecked(),
2792
+ Nan::New<Number>(-(pango_font_metrics_get_ascent(metrics) * inverse_pango_scale - y_offset))).Check();
2793
+
2794
+ pango_font_metrics_unref(metrics);
2795
+
2796
+ info.GetReturnValue().Set(obj);
2797
+ }
2798
+
2799
+ /*
2800
+ * Set line dash
2801
+ * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash
2802
+ */
2803
+
2804
+ NAN_METHOD(Context2d::SetLineDash) {
2805
+ if (!info[0]->IsArray()) return;
2806
+ Local<Array> dash = Local<Array>::Cast(info[0]);
2807
+ uint32_t dashes = dash->Length() & 1 ? dash->Length() * 2 : dash->Length();
2808
+ uint32_t zero_dashes = 0;
2809
+ std::vector<double> a(dashes);
2810
+ for (uint32_t i=0; i<dashes; i++) {
2811
+ Local<Value> d = Nan::Get(dash, i % dash->Length()).ToLocalChecked();
2812
+ if (!d->IsNumber()) return;
2813
+ a[i] = Nan::To<double>(d).FromMaybe(0);
2814
+ if (a[i] == 0) zero_dashes++;
2815
+ if (a[i] < 0 || !std::isfinite(a[i])) return;
2816
+ }
2817
+
2818
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2819
+ cairo_t *ctx = context->context();
2820
+ double offset;
2821
+ cairo_get_dash(ctx, NULL, &offset);
2822
+ if (zero_dashes == dashes) {
2823
+ std::vector<double> b(0);
2824
+ cairo_set_dash(ctx, b.data(), 0, offset);
2825
+ } else {
2826
+ cairo_set_dash(ctx, a.data(), dashes, offset);
2827
+ }
2828
+ }
2829
+
2830
+ /*
2831
+ * Get line dash
2832
+ * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash
2833
+ */
2834
+ NAN_METHOD(Context2d::GetLineDash) {
2835
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2836
+ cairo_t *ctx = context->context();
2837
+ int dashes = cairo_get_dash_count(ctx);
2838
+ std::vector<double> a(dashes);
2839
+ cairo_get_dash(ctx, a.data(), NULL);
2840
+
2841
+ Local<Array> dash = Nan::New<Array>(dashes);
2842
+ for (int i=0; i<dashes; i++) {
2843
+ Nan::Set(dash, Nan::New<Number>(i), Nan::New<Number>(a[i])).Check();
2844
+ }
2845
+
2846
+ info.GetReturnValue().Set(dash);
2847
+ }
2848
+
2849
+ /*
2850
+ * Set line dash offset
2851
+ * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash
2852
+ */
2853
+ NAN_SETTER(Context2d::SetLineDashOffset) {
2854
+ CHECK_RECEIVER(Context2d.SetLineDashOffset);
2855
+ double offset = Nan::To<double>(value).FromMaybe(0);
2856
+ if (!std::isfinite(offset)) return;
2857
+
2858
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2859
+ cairo_t *ctx = context->context();
2860
+
2861
+ int dashes = cairo_get_dash_count(ctx);
2862
+ std::vector<double> a(dashes);
2863
+ cairo_get_dash(ctx, a.data(), NULL);
2864
+ cairo_set_dash(ctx, a.data(), dashes, offset);
2865
+ }
2866
+
2867
+ /*
2868
+ * Get line dash offset
2869
+ * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash
2870
+ */
2871
+ NAN_GETTER(Context2d::GetLineDashOffset) {
2872
+ CHECK_RECEIVER(Context2d.GetLineDashOffset);
2873
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2874
+ cairo_t *ctx = context->context();
2875
+ double offset;
2876
+ cairo_get_dash(ctx, NULL, &offset);
2877
+
2878
+ info.GetReturnValue().Set(Nan::New<Number>(offset));
2879
+ }
2880
+
2881
+ /*
2882
+ * Fill the rectangle defined by x, y, width and height.
2883
+ */
2884
+
2885
+ NAN_METHOD(Context2d::FillRect) {
2886
+ RECT_ARGS;
2887
+ if (0 == width || 0 == height) return;
2888
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2889
+ cairo_t *ctx = context->context();
2890
+ context->savePath();
2891
+ cairo_rectangle(ctx, x, y, width, height);
2892
+ context->fill();
2893
+ context->restorePath();
2894
+ }
2895
+
2896
+ /*
2897
+ * Stroke the rectangle defined by x, y, width and height.
2898
+ */
2899
+
2900
+ NAN_METHOD(Context2d::StrokeRect) {
2901
+ RECT_ARGS;
2902
+ if (0 == width && 0 == height) return;
2903
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2904
+ cairo_t *ctx = context->context();
2905
+ context->savePath();
2906
+ cairo_rectangle(ctx, x, y, width, height);
2907
+ context->stroke();
2908
+ context->restorePath();
2909
+ }
2910
+
2911
+ /*
2912
+ * Clears all pixels defined by x, y, width and height.
2913
+ */
2914
+
2915
+ NAN_METHOD(Context2d::ClearRect) {
2916
+ RECT_ARGS;
2917
+ if (0 == width || 0 == height) return;
2918
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2919
+ cairo_t *ctx = context->context();
2920
+ cairo_save(ctx);
2921
+ context->savePath();
2922
+ cairo_rectangle(ctx, x, y, width, height);
2923
+ cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR);
2924
+ cairo_fill(ctx);
2925
+ context->restorePath();
2926
+ cairo_restore(ctx);
2927
+ }
2928
+
2929
+ /*
2930
+ * Adds a rectangle subpath.
2931
+ */
2932
+
2933
+ NAN_METHOD(Context2d::Rect) {
2934
+ RECT_ARGS;
2935
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
2936
+ cairo_t *ctx = context->context();
2937
+ if (width == 0) {
2938
+ cairo_move_to(ctx, x, y);
2939
+ cairo_line_to(ctx, x, y + height);
2940
+ } else if (height == 0) {
2941
+ cairo_move_to(ctx, x, y);
2942
+ cairo_line_to(ctx, x + width, y);
2943
+ } else {
2944
+ cairo_rectangle(ctx, x, y, width, height);
2945
+ }
2946
+ }
2947
+
2948
+ // Draws an arc with two potentially different radii.
2949
+ inline static
2950
+ void elli_arc(cairo_t* ctx, double xc, double yc, double rx, double ry, double a1, double a2, bool clockwise=true) {
2951
+ if (rx == 0. || ry == 0.) {
2952
+ cairo_line_to(ctx, xc + rx, yc + ry);
2953
+ } else {
2954
+ cairo_save(ctx);
2955
+ cairo_translate(ctx, xc, yc);
2956
+ cairo_scale(ctx, rx, ry);
2957
+ if (clockwise)
2958
+ cairo_arc(ctx, 0., 0., 1., a1, a2);
2959
+ else
2960
+ cairo_arc_negative(ctx, 0., 0., 1., a2, a1);
2961
+ cairo_restore(ctx);
2962
+ }
2963
+ }
2964
+
2965
+ inline static
2966
+ bool getRadius(Point<double>& p, const Local<Value>& v) {
2967
+ if (v->IsObject()) { // 5.1 DOMPointInit
2968
+ auto rx = Nan::Get(v.As<Object>(), Nan::New("x").ToLocalChecked()).ToLocalChecked();
2969
+ auto ry = Nan::Get(v.As<Object>(), Nan::New("y").ToLocalChecked()).ToLocalChecked();
2970
+ if (rx->IsNumber() && ry->IsNumber()) {
2971
+ auto rxv = Nan::To<double>(rx).FromJust();
2972
+ auto ryv = Nan::To<double>(ry).FromJust();
2973
+ if (!std::isfinite(rxv) || !std::isfinite(ryv))
2974
+ return true;
2975
+ if (rxv < 0 || ryv < 0) {
2976
+ Nan::ThrowRangeError("radii must be positive.");
2977
+ return true;
2978
+ }
2979
+ p.x = rxv;
2980
+ p.y = ryv;
2981
+ return false;
2982
+ }
2983
+ } else if (v->IsNumber()) { // 5.2 unrestricted double
2984
+ auto rv = Nan::To<double>(v).FromJust();
2985
+ if (!std::isfinite(rv))
2986
+ return true;
2987
+ if (rv < 0) {
2988
+ Nan::ThrowRangeError("radii must be positive.");
2989
+ return true;
2990
+ }
2991
+ p.x = p.y = rv;
2992
+ return false;
2993
+ }
2994
+ return true;
2995
+ }
2996
+
2997
+ /**
2998
+ * https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-roundrect
2999
+ * x, y, w, h, [radius|[radii]]
3000
+ */
3001
+ NAN_METHOD(Context2d::RoundRect) {
3002
+ RECT_ARGS;
3003
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
3004
+ cairo_t *ctx = context->context();
3005
+
3006
+ // 4. Let normalizedRadii be an empty list
3007
+ Point<double> normalizedRadii[4];
3008
+ size_t nRadii = 4;
3009
+
3010
+ if (info[4]->IsUndefined()) {
3011
+ for (size_t i = 0; i < 4; i++)
3012
+ normalizedRadii[i].x = normalizedRadii[i].y = 0.;
3013
+
3014
+ } else if (info[4]->IsArray()) {
3015
+ auto radiiList = info[4].As<v8::Array>();
3016
+ nRadii = radiiList->Length();
3017
+ if (!(nRadii >= 1 && nRadii <= 4)) {
3018
+ Nan::ThrowRangeError("radii must be a list of one, two, three or four radii.");
3019
+ return;
3020
+ }
3021
+ // 5. For each radius of radii
3022
+ for (size_t i = 0; i < nRadii; i++) {
3023
+ auto r = Nan::Get(radiiList, i).ToLocalChecked();
3024
+ if (getRadius(normalizedRadii[i], r))
3025
+ return;
3026
+ }
3027
+
3028
+ } else {
3029
+ // 2. If radii is a double, then set radii to <<radii>>
3030
+ if (getRadius(normalizedRadii[0], info[4]))
3031
+ return;
3032
+ for (size_t i = 1; i < 4; i++) {
3033
+ normalizedRadii[i].x = normalizedRadii[0].x;
3034
+ normalizedRadii[i].y = normalizedRadii[0].y;
3035
+ }
3036
+ }
3037
+
3038
+ Point<double> upperLeft, upperRight, lowerRight, lowerLeft;
3039
+ if (nRadii == 4) {
3040
+ upperLeft = normalizedRadii[0];
3041
+ upperRight = normalizedRadii[1];
3042
+ lowerRight = normalizedRadii[2];
3043
+ lowerLeft = normalizedRadii[3];
3044
+ } else if (nRadii == 3) {
3045
+ upperLeft = normalizedRadii[0];
3046
+ upperRight = normalizedRadii[1];
3047
+ lowerLeft = normalizedRadii[1];
3048
+ lowerRight = normalizedRadii[2];
3049
+ } else if (nRadii == 2) {
3050
+ upperLeft = normalizedRadii[0];
3051
+ lowerRight = normalizedRadii[0];
3052
+ upperRight = normalizedRadii[1];
3053
+ lowerLeft = normalizedRadii[1];
3054
+ } else {
3055
+ upperLeft = normalizedRadii[0];
3056
+ upperRight = normalizedRadii[0];
3057
+ lowerRight = normalizedRadii[0];
3058
+ lowerLeft = normalizedRadii[0];
3059
+ }
3060
+
3061
+ bool clockwise = true;
3062
+ if (width < 0) {
3063
+ clockwise = false;
3064
+ x += width;
3065
+ width = -width;
3066
+ std::swap(upperLeft, upperRight);
3067
+ std::swap(lowerLeft, lowerRight);
3068
+ }
3069
+
3070
+ if (height < 0) {
3071
+ clockwise = !clockwise;
3072
+ y += height;
3073
+ height = -height;
3074
+ std::swap(upperLeft, lowerLeft);
3075
+ std::swap(upperRight, lowerRight);
3076
+ }
3077
+
3078
+ // 11. Corner curves must not overlap. Scale radii to prevent this.
3079
+ {
3080
+ auto top = upperLeft.x + upperRight.x;
3081
+ auto right = upperRight.y + lowerRight.y;
3082
+ auto bottom = lowerRight.x + lowerLeft.x;
3083
+ auto left = upperLeft.y + lowerLeft.y;
3084
+ auto scale = std::min({ width / top, height / right, width / bottom, height / left });
3085
+ if (scale < 1.) {
3086
+ upperLeft.x *= scale;
3087
+ upperLeft.y *= scale;
3088
+ upperRight.x *= scale;
3089
+ upperRight.x *= scale;
3090
+ lowerLeft.y *= scale;
3091
+ lowerLeft.y *= scale;
3092
+ lowerRight.y *= scale;
3093
+ lowerRight.y *= scale;
3094
+ }
3095
+ }
3096
+
3097
+ // 12. Draw
3098
+ cairo_move_to(ctx, x + upperLeft.x, y);
3099
+ if (clockwise) {
3100
+ cairo_line_to(ctx, x + width - upperRight.x, y);
3101
+ elli_arc(ctx, x + width - upperRight.x, y + upperRight.y, upperRight.x, upperRight.y, 3. * M_PI / 2., 0.);
3102
+ cairo_line_to(ctx, x + width, y + height - lowerRight.y);
3103
+ elli_arc(ctx, x + width - lowerRight.x, y + height - lowerRight.y, lowerRight.x, lowerRight.y, 0, M_PI / 2.);
3104
+ cairo_line_to(ctx, x + lowerLeft.x, y + height);
3105
+ elli_arc(ctx, x + lowerLeft.x, y + height - lowerLeft.y, lowerLeft.x, lowerLeft.y, M_PI / 2., M_PI);
3106
+ cairo_line_to(ctx, x, y + upperLeft.y);
3107
+ elli_arc(ctx, x + upperLeft.x, y + upperLeft.y, upperLeft.x, upperLeft.y, M_PI, 3. * M_PI / 2.);
3108
+ } else {
3109
+ elli_arc(ctx, x + upperLeft.x, y + upperLeft.y, upperLeft.x, upperLeft.y, M_PI, 3. * M_PI / 2., false);
3110
+ cairo_line_to(ctx, x, y + upperLeft.y);
3111
+ elli_arc(ctx, x + lowerLeft.x, y + height - lowerLeft.y, lowerLeft.x, lowerLeft.y, M_PI / 2., M_PI, false);
3112
+ cairo_line_to(ctx, x + lowerLeft.x, y + height);
3113
+ elli_arc(ctx, x + width - lowerRight.x, y + height - lowerRight.y, lowerRight.x, lowerRight.y, 0, M_PI / 2., false);
3114
+ cairo_line_to(ctx, x + width, y + height - lowerRight.y);
3115
+ elli_arc(ctx, x + width - upperRight.x, y + upperRight.y, upperRight.x, upperRight.y, 3. * M_PI / 2., 0., false);
3116
+ cairo_line_to(ctx, x + width - upperRight.x, y);
3117
+ }
3118
+ cairo_close_path(ctx);
3119
+ }
3120
+
3121
+ // Adapted from https://chromium.googlesource.com/chromium/blink/+/refs/heads/main/Source/modules/canvas2d/CanvasPathMethods.cpp
3122
+ static void canonicalizeAngle(double& startAngle, double& endAngle) {
3123
+ // Make 0 <= startAngle < 2*PI
3124
+ double newStartAngle = std::fmod(startAngle, twoPi);
3125
+ if (newStartAngle < 0) {
3126
+ newStartAngle += twoPi;
3127
+ // Check for possible catastrophic cancellation in cases where
3128
+ // newStartAngle was a tiny negative number (c.f. crbug.com/503422)
3129
+ if (newStartAngle >= twoPi)
3130
+ newStartAngle -= twoPi;
3131
+ }
3132
+ double delta = newStartAngle - startAngle;
3133
+ startAngle = newStartAngle;
3134
+ endAngle = endAngle + delta;
3135
+ }
3136
+
3137
+ // Adapted from https://chromium.googlesource.com/chromium/blink/+/refs/heads/main/Source/modules/canvas2d/CanvasPathMethods.cpp
3138
+ static double adjustEndAngle(double startAngle, double endAngle, bool counterclockwise) {
3139
+ double newEndAngle = endAngle;
3140
+ /* http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-arc
3141
+ * If the counterclockwise argument is false and endAngle-startAngle is equal to or greater than 2pi, or,
3142
+ * if the counterclockwise argument is true and startAngle-endAngle is equal to or greater than 2pi,
3143
+ * then the arc is the whole circumference of this ellipse, and the point at startAngle along this circle's circumference,
3144
+ * measured in radians clockwise from the ellipse's semi-major axis, acts as both the start point and the end point.
3145
+ */
3146
+ if (!counterclockwise && endAngle - startAngle >= twoPi)
3147
+ newEndAngle = startAngle + twoPi;
3148
+ else if (counterclockwise && startAngle - endAngle >= twoPi)
3149
+ newEndAngle = startAngle - twoPi;
3150
+ /*
3151
+ * Otherwise, the arc is the path along the circumference of this ellipse from the start point to the end point,
3152
+ * going anti-clockwise if the counterclockwise argument is true, and clockwise otherwise.
3153
+ * Since the points are on the ellipse, as opposed to being simply angles from zero,
3154
+ * the arc can never cover an angle greater than 2pi radians.
3155
+ */
3156
+ /* NOTE: When startAngle = 0, endAngle = 2Pi and counterclockwise = true, the spec does not indicate clearly.
3157
+ * We draw the entire circle, because some web sites use arc(x, y, r, 0, 2*Math.PI, true) to draw circle.
3158
+ * We preserve backward-compatibility.
3159
+ */
3160
+ else if (!counterclockwise && startAngle > endAngle)
3161
+ newEndAngle = startAngle + (twoPi - std::fmod(startAngle - endAngle, twoPi));
3162
+ else if (counterclockwise && startAngle < endAngle)
3163
+ newEndAngle = startAngle - (twoPi - std::fmod(endAngle - startAngle, twoPi));
3164
+ return newEndAngle;
3165
+ }
3166
+
3167
+ /*
3168
+ * Adds an arc at x, y with the given radii and start/end angles.
3169
+ */
3170
+
3171
+ NAN_METHOD(Context2d::Arc) {
3172
+ double args[5];
3173
+ if(!checkArgs(info, args, 5))
3174
+ return;
3175
+
3176
+ auto x = args[0];
3177
+ auto y = args[1];
3178
+ auto radius = args[2];
3179
+ auto startAngle = args[3];
3180
+ auto endAngle = args[4];
3181
+
3182
+ if (radius < 0) {
3183
+ Nan::ThrowRangeError("The radius provided is negative.");
3184
+ return;
3185
+ }
3186
+
3187
+ bool counterclockwise = Nan::To<bool>(info[5]).FromMaybe(false);
3188
+
3189
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
3190
+ cairo_t *ctx = context->context();
3191
+
3192
+ canonicalizeAngle(startAngle, endAngle);
3193
+ endAngle = adjustEndAngle(startAngle, endAngle, counterclockwise);
3194
+
3195
+ if (counterclockwise) {
3196
+ cairo_arc_negative(ctx, x, y, radius, startAngle, endAngle);
3197
+ } else {
3198
+ cairo_arc(ctx, x, y, radius, startAngle, endAngle);
3199
+ }
3200
+ }
3201
+
3202
+ /*
3203
+ * Adds an arcTo point (x0,y0) to (x1,y1) with the given radius.
3204
+ *
3205
+ * Implementation influenced by WebKit.
3206
+ */
3207
+
3208
+ NAN_METHOD(Context2d::ArcTo) {
3209
+ double args[5];
3210
+ if(!checkArgs(info, args, 5))
3211
+ return;
3212
+
3213
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
3214
+ cairo_t *ctx = context->context();
3215
+
3216
+ // Current path point
3217
+ double x, y;
3218
+ cairo_get_current_point(ctx, &x, &y);
3219
+ Point<float> p0(x, y);
3220
+
3221
+ // Point (x0,y0)
3222
+ Point<float> p1(args[0], args[1]);
3223
+
3224
+ // Point (x1,y1)
3225
+ Point<float> p2(args[2], args[3]);
3226
+
3227
+ float radius = args[4];
3228
+
3229
+ if ((p1.x == p0.x && p1.y == p0.y)
3230
+ || (p1.x == p2.x && p1.y == p2.y)
3231
+ || radius == 0.f) {
3232
+ cairo_line_to(ctx, p1.x, p1.y);
3233
+ return;
3234
+ }
3235
+
3236
+ Point<float> p1p0((p0.x - p1.x),(p0.y - p1.y));
3237
+ Point<float> p1p2((p2.x - p1.x),(p2.y - p1.y));
3238
+ float p1p0_length = sqrtf(p1p0.x * p1p0.x + p1p0.y * p1p0.y);
3239
+ float p1p2_length = sqrtf(p1p2.x * p1p2.x + p1p2.y * p1p2.y);
3240
+
3241
+ double cos_phi = (p1p0.x * p1p2.x + p1p0.y * p1p2.y) / (p1p0_length * p1p2_length);
3242
+ // all points on a line logic
3243
+ if (-1 == cos_phi) {
3244
+ cairo_line_to(ctx, p1.x, p1.y);
3245
+ return;
3246
+ }
3247
+
3248
+ if (1 == cos_phi) {
3249
+ // add infinite far away point
3250
+ unsigned int max_length = 65535;
3251
+ double factor_max = max_length / p1p0_length;
3252
+ Point<float> ep((p0.x + factor_max * p1p0.x), (p0.y + factor_max * p1p0.y));
3253
+ cairo_line_to(ctx, ep.x, ep.y);
3254
+ return;
3255
+ }
3256
+
3257
+ float tangent = radius / tan(acos(cos_phi) / 2);
3258
+ float factor_p1p0 = tangent / p1p0_length;
3259
+ Point<float> t_p1p0((p1.x + factor_p1p0 * p1p0.x), (p1.y + factor_p1p0 * p1p0.y));
3260
+
3261
+ Point<float> orth_p1p0(p1p0.y, -p1p0.x);
3262
+ float orth_p1p0_length = sqrt(orth_p1p0.x * orth_p1p0.x + orth_p1p0.y * orth_p1p0.y);
3263
+ float factor_ra = radius / orth_p1p0_length;
3264
+
3265
+ double cos_alpha = (orth_p1p0.x * p1p2.x + orth_p1p0.y * p1p2.y) / (orth_p1p0_length * p1p2_length);
3266
+ if (cos_alpha < 0.f)
3267
+ orth_p1p0 = Point<float>(-orth_p1p0.x, -orth_p1p0.y);
3268
+
3269
+ Point<float> p((t_p1p0.x + factor_ra * orth_p1p0.x), (t_p1p0.y + factor_ra * orth_p1p0.y));
3270
+
3271
+ orth_p1p0 = Point<float>(-orth_p1p0.x, -orth_p1p0.y);
3272
+ float sa = acos(orth_p1p0.x / orth_p1p0_length);
3273
+ if (orth_p1p0.y < 0.f)
3274
+ sa = 2 * M_PI - sa;
3275
+
3276
+ bool anticlockwise = false;
3277
+
3278
+ float factor_p1p2 = tangent / p1p2_length;
3279
+ Point<float> t_p1p2((p1.x + factor_p1p2 * p1p2.x), (p1.y + factor_p1p2 * p1p2.y));
3280
+ Point<float> orth_p1p2((t_p1p2.x - p.x),(t_p1p2.y - p.y));
3281
+ float orth_p1p2_length = sqrtf(orth_p1p2.x * orth_p1p2.x + orth_p1p2.y * orth_p1p2.y);
3282
+ float ea = acos(orth_p1p2.x / orth_p1p2_length);
3283
+
3284
+ if (orth_p1p2.y < 0) ea = 2 * M_PI - ea;
3285
+ if ((sa > ea) && ((sa - ea) < M_PI)) anticlockwise = true;
3286
+ if ((sa < ea) && ((ea - sa) > M_PI)) anticlockwise = true;
3287
+
3288
+ cairo_line_to(ctx, t_p1p0.x, t_p1p0.y);
3289
+
3290
+ if (anticlockwise && M_PI * 2 != radius) {
3291
+ cairo_arc_negative(ctx
3292
+ , p.x
3293
+ , p.y
3294
+ , radius
3295
+ , sa
3296
+ , ea);
3297
+ } else {
3298
+ cairo_arc(ctx
3299
+ , p.x
3300
+ , p.y
3301
+ , radius
3302
+ , sa
3303
+ , ea);
3304
+ }
3305
+ }
3306
+
3307
+ /*
3308
+ * Adds an ellipse to the path which is centered at (x, y) position with the
3309
+ * radii radiusX and radiusY starting at startAngle and ending at endAngle
3310
+ * going in the given direction by anticlockwise (defaulting to clockwise).
3311
+ */
3312
+
3313
+ NAN_METHOD(Context2d::Ellipse) {
3314
+ double args[7];
3315
+ if(!checkArgs(info, args, 7))
3316
+ return;
3317
+
3318
+ double radiusX = args[2];
3319
+ double radiusY = args[3];
3320
+
3321
+ if (radiusX == 0 || radiusY == 0) return;
3322
+
3323
+ double x = args[0];
3324
+ double y = args[1];
3325
+ double rotation = args[4];
3326
+ double startAngle = args[5];
3327
+ double endAngle = args[6];
3328
+ bool anticlockwise = Nan::To<bool>(info[7]).FromMaybe(false);
3329
+
3330
+ Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
3331
+ cairo_t *ctx = context->context();
3332
+
3333
+ // See https://www.cairographics.org/cookbook/ellipses/
3334
+ double xRatio = radiusX / radiusY;
3335
+
3336
+ cairo_matrix_t save_matrix;
3337
+ cairo_get_matrix(ctx, &save_matrix);
3338
+ cairo_translate(ctx, x, y);
3339
+ cairo_rotate(ctx, rotation);
3340
+ cairo_scale(ctx, xRatio, 1.0);
3341
+ cairo_translate(ctx, -x, -y);
3342
+ if (anticlockwise && M_PI * 2 != args[4]) {
3343
+ cairo_arc_negative(ctx,
3344
+ x,
3345
+ y,
3346
+ radiusY,
3347
+ startAngle,
3348
+ endAngle);
3349
+ } else {
3350
+ cairo_arc(ctx,
3351
+ x,
3352
+ y,
3353
+ radiusY,
3354
+ startAngle,
3355
+ endAngle);
3356
+ }
3357
+ cairo_set_matrix(ctx, &save_matrix);
3358
+ }
3359
+
3360
+ #undef CHECK_RECEIVER