diff --git a/.gitignore b/.gitignore index 6e9fcd3..1308944 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ examples/*.jpg testing out.png out.pdf +out.svg .pomo node_modules diff --git a/.travis.yml b/.travis.yml index 634d639..0e35a6a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ language: node_js node_js: - - 0.4 - - 0.6 - - 0.7 # development version of 0.8, may be unstable - - 0.8 - - 0.9 + - '0.6' + - '0.8' + - '0.10' + - '0.11' +before_install: + - sudo chown -R $USER /usr/local + - sh install diff --git a/History.md b/History.md index df23f5b..b99c17a 100644 --- a/History.md +++ b/History.md @@ -1,10 +1,49 @@ + +1.1.6 / 2014-08-01 +================== + + * export canvas.CanvasPixelArray instead of canvas.PixelArray which is undefined + * Glib version test into giflib exists test + * Giflib 5.1 + * install: use an even older version of giflib (v4.1.6) + * install: use an older version of giflib (v4.2.3) + * install: install `giflib` + * install: use more compatible sh syntax + * travis: attempt to run the ./install script before testintg + * travis: test node v0.6, v0.8, v0.10, and v0.11 + * Distinguish between 'add' and 'lighter' + +1.1.5 / 2014-06-26 +================== + + * Readme: remove Contributors section + * Readme: update copyright + * On Windows, copy required DLLs next to ".node" file (#442 @pandell) + * Duplicate "msvc_settings" for "Debug" configuration + * Remove unneeded #include + * Use float constants to prevent double->float conversion warning + * Ignore Visual C++ 2013 warnings (#441 @pandell) + * Add algorithm include to CanvasRenderingContext2d.cc for std::min (#435 @kkoopa) + * Updated NAN to 1.2.0 (#434 @kkoopa) + +1.1.4 / 2014-06-08 +================== + + * Fix compile error with Visual C++ + * Add support for the lineDash API + * Update NAN + * New V8 compatibility + * Correctly limit bounds in PutImageData to prevent segment fault + * Fix segfault when onload and onerror are not function + * Add support for Node 0.11.9 + 1.1.3 / 2014-01-08 ================== -* Add CAIRO_FORMAT_INVALID -* Readjust the amount of allocated memory -* Fix argument index for filter parameter -* Make has_lib.sh work properly on Debian 64bit + * Add CAIRO_FORMAT_INVALID + * Readjust the amount of allocated memory + * Fix argument index for filter parameter + * Make has_lib.sh work properly on Debian 64bit 1.1.2 / 2013-10-31 ================== @@ -42,337 +81,337 @@ 1.0.2 / 2013-03-22 ================== - * add Context2d#imageSmoothingEnabled= + * add Context2d#imageSmoothingEnabled= 1.0.1 / 2013-02-25 ================== - * travis: test modern node versions - * change the node-gyp build to use pkg-config + * travis: test modern node versions + * change the node-gyp build to use pkg-config 1.0.0 / 2013-01-16 ================== - * add conditional pango font support [Julian Viereck] - * add `Canvas#{png,jpeg}Stream()` alias of create* legacy methods - * add support for grayscale JPEGs - * fix: explicitly cast the after work callback function to "uv_after_work_cb" - * fix test server for express 3.x - * fix: call cairo_surface_finish in ~Canvas when pdf - * remove old 0.4.x binding support. Closes #197 + * add conditional pango font support [Julian Viereck] + * add `Canvas#{png,jpeg}Stream()` alias of create* legacy methods + * add support for grayscale JPEGs + * fix: explicitly cast the after work callback function to "uv_after_work_cb" + * fix test server for express 3.x + * fix: call cairo_surface_finish in ~Canvas when pdf + * remove old 0.4.x binding support. Closes #197 0.13.1 / 2012-08-20 ================== - * fix cases where GIF_LIB_VERSION is not defined - * fix auto-detection of optional libraries for OS X - * fix Context2d::SetFont for pango when setting normal weight/style + * fix cases where GIF_LIB_VERSION is not defined + * fix auto-detection of optional libraries for OS X + * fix Context2d::SetFont for pango when setting normal weight/style 0.13.0 / 2012-08-12 ================== - * add pango support [c-spencer] - * add pango / png / jpeg gyp auto-detection [c-spencer] - * add `.gifVersion` [tootallnate] - * add `.jpegVersion` [tootallnate] - * add moar gyp stuff [tootallnate] - * remove wscript - * fix `closure_destroy()` with cast for `AdjustAmountOfExternalAllocatedMemory()` + * add pango support [c-spencer] + * add pango / png / jpeg gyp auto-detection [c-spencer] + * add `.gifVersion` [tootallnate] + * add `.jpegVersion` [tootallnate] + * add moar gyp stuff [tootallnate] + * remove wscript + * fix `closure_destroy()` with cast for `AdjustAmountOfExternalAllocatedMemory()` 0.12.1 / 2012-06-29 ================== - * fix jpeg malloc Image issue. Closes #160 [c-spencer] - * Improve Image mode API - * Add clearData method to handle reassignment of src, and clean up mime data memory handling. - * Improve how _data_len is managed and use to adjust memory, hide more of mime API behind cairo version conditional. - * Add optional mime-data tracking to Image. - * Refactor JPEG decoding into decodeJPEGIntoSurface + * fix jpeg malloc Image issue. Closes #160 [c-spencer] + * Improve Image mode API + * Add clearData method to handle reassignment of src, and clean up mime data memory handling. + * Improve how _data_len is managed and use to adjust memory, hide more of mime API behind cairo version conditional. + * Add optional mime-data tracking to Image. + * Refactor JPEG decoding into decodeJPEGIntoSurface 0.12.0 / 2012-05-02 ================== - * Added `textDrawingMode` context property [c-spencer] - * Added additional TextMetrics properties [c-spencer] + * Added `textDrawingMode` context property [c-spencer] + * Added additional TextMetrics properties [c-spencer] 0.11.3 / 2012-04-25 ================== - * Fixed `Image` memory leak. Closes #150 - * Fixed Context2d::hasShadow() + * Fixed `Image` memory leak. Closes #150 + * Fixed Context2d::hasShadow() 0.11.2 / 2012-04-12 ================== - * Fixed: pdf memory leak, free closure and surface in ~Canvas + * Fixed: pdf memory leak, free closure and surface in ~Canvas 0.11.1 / 2012-04-10 ================== - * Changed: renamed .nextPage() to .addPage() + * Changed: renamed .nextPage() to .addPage() 0.11.0 / 2012-04-10 ================== - * Added quick PDF support - * Added `Canvas#type` getter - * Added ./examples/pdf-images.js - * Added ./examples/multiple-page-pdf.js - * Added ./examples/small-pdf.js + * Added quick PDF support + * Added `Canvas#type` getter + * Added ./examples/pdf-images.js + * Added ./examples/multiple-page-pdf.js + * Added ./examples/small-pdf.js 0.10.3 / 2012-02-27 ================== - * Fixed quadratic curve starting point for undefined path. Closes #155 + * Fixed quadratic curve starting point for undefined path. Closes #155 0.10.2 / 2012-02-06 ================== - * Fixed: Context2d setters with invalid values ignored - * Changed: replaced seek with `fstat()` + * Fixed: Context2d setters with invalid values ignored + * Changed: replaced seek with `fstat()` 0.10.1 / 2012-01-31 ================== - * Added _/opt/local/lib_ to wscript [obarthel] - * Added bounds checking to `rgba_to_string()` [obarthel] - * Fixed cleanup in JPEG Image loading [obarthel] - * Fixed missing CSS color table values [obarthel] + * Added _/opt/local/lib_ to wscript [obarthel] + * Added bounds checking to `rgba_to_string()` [obarthel] + * Fixed cleanup in JPEG Image loading [obarthel] + * Fixed missing CSS color table values [obarthel] 0.10.0 / 2012-01-18 ================== - * Added `ctx.createPattern()` [slaskis] + * Added `ctx.createPattern()` [slaskis] 0.9.0 / 2012-01-13 ================== - * Added `createJPEGStream()` [Elijah Hamovitz] + * Added `createJPEGStream()` [Elijah Hamovitz] 0.8.3 / 2012-01-04 ================== - * Added support for libjpeg62-dev or libjpeg8-dev [wwlinx] + * Added support for libjpeg62-dev or libjpeg8-dev [wwlinx] 0.8.2 / 2011-12-14 ================== - * Fixed two memory leaks in context2d [Tharit] - * Fixed `make test-server` + * Fixed two memory leaks in context2d [Tharit] + * Fixed `make test-server` 0.8.1 / 2011-10-31 ================== - * Added 0.5.x support [TooTallNate] - * Fixed `measureText().width`. Closes #126 + * Added 0.5.x support [TooTallNate] + * Fixed `measureText().width`. Closes #126 0.8.0 / 2011-10-28 ================== - * Added data uri support. Closes #49 + * Added data uri support. Closes #49 0.7.3 / 2011-09-14 ================== - * Added better lineTo() / moveTo() exception messages + * Added better lineTo() / moveTo() exception messages 0.7.2 / 2011-08-30 ================== - * Changed: prefix some private methods with _ + * Changed: prefix some private methods with _ 0.7.1 / 2011-08-25 ================== - * Added better image format detection - * Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD + * Added better image format detection + * Added libpath options to waf configuration; this was necessary to correctly detect gif and jpeg support on FreeBSD 0.7.0 / 2011-07-12 ================== - * Added GIF support [Brian McKinney] + * Added GIF support [Brian McKinney] 0.6.0 / 2011-06-04 ================== - * Added `Image#src=Buffer` support. Closes #91 - * Added `devDependencies` - * Added `source-atop` test - * Added _image-src.js_ example - * Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()` - * Fixed v8 memory hint when resizing canvas [atomizer] + * Added `Image#src=Buffer` support. Closes #91 + * Added `devDependencies` + * Added `source-atop` test + * Added _image-src.js_ example + * Removed `V8::AdjustAmountOfExternalAllocatedMemory()` call from `toBuffer()` + * Fixed v8 memory hint when resizing canvas [atomizer] 0.5.4 / 2011-04-20 ================== - * Added; special case of zero-width rectangle [atomizer] - * Fixed; do not clamp arguments to integer values [atomizer] - * Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer] - * Fixed; `restorePath()`: clear current path before appending [atomizer] + * Added; special case of zero-width rectangle [atomizer] + * Fixed; do not clamp arguments to integer values [atomizer] + * Fixed; preserve current path during `fillRect()` and `strokeRect()` [atomizer] + * Fixed; `restorePath()`: clear current path before appending [atomizer] 0.5.3 / 2011-04-11 ================== - * Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte] + * Clamp image bounds in `PixelArray::PixelArray()` [Marcello Bastea-Forte] 0.5.2 / 2011-04-09 ================== - * Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte] + * Changed; make `PNGStream` a real `Stream` [Marcello Bastea-Forte] 0.5.1 / 2011-03-16 ================== - * Fixed (kinda) `img.src=` error handling - * Fixed; move closure.h down for malloc ref. Closes #80 + * Fixed (kinda) `img.src=` error handling + * Fixed; move closure.h down for malloc ref. Closes #80 0.5.0 / 2011-03-14 ================== - * Added several more operators (color-dodge, color-burn, difference, etc) - * Performance; no longer re-allocating `closure->data` for each png write - * Fixed freeing of `Context2d` states - * Fixed text alignment / baseline [Olaf] - * Fixed HandleScopes [Olaf] - * Fixed small misc memory leaks - * Fixed `Buffer` usage for node 0.4.x + * Added several more operators (color-dodge, color-burn, difference, etc) + * Performance; no longer re-allocating `closure->data` for each png write + * Fixed freeing of `Context2d` states + * Fixed text alignment / baseline [Olaf] + * Fixed HandleScopes [Olaf] + * Fixed small misc memory leaks + * Fixed `Buffer` usage for node 0.4.x 0.4.3 / 2011-01-11 ================== - * Fixed font family dereferencing. Closes #72 - * Fixed; stripping of quotes from font-family before applying - * Fixed duplicate textAlign getter - * Removed sans-serif default of _Arial_ + * Fixed font family dereferencing. Closes #72 + * Fixed; stripping of quotes from font-family before applying + * Fixed duplicate textAlign getter + * Removed sans-serif default of _Arial_ 0.4.2 / 2010-12-28 ================== - * Fixed font size growing issue after successive calls. Closes #70 + * Fixed font size growing issue after successive calls. Closes #70 0.4.1 / 2010-12-18 ================== - * Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68 + * Fixed; toString() first argument of `{fill,stroke}Text()`. Closes #68 0.4.0 / 2010-12-12 ================== - * Added `drawImage()` with `Canvas` instance support. Closes #67 + * Added `drawImage()` with `Canvas` instance support. Closes #67 0.3.3 / 2010-11-30 ================== - * Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_ - * Fixed; pre-multiply `putImageData()` components - * Fixed; `PixelArray` data is not premultiplied + * Added `CanvasRenderingContext2d#patternQuality` accessor, accepting _fast_, _good_, and _best_ + * Fixed; pre-multiply `putImageData()` components + * Fixed; `PixelArray` data is not premultiplied 0.3.2 / 2010-11-26 ================== - * Added --profile option to config - * Fixed `eio_custom` segfault(s). Closes #46 - * Fixed two named colors. Closes #62 [thanks noonat] - * Fixed a few warnings - * Fixed; freeing data in `Image::loadJPEG()` on failure - * Fixed; include _jpeglib_ only when __HAVE_JPEG__ - * Fixed; using `strstr()` instead of `strnstr()` + * Added --profile option to config + * Fixed `eio_custom` segfault(s). Closes #46 + * Fixed two named colors. Closes #62 [thanks noonat] + * Fixed a few warnings + * Fixed; freeing data in `Image::loadJPEG()` on failure + * Fixed; include _jpeglib_ only when __HAVE_JPEG__ + * Fixed; using `strstr()` instead of `strnstr()` 0.3.1 / 2010-11-24 ================== - * Fixed; `Image` loading is sync until race-condition is resolved - * Fixed; `Image::loadJPEG()` return status based on errno + * Fixed; `Image` loading is sync until race-condition is resolved + * Fixed; `Image::loadJPEG()` return status based on errno 0.3.0 / 2010-11-24 ================== - * Added arcTo(). Closes #11 - * Added c color parser, _./examples/ray.js_ is now twice as fast - * Fixed `putImageData()` bug messing up rgba channels + * Added arcTo(). Closes #11 + * Added c color parser, _./examples/ray.js_ is now twice as fast + * Fixed `putImageData()` bug messing up rgba channels 0.2.1 / 2010-11-19 ================== - * Added image _resize_ example - * Fixed canvas resizing via `{width,height}=`. Closes #57 - * Fixed `Canvas#getContext()`, caching the CanvasRenderingContext - * Fixed async image loading (test server still messed) + * Added image _resize_ example + * Fixed canvas resizing via `{width,height}=`. Closes #57 + * Fixed `Canvas#getContext()`, caching the CanvasRenderingContext + * Fixed async image loading (test server still messed) 0.2.0 / 2010-11-18 ================== - * Added jpeg `Image` support (when libjpeg is available) - * Added _hsl_ / _hsla_ color support. [Tom Carden] + * Added jpeg `Image` support (when libjpeg is available) + * Added _hsl_ / _hsla_ color support. [Tom Carden] 0.1.0 / 2010-11-17 ================== - * Added `Image` - * Added `ImageData` - * Added `PixelArray` - * Added `CanvasRenderingContext2d#drawImage()` - * Added `CanvasRenderingContext2d#getImageData()` - * Added `CanvasRenderingContext2d#createImageData()` - * Added kraken blur benchmark example - * Added several new tests - * Fixed instanceof checks for many c++ methods - * Fixed test runner in firefox [Don Park] + * Added `Image` + * Added `ImageData` + * Added `PixelArray` + * Added `CanvasRenderingContext2d#drawImage()` + * Added `CanvasRenderingContext2d#getImageData()` + * Added `CanvasRenderingContext2d#createImageData()` + * Added kraken blur benchmark example + * Added several new tests + * Fixed instanceof checks for many c++ methods + * Fixed test runner in firefox [Don Park] 0.0.8 / 2010-11-12 ================== - * Added `CanvasRenderingContext2d#drawImage()` - * Fixed `free()` call missing stdlib - * Fixed Image#{width,height} initialization to 0 - * Fixed; load image on non-LOADING state + * Added `CanvasRenderingContext2d#drawImage()` + * Fixed `free()` call missing stdlib + * Fixed Image#{width,height} initialization to 0 + * Fixed; load image on non-LOADING state 0.0.7 / 2010-11-12 ================== - * Fixed _lighter_ for older versions of cairo + * Fixed _lighter_ for older versions of cairo 0.0.6 / 2010-11-12 ================== - * Added `Image` - * Added conditional support for cairo 1.10.0 operators + * Added `Image` + * Added conditional support for cairo 1.10.0 operators 0.0.5 / 2010-11-10 ================== - * Added custom port support to _test/server.js_ - * Added more global composite operator support - * Added `Context2d#antialias=` - * Added _voronoi_ example - * Added -D__NDEBUG__ to default build - * Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park] - * Fixed getter bug preventing patterns from being returned via `fillStyle` etc + * Added custom port support to _test/server.js_ + * Added more global composite operator support + * Added `Context2d#antialias=` + * Added _voronoi_ example + * Added -D__NDEBUG__ to default build + * Added __BUFFER_DATA__ macro for backwards compat buffer data access [Don Park] + * Fixed getter bug preventing patterns from being returned via `fillStyle` etc - * Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc() - * Fixed; free `Canvas::ToBuffer()` closure data + * Fixed; __CAIRO_STATUS_NO_MEMORY___ on failed {re,m}alloc() + * Fixed; free `Canvas::ToBuffer()` closure data 0.0.4 / 2010-11-09 ================== - * Bump to fix npm engine cache bug... + * Bump to fix npm engine cache bug... 0.0.3 / 2010-11-09 ================== - * Added async `toDataURL()` support - * Added async `toBuffer()` support - * Removed buffer utils + * Added async `toDataURL()` support + * Added async `toBuffer()` support + * Removed buffer utils 0.0.2 / 2010-11-08 ================== - * Added shadow support (faster/better gaussian blur to come) - * Added node v0.3 support [Don Park] - * Added -O3 to build - * Removed `Canvas#savePNG()` use `Canvas#createPNGStream()` + * Added shadow support (faster/better gaussian blur to come) + * Added node v0.3 support [Don Park] + * Added -O3 to build + * Removed `Canvas#savePNG()` use `Canvas#createPNGStream()` 0.0.1 / 2010-11-04 ================== - * Initial release + * Initial release diff --git a/Readme.md b/Readme.md index b91245d..28e694f 100644 --- a/Readme.md +++ b/Readme.md @@ -1,20 +1,38 @@ -[![NPM version](https://badge.fury.io/js/canvas.png)](http://badge.fury.io/js/canvas) -[![Dependency Status](https://gemnasium.com/LearnBoost/node-canvas.png)](https://gemnasium.com/LearnBoost/node-canvas) +node-canvas +=========== +### Canvas graphics API backed by Cairo +[![Build Status](https://travis-ci.org/Automattic/node-canvas.svg?branch=master)](https://travis-ci.org/Automattic/node-canvas) +[![NPM version](https://badge.fury.io/js/canvas.svg)](http://badge.fury.io/js/canvas) -# node-canvas - - Node canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org). + node-canvas is a [Cairo](http://cairographics.org/) backed Canvas implementation for [NodeJS](http://nodejs.org). ## Authors - TJ Holowaychuk ([visionmedia](http://github.com/visionmedia)) + - Nathan Rajlich ([TooTallNate](http://github.com/TooTallNate)) + - Rod Vagg ([rvagg](http://github.com/rvagg)) + - Juriy Zaytsev ([kangax](http://github.com/kangax)) ## Installation - $ npm install canvas +```bash +$ npm install canvas +``` Unless previously installed you'll _need_ __Cairo__. For system-specific installation view the [Wiki](https://github.com/LearnBoost/node-canvas/wiki/_pages). +You can quickly install Cairo and its dependencies for OS X using the one liner below: + +```bash +$ wget https://raw.githubusercontent.com/LearnBoost/node-canvas/master/install -O - | sh +``` + +or if you use MacPorts + +```bash +sudo port install pkgconfig libpng giflib freetype libpixman cairo +``` + ## Screencasts - [Introduction](http://screenr.com/CTk) @@ -23,6 +41,7 @@ Unless previously installed you'll _need_ __Cairo__. For system-specific install ```javascript var Canvas = require('canvas') + , Image = Canvas.Image , canvas = new Canvas(200,200) , ctx = canvas.getContext('2d'); @@ -238,6 +257,17 @@ ctx.fillText('Hello World 3', 50, 80); ctx.addPage(); ``` +## SVG support + + Just like PDF support, make sure to install cairo with `--enable-svg=yes`. + You also need to tell node-canvas that it is working on SVG upon its initialization: + +```js +var canvas = new Canvas(200, 500, 'svg'); +// Use the normal primitives. +fs.writeFile('out.svg', canvas.toBuffer()); +``` + ## Benchmarks Although node-canvas is extremely new, and we have not even begun optimization yet it is already quite fast. For benchmarks vs other node canvas implementations view this [gist](https://gist.github.com/664922), or update the submodules and run `$ make benchmark` yourself. @@ -258,7 +288,7 @@ If you have not previously, init git submodules: Build node-canvas: - $ node-waf configure build + $ node-gyp rebuild Unit tests: @@ -278,45 +308,13 @@ Tested with and designed for: For node 0.2.x `node-canvas` <= 0.4.3 may be used, 0.5.0 and above are designed for node 0.4.x only. -## Contributors - -``` -project : node-canvas - repo age : 1 year, 11 months - active : 120 days - commits : 963 - files : 72 - authors : - 816 Tj Holowaychuk 84.7% - 58 TJ Holowaychuk 6.0% - 23 c-spencer 2.4% - 16 Nathan Rajlich 1.7% - 12 atomizer 1.2% - 6 Elijah Hamovitz 0.6% - 5 Luigi Pinca 0.5% - 5 Robert Sköld 0.5% - 4 obarthel 0.4% - 3 Don Park 0.3% - 2 Andreas Botsikas 0.2% - 2 Gabriel Falcao 0.2% - 1 Brian McKinney 0.1% - 1 Seiya Konno 0.1% - 1 Syoyo Fujita 0.1% - 1 Marcello Bastea-Forte 0.1% - 1 Tharit 0.1% - 1 Konstantin Käfer 0.1% - 1 Tom Carden 0.1% - 1 Walt Lin 0.1% - 1 David Björklund 0.1% - 1 Brian White 0.1% - 1 Philippe Plantier 0.1% -``` - ## License (The MIT License) -Copyright (c) 2010 LearnBoost <dev@learnboost.ca> +Copyright (c) 2010 LearnBoost, and contributors <dev@learnboost.com> + +Copyright (c) 2014 Automattic, Inc and contributors <dev@automattic.com> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/binding.gyp b/binding.gyp index 1a3a9c8..b4f9162 100644 --- a/binding.gyp +++ b/binding.gyp @@ -19,6 +19,25 @@ }] ], 'targets': [ + { + 'target_name': 'canvas-postbuild', + 'dependencies': ['canvas'], + 'conditions': [ + ['OS=="win"', { + 'copies': [{ + 'destination': '<(PRODUCT_DIR)', + 'files': [ + '<(GTK_Root)/bin/libcairo-2.dll', + '<(GTK_Root)/bin/libexpat-1.dll', + '<(GTK_Root)/bin/libfontconfig-1.dll', + '<(GTK_Root)/bin/libfreetype-6.dll', + '<(GTK_Root)/bin/libpng14-14.dll', + '<(GTK_Root)/bin/zlib1.dll', + ] + }] + }] + ] + }, { 'target_name': 'canvas', 'include_dirs': ["" - , "contributors": [ - "Nathan Rajlich " - , "Rod Vagg " - , "Juriy Zaytsev " - ] - , "keywords": ["canvas", "graphic", "graphics", "pixman", "cairo", "image", "images", "pdf"] - , "homepage": "https://github.com/learnboost/node-canvas" - , "repository": "git://github.com/learnboost/node-canvas" - , "scripts": { - "test": "make test" - } - , "dependencies": { - "nan": "~0.7.0" - } - , "devDependencies": { - "express": "3.0" - , "jade": "0.28.1" - , "mocha": "*" - , "should": "*" - } - , "engines": { "node": ">= 0.6.0" } - , "main": "./lib/canvas.js" +{ + "name": "canvas", + "description": "Canvas graphics API backed by Cairo", + "version": "1.1.6", + "author": "TJ Holowaychuk ", + "contributors": [ + "Nathan Rajlich ", + "Rod Vagg ", + "Juriy Zaytsev " + ], + "keywords": [ + "canvas", + "graphic", + "graphics", + "pixman", + "cairo", + "image", + "images", + "pdf" + ], + "homepage": "https://github.com/learnboost/node-canvas", + "repository": "git://github.com/learnboost/node-canvas", + "scripts": { + "test": "make test" + }, + "dependencies": { + "nan": "~1.2.0" + }, + "devDependencies": { + "express": "3.0", + "jade": "0.28.1", + "mocha": "*", + "should": "*" + }, + "engines": { + "node": ">= 0.6.0" + }, + "main": "./lib/canvas.js" } diff --git a/src/Canvas.cc b/src/Canvas.cc index 306904f..01d3363 100644 --- a/src/Canvas.cc +++ b/src/Canvas.cc @@ -13,6 +13,7 @@ #include #include #include +#include #include "closure.h" #ifdef HAVE_JPEG @@ -30,10 +31,10 @@ Canvas::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(Canvas::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(Canvas::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("Canvas")); + ctor->SetClassName(NanNew("Canvas")); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -42,19 +43,19 @@ Canvas::Initialize(Handle target) { #ifdef HAVE_JPEG NODE_SET_PROTOTYPE_METHOD(ctor, "streamJPEGSync", StreamJPEGSync); #endif - proto->SetAccessor(NanSymbol("type"), GetType); - proto->SetAccessor(NanSymbol("width"), GetWidth, SetWidth); - proto->SetAccessor(NanSymbol("height"), GetHeight, SetHeight); - - proto->Set("PNG_NO_FILTERS", Uint32::New(PNG_NO_FILTERS)); - proto->Set("PNG_FILTER_NONE", Uint32::New(PNG_FILTER_NONE)); - proto->Set("PNG_FILTER_SUB", Uint32::New(PNG_FILTER_SUB)); - proto->Set("PNG_FILTER_UP", Uint32::New(PNG_FILTER_UP)); - proto->Set("PNG_FILTER_AVG", Uint32::New(PNG_FILTER_AVG)); - proto->Set("PNG_FILTER_PAETH", Uint32::New(PNG_FILTER_PAETH)); - proto->Set("PNG_ALL_FILTERS", Uint32::New(PNG_ALL_FILTERS)); - - target->Set(NanSymbol("Canvas"), ctor->GetFunction()); + proto->SetAccessor(NanNew("type"), GetType); + proto->SetAccessor(NanNew("width"), GetWidth, SetWidth); + proto->SetAccessor(NanNew("height"), GetHeight, SetHeight); + + NanSetTemplate(proto, "PNG_NO_FILTERS", NanNew(PNG_NO_FILTERS)); + NanSetTemplate(proto, "PNG_FILTER_NONE", NanNew(PNG_FILTER_NONE)); + NanSetTemplate(proto, "PNG_FILTER_SUB", NanNew(PNG_FILTER_SUB)); + NanSetTemplate(proto, "PNG_FILTER_UP", NanNew(PNG_FILTER_UP)); + NanSetTemplate(proto, "PNG_FILTER_AVG", NanNew(PNG_FILTER_AVG)); + NanSetTemplate(proto, "PNG_FILTER_PAETH", NanNew(PNG_FILTER_PAETH)); + NanSetTemplate(proto, "PNG_ALL_FILTERS", NanNew(PNG_ALL_FILTERS)); + + target->Set(NanNew("Canvas"), ctor->GetFunction()); } /* @@ -67,9 +68,11 @@ NAN_METHOD(Canvas::New) { canvas_type_t type = CANVAS_TYPE_IMAGE; if (args[0]->IsNumber()) width = args[0]->Uint32Value(); if (args[1]->IsNumber()) height = args[1]->Uint32Value(); - if (args[2]->IsString()) type = !strcmp("pdf", *String::AsciiValue(args[2])) + if (args[2]->IsString()) type = !strcmp("pdf", *String::Utf8Value(args[2])) ? CANVAS_TYPE_PDF - : CANVAS_TYPE_IMAGE; + : !strcmp("svg", *String::Utf8Value(args[2])) + ? CANVAS_TYPE_SVG + : CANVAS_TYPE_IMAGE; Canvas *canvas = new Canvas(width, height, type); canvas->Wrap(args.This()); NanReturnValue(args.This()); @@ -82,7 +85,7 @@ NAN_METHOD(Canvas::New) { NAN_GETTER(Canvas::GetType) { NanScope(); Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(String::New(canvas->isPDF() ? "pdf" : "image")); + NanReturnValue(NanNew(canvas->isPDF() ? "pdf" : canvas->isSVG() ? "svg" : "image")); } /* @@ -92,7 +95,7 @@ NAN_GETTER(Canvas::GetType) { NAN_GETTER(Canvas::GetWidth) { NanScope(); Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(canvas->width)); + NanReturnValue(NanNew(canvas->width)); } /* @@ -115,7 +118,7 @@ NAN_SETTER(Canvas::SetWidth) { NAN_GETTER(Canvas::GetHeight) { NanScope(); Canvas *canvas = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(canvas->height)); + NanReturnValue(NanNew(canvas->height)); } /* @@ -211,7 +214,7 @@ Canvas::EIO_AfterToBuffer(eio_req *req) { } else { Local buf = NanNewBufferHandle((char*)closure->data, closure->len); memcpy(Buffer::Data(buf), closure->data, closure->len); - Local argv[2] = { NanNewLocal(Null()), buf }; + Local argv[2] = { NanNew(NanNull()), buf }; closure->pfn->Call(2, argv); } @@ -238,7 +241,7 @@ NAN_METHOD(Canvas::ToBuffer) { Canvas *canvas = ObjectWrap::Unwrap(args.This()); // TODO: async / move this out - if (canvas->isPDF()) { + if (canvas->isPDF() || canvas->isSVG()) { cairo_surface_finish(canvas->surface()); closure_t *closure = (closure_t *) canvas->closure(); @@ -246,13 +249,13 @@ NAN_METHOD(Canvas::ToBuffer) { NanReturnValue(buf); } - if (args.Length() > 1 && !(args[1]->StrictEquals(Undefined()) && args[2]->StrictEquals(Undefined()))) { - if (!args[1]->StrictEquals(Undefined())) { + if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) { + if (!args[1]->StrictEquals(NanUndefined())) { bool good = true; if (args[1]->IsNumber()) { compression_level = args[1]->Uint32Value(); } else if (args[1]->IsString()) { - if (args[1]->StrictEquals(String::New("0"))) { + if (args[1]->StrictEquals(NanNew("0"))) { compression_level = 0; } else { uint32_t tmp = args[1]->Uint32Value(); @@ -275,7 +278,7 @@ NAN_METHOD(Canvas::ToBuffer) { } } - if (!args[2]->StrictEquals(Undefined())) { + if (!args[2]->StrictEquals(NanUndefined())) { if (args[2]->IsUint32()) { filter = args[2]->Uint32Value(); } else { @@ -348,10 +351,10 @@ streamPNG(void *c, const uint8_t *data, unsigned len) { closure_t *closure = (closure_t *) c; Local buf = NanNewBufferHandle((char *)data, len); Local argv[3] = { - NanNewLocal(Null()) + NanNew(NanNull()) , buf - , Integer::New(len) }; - MakeCallback(Context::GetCurrent()->Global(), closure->fn, 3, argv); + , NanNew(len) }; + NanMakeCallback(NanGetCurrentContext()->Global(), closure->fn, 3, argv); return CAIRO_STATUS_SUCCESS; } @@ -367,13 +370,13 @@ NAN_METHOD(Canvas::StreamPNGSync) { if (!args[0]->IsFunction()) return NanThrowTypeError("callback function required"); - if (args.Length() > 1 && !(args[1]->StrictEquals(Undefined()) && args[2]->StrictEquals(Undefined()))) { - if (!args[1]->StrictEquals(Undefined())) { + if (args.Length() > 1 && !(args[1]->StrictEquals(NanUndefined()) && args[2]->StrictEquals(NanUndefined()))) { + if (!args[1]->StrictEquals(NanUndefined())) { bool good = true; if (args[1]->IsNumber()) { compression_level = args[1]->Uint32Value(); } else if (args[1]->IsString()) { - if (args[1]->StrictEquals(String::New("0"))) { + if (args[1]->StrictEquals(NanNew("0"))) { compression_level = 0; } else { uint32_t tmp = args[1]->Uint32Value(); @@ -396,7 +399,7 @@ NAN_METHOD(Canvas::StreamPNGSync) { } } - if (!args[2]->StrictEquals(Undefined())) { + if (!args[2]->StrictEquals(NanUndefined())) { if (args[2]->IsUint32()) { filter = args[1]->Uint32Value(); } else { @@ -420,13 +423,13 @@ NAN_METHOD(Canvas::StreamPNGSync) { NanReturnValue(try_catch.ReThrow()); } else if (status) { Local argv[1] = { Canvas::Error(status) }; - MakeCallback(Context::GetCurrent()->Global(), closure.fn, 1, argv); + NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv); } else { Local argv[3] = { - NanNewLocal(Null()) - , NanNewLocal(Null()) - , Integer::New(0) }; - MakeCallback(Context::GetCurrent()->Global(), closure.fn, 3, argv); + NanNew(NanNull()) + , NanNew(NanNull()) + , NanNew(0) }; + NanMakeCallback(NanGetCurrentContext()->Global(), closure.fn, 1, argv); } NanReturnUndefined(); } @@ -480,10 +483,16 @@ Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() { cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); assert(status == CAIRO_STATUS_SUCCESS); _surface = cairo_pdf_surface_create_for_stream(toBuffer, _closure, w, h); + } else if (CANVAS_TYPE_SVG == t) { + _closure = malloc(sizeof(closure_t)); + assert(_closure); + cairo_status_t status = closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + assert(status == CAIRO_STATUS_SUCCESS); + _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, w, h); } else { _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); assert(_surface); - V8::AdjustAmountOfExternalAllocatedMemory(4 * w * h); + NanAdjustExternalMemory(4 * w * h); } } @@ -494,6 +503,7 @@ Canvas::Canvas(int w, int h, canvas_type_t t): ObjectWrap() { Canvas::~Canvas() { switch (type) { case CANVAS_TYPE_PDF: + case CANVAS_TYPE_SVG: cairo_surface_finish(_surface); closure_destroy((closure_t *) _closure); free(_closure); @@ -501,7 +511,7 @@ Canvas::~Canvas() { break; case CANVAS_TYPE_IMAGE: cairo_surface_destroy(_surface); - V8::AdjustAmountOfExternalAllocatedMemory(-4 * width * height); + NanAdjustExternalMemory(-4 * width * height); break; } } @@ -512,20 +522,39 @@ Canvas::~Canvas() { void Canvas::resurface(Handle canvas) { + NanScope(); + Handle context; switch (type) { case CANVAS_TYPE_PDF: cairo_pdf_surface_set_size(_surface, width, height); break; + case CANVAS_TYPE_SVG: + // Re-surface + cairo_surface_finish(_surface); + closure_destroy((closure_t *) _closure); + cairo_surface_destroy(_surface); + closure_init((closure_t *) _closure, this, 0, PNG_NO_FILTERS); + _surface = cairo_svg_surface_create_for_stream(toBuffer, _closure, width, height); + + // Reset context + context = canvas->Get(NanNew("context")); + if (!context->IsUndefined()) { + Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); + cairo_t *prev = context2d->context(); + context2d->setContext(cairo_create(surface())); + cairo_destroy(prev); + } + break; case CANVAS_TYPE_IMAGE: // Re-surface int old_width = cairo_image_surface_get_width(_surface); int old_height = cairo_image_surface_get_height(_surface); cairo_surface_destroy(_surface); _surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height); - V8::AdjustAmountOfExternalAllocatedMemory(4 * (width * height - old_width * old_height)); + NanAdjustExternalMemory(4 * (width * height - old_width * old_height)); // Reset context - Handle context = canvas->Get(String::New("context")); + context = canvas->Get(NanNew("context")); if (!context->IsUndefined()) { Context2d *context2d = ObjectWrap::Unwrap(context->ToObject()); cairo_t *prev = context2d->context(); @@ -542,5 +571,5 @@ Canvas::resurface(Handle canvas) { Local Canvas::Error(cairo_status_t status) { - return Exception::Error(String::New(cairo_status_to_string(status))); + return Exception::Error(NanNew(cairo_status_to_string(status))); } diff --git a/src/Canvas.h b/src/Canvas.h index 912d2e2..90ef1e5 100644 --- a/src/Canvas.h +++ b/src/Canvas.h @@ -19,7 +19,7 @@ #include #endif -#include "nan.h" +#include using namespace v8; using namespace node; @@ -39,7 +39,8 @@ using namespace node; typedef enum { CANVAS_TYPE_IMAGE, - CANVAS_TYPE_PDF + CANVAS_TYPE_PDF, + CANVAS_TYPE_SVG } canvas_type_t; /* @@ -78,6 +79,7 @@ class Canvas: public node::ObjectWrap { #endif inline bool isPDF(){ return CANVAS_TYPE_PDF == type; } + inline bool isSVG(){ return CANVAS_TYPE_SVG == type; } inline cairo_surface_t *surface(){ return _surface; } inline void *closure(){ return _closure; } inline uint8_t *data(){ return cairo_image_surface_get_data(_surface); } diff --git a/src/CanvasGradient.cc b/src/CanvasGradient.cc index 802224e..9e41c58 100644 --- a/src/CanvasGradient.cc +++ b/src/CanvasGradient.cc @@ -20,14 +20,14 @@ Gradient::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(Gradient::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(Gradient::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("CanvasGradient")); + ctor->SetClassName(NanNew("CanvasGradient")); // Prototype NODE_SET_PROTOTYPE_METHOD(ctor, "addColorStop", AddColorStop); - target->Set(NanSymbol("CanvasGradient"), ctor->GetFunction()); + target->Set(NanNew("CanvasGradient"), ctor->GetFunction()); } /* @@ -60,7 +60,7 @@ NAN_METHOD(Gradient::New) { grad->Wrap(args.This()); NanReturnValue(args.This()); } - + return NanThrowTypeError("invalid arguments"); } @@ -77,7 +77,7 @@ NAN_METHOD(Gradient::AddColorStop) { Gradient *grad = ObjectWrap::Unwrap(args.This()); short ok; - String::AsciiValue str(args[1]); + String::Utf8Value str(args[1]); uint32_t rgba = rgba_from_string(*str, &ok); if (ok) { diff --git a/src/CanvasGradient.h b/src/CanvasGradient.h index 69808e5..bcc531a 100644 --- a/src/CanvasGradient.h +++ b/src/CanvasGradient.h @@ -8,7 +8,6 @@ #ifndef __NODE_GRADIENT_H__ #define __NODE_GRADIENT_H__ -#include "nan.h" #include "Canvas.h" class Gradient: public node::ObjectWrap { diff --git a/src/CanvasPattern.cc b/src/CanvasPattern.cc index 16bb99f..38c86d7 100644 --- a/src/CanvasPattern.cc +++ b/src/CanvasPattern.cc @@ -20,16 +20,16 @@ Pattern::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(Pattern::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(Pattern::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("CanvasPattern")); + ctor->SetClassName(NanNew("CanvasPattern")); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("CanvasPattern")); + ctor->SetClassName(NanNew("CanvasPattern")); // Prototype - target->Set(NanSymbol("CanvasPattern"), ctor->GetFunction()); + target->Set(NanNew("CanvasPattern"), ctor->GetFunction()); } /* diff --git a/src/CanvasPattern.h b/src/CanvasPattern.h index 2cc3ecc..ea3faeb 100644 --- a/src/CanvasPattern.h +++ b/src/CanvasPattern.h @@ -8,7 +8,6 @@ #ifndef __NODE_PATTERN_H__ #define __NODE_PATTERN_H__ -#include "nan.h" #include "Canvas.h" class Pattern: public node::ObjectWrap { diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index fd24049..649bf86 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include "Canvas.h" #include "Point.h" #include "Image.h" @@ -20,6 +22,12 @@ #include "FontFace.h" #endif +// Windows doesn't support the C99 names for these +#ifndef isnan +#define isnan(x) _isnan(x) +#define isinf(x) (!_finite(x)) +#endif + Persistent Context2d::constructor; /* @@ -81,10 +89,10 @@ Context2d::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(Context2d::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(Context2d::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("CanvasRenderingContext2d")); + ctor->SetClassName(NanNew("CanvasRenderingContext2d")); // Prototype Local proto = ctor->PrototypeTemplate(); @@ -117,6 +125,8 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "closePath", ClosePath); NODE_SET_PROTOTYPE_METHOD(ctor, "arc", Arc); NODE_SET_PROTOTYPE_METHOD(ctor, "arcTo", ArcTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "setLineDash", SetLineDash); + NODE_SET_PROTOTYPE_METHOD(ctor, "getLineDash", GetLineDash); NODE_SET_PROTOTYPE_METHOD(ctor, "_setFont", SetFont); #ifdef HAVE_FREETYPE NODE_SET_PROTOTYPE_METHOD(ctor, "_setFontFace", SetFontFace); @@ -127,23 +137,24 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "_setStrokePattern", SetStrokePattern); NODE_SET_PROTOTYPE_METHOD(ctor, "_setTextBaseline", SetTextBaseline); NODE_SET_PROTOTYPE_METHOD(ctor, "_setTextAlignment", SetTextAlignment); - proto->SetAccessor(NanSymbol("patternQuality"), GetPatternQuality, SetPatternQuality); - proto->SetAccessor(NanSymbol("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); - proto->SetAccessor(NanSymbol("globalAlpha"), GetGlobalAlpha, SetGlobalAlpha); - proto->SetAccessor(NanSymbol("shadowColor"), GetShadowColor, SetShadowColor); - proto->SetAccessor(NanSymbol("fillColor"), GetFillColor); - proto->SetAccessor(NanSymbol("strokeColor"), GetStrokeColor); - proto->SetAccessor(NanSymbol("miterLimit"), GetMiterLimit, SetMiterLimit); - proto->SetAccessor(NanSymbol("lineWidth"), GetLineWidth, SetLineWidth); - proto->SetAccessor(NanSymbol("lineCap"), GetLineCap, SetLineCap); - proto->SetAccessor(NanSymbol("lineJoin"), GetLineJoin, SetLineJoin); - proto->SetAccessor(NanSymbol("shadowOffsetX"), GetShadowOffsetX, SetShadowOffsetX); - proto->SetAccessor(NanSymbol("shadowOffsetY"), GetShadowOffsetY, SetShadowOffsetY); - proto->SetAccessor(NanSymbol("shadowBlur"), GetShadowBlur, SetShadowBlur); - proto->SetAccessor(NanSymbol("antialias"), GetAntiAlias, SetAntiAlias); - proto->SetAccessor(NanSymbol("textDrawingMode"), GetTextDrawingMode, SetTextDrawingMode); - proto->SetAccessor(NanSymbol("filter"), GetFilter, SetFilter); - target->Set(NanSymbol("CanvasRenderingContext2d"), ctor->GetFunction()); + proto->SetAccessor(NanNew("patternQuality"), GetPatternQuality, SetPatternQuality); + proto->SetAccessor(NanNew("globalCompositeOperation"), GetGlobalCompositeOperation, SetGlobalCompositeOperation); + proto->SetAccessor(NanNew("globalAlpha"), GetGlobalAlpha, SetGlobalAlpha); + proto->SetAccessor(NanNew("shadowColor"), GetShadowColor, SetShadowColor); + proto->SetAccessor(NanNew("fillColor"), GetFillColor); + proto->SetAccessor(NanNew("strokeColor"), GetStrokeColor); + proto->SetAccessor(NanNew("miterLimit"), GetMiterLimit, SetMiterLimit); + proto->SetAccessor(NanNew("lineWidth"), GetLineWidth, SetLineWidth); + proto->SetAccessor(NanNew("lineCap"), GetLineCap, SetLineCap); + proto->SetAccessor(NanNew("lineJoin"), GetLineJoin, SetLineJoin); + proto->SetAccessor(NanNew("lineDashOffset"), GetLineDashOffset, SetLineDashOffset); + proto->SetAccessor(NanNew("shadowOffsetX"), GetShadowOffsetX, SetShadowOffsetX); + proto->SetAccessor(NanNew("shadowOffsetY"), GetShadowOffsetY, SetShadowOffsetY); + proto->SetAccessor(NanNew("shadowBlur"), GetShadowBlur, SetShadowBlur); + proto->SetAccessor(NanNew("antialias"), GetAntiAlias, SetAntiAlias); + proto->SetAccessor(NanNew("textDrawingMode"), GetTextDrawingMode, SetTextDrawingMode); + proto->SetAccessor(NanNew("filter"), GetFilter, SetFilter); + target->Set(NanNew("CanvasRenderingContext2d"), ctor->GetFunction()); } /* @@ -523,8 +534,8 @@ NAN_METHOD(Context2d::PutImageData) { switch (args.Length()) { // imageData, dx, dy case 3: - cols = arr->width(); - rows = arr->height(); + cols = std::min(arr->width(), context->canvas()->width - dx); + rows = std::min(arr->height(), context->canvas()->height - dy); break; // imageData, dx, dy, sx, sy, sw, sh case 7: @@ -536,16 +547,17 @@ NAN_METHOD(Context2d::PutImageData) { if (sy < 0) sh += sy, sy = 0; if (sx + sw > arr->width()) sw = arr->width() - sx; if (sy + sh > arr->height()) sh = arr->height() - sy; - if (sw <= 0 || sh <= 0) NanReturnUndefined(); - cols = sw; - rows = sh; dx += sx; dy += sy; + cols = std::min(sw, context->canvas()->width - dx); + rows = std::min(sh, context->canvas()->height - dy); break; default: return NanThrowError("invalid arguments"); } + if (cols <= 0 || rows <= 0) NanReturnUndefined(); + uint8_t *srcRows = src + sy * srcStride + sx * 4; for (int y = 0; y < rows; ++y) { uint32_t *row = (uint32_t *)(dst + dstStride * (y + dy)); @@ -694,7 +706,7 @@ NAN_METHOD(Context2d::DrawImage) { NAN_GETTER(Context2d::GetGlobalAlpha) { NanScope(); Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(context->state->globalAlpha)); + NanReturnValue(NanNew(context->state->globalAlpha)); } /* @@ -728,7 +740,6 @@ NAN_GETTER(Context2d::GetGlobalCompositeOperation) { case CAIRO_OPERATOR_DEST_IN: op = "destination-in"; break; case CAIRO_OPERATOR_DEST_OUT: op = "destination-out"; break; case CAIRO_OPERATOR_DEST_OVER: op = "destination-over"; break; - case CAIRO_OPERATOR_ADD: op = "lighter"; break; case CAIRO_OPERATOR_CLEAR: op = "clear"; break; case CAIRO_OPERATOR_SOURCE: op = "source"; break; case CAIRO_OPERATOR_DEST: op = "dest"; break; @@ -738,6 +749,7 @@ NAN_GETTER(Context2d::GetGlobalCompositeOperation) { // supported by resent versions of cairo #if CAIRO_VERSION_MINOR >= 10 case CAIRO_OPERATOR_LIGHTEN: op = "lighten"; break; + case CAIRO_OPERATOR_ADD: op = "add"; break; case CAIRO_OPERATOR_DARKEN: op = "darker"; break; case CAIRO_OPERATOR_MULTIPLY: op = "multiply"; break; case CAIRO_OPERATOR_SCREEN: op = "screen"; break; @@ -752,10 +764,12 @@ NAN_GETTER(Context2d::GetGlobalCompositeOperation) { case CAIRO_OPERATOR_COLOR_BURN: op = "color-burn"; break; case CAIRO_OPERATOR_DIFFERENCE: op = "difference"; break; case CAIRO_OPERATOR_EXCLUSION: op = "exclusion"; break; +#else + case CAIRO_OPERATOR_ADD: op = "lighter"; break; #endif } - NanReturnValue(NanSymbol(op)); + NanReturnValue(NanNew(op)); } /* @@ -764,7 +778,7 @@ NAN_GETTER(Context2d::GetGlobalCompositeOperation) { NAN_SETTER(Context2d::SetPatternQuality) { Context2d *context = ObjectWrap::Unwrap(args.This()); - String::AsciiValue quality(value->ToString()); + String::Utf8Value quality(value->ToString()); if (0 == strcmp("fast", *quality)) { context->state->patternQuality = CAIRO_FILTER_FAST; } else if (0 == strcmp("good", *quality)) { @@ -793,7 +807,7 @@ NAN_GETTER(Context2d::GetPatternQuality) { case CAIRO_FILTER_BILINEAR: quality = "bilinear"; break; default: quality = "good"; } - NanReturnValue(NanSymbol(quality)); + NanReturnValue(NanNew(quality)); } /* @@ -803,7 +817,7 @@ NAN_GETTER(Context2d::GetPatternQuality) { NAN_SETTER(Context2d::SetGlobalCompositeOperation) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->context(); - String::AsciiValue type(value->ToString()); + String::Utf8Value type(value->ToString()); if (0 == strcmp("xor", *type)) { cairo_set_operator(ctx, CAIRO_OPERATOR_XOR); } else if (0 == strcmp("source-atop", *type)) { @@ -833,6 +847,8 @@ NAN_SETTER(Context2d::SetGlobalCompositeOperation) { // Non-standard // supported by resent versions of cairo #if CAIRO_VERSION_MINOR >= 10 + } else if (0 == strcmp("add", *type)) { + cairo_set_operator(ctx, CAIRO_OPERATOR_ADD); } else if (0 == strcmp("lighten", *type)) { cairo_set_operator(ctx, CAIRO_OPERATOR_LIGHTEN); } else if (0 == strcmp("darker", *type)) { @@ -878,7 +894,7 @@ NAN_SETTER(Context2d::SetGlobalCompositeOperation) { NAN_GETTER(Context2d::GetShadowOffsetX) { NanScope(); Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(context->state->shadowOffsetX)); + NanReturnValue(NanNew(context->state->shadowOffsetX)); } /* @@ -897,7 +913,7 @@ NAN_SETTER(Context2d::SetShadowOffsetX) { NAN_GETTER(Context2d::GetShadowOffsetY) { NanScope(); Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(context->state->shadowOffsetY)); + NanReturnValue(NanNew(context->state->shadowOffsetY)); } /* @@ -916,7 +932,7 @@ NAN_SETTER(Context2d::SetShadowOffsetY) { NAN_GETTER(Context2d::GetShadowBlur) { NanScope(); Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(context->state->shadowBlur)); + NanReturnValue(NanNew(context->state->shadowBlur)); } /* @@ -945,7 +961,7 @@ NAN_GETTER(Context2d::GetAntiAlias) { case CAIRO_ANTIALIAS_SUBPIXEL: aa = "subpixel"; break; default: aa = "default"; } - NanReturnValue(NanSymbol(aa)); + NanReturnValue(NanNew(aa)); } /* @@ -953,7 +969,7 @@ NAN_GETTER(Context2d::GetAntiAlias) { */ NAN_SETTER(Context2d::SetAntiAlias) { - String::AsciiValue str(value->ToString()); + String::Utf8Value str(value->ToString()); Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->context(); cairo_antialias_t a; @@ -986,7 +1002,7 @@ NAN_GETTER(Context2d::GetTextDrawingMode) { } else { mode = "unknown"; } - NanReturnValue(NanSymbol(mode)); + NanReturnValue(NanNew(mode)); } /* @@ -994,7 +1010,7 @@ NAN_GETTER(Context2d::GetTextDrawingMode) { */ NAN_SETTER(Context2d::SetTextDrawingMode) { - String::AsciiValue str(value->ToString()); + String::Utf8Value str(value->ToString()); Context2d *context = ObjectWrap::Unwrap(args.This()); if (0 == strcmp("path", *str)) { context->state->textDrawingMode = TEXT_DRAW_PATHS; @@ -1018,7 +1034,7 @@ NAN_GETTER(Context2d::GetFilter) { case CAIRO_FILTER_BILINEAR: filter = "bilinear"; break; default: filter = "good"; } - NanReturnValue(NanSymbol(filter)); + NanReturnValue(NanNew(filter)); } /* @@ -1026,7 +1042,7 @@ NAN_GETTER(Context2d::GetFilter) { */ NAN_SETTER(Context2d::SetFilter) { - String::AsciiValue str(value->ToString()); + String::Utf8Value str(value->ToString()); Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_filter_t filter; if (0 == strcmp("fast", *str)) { @@ -1050,7 +1066,7 @@ NAN_SETTER(Context2d::SetFilter) { NAN_GETTER(Context2d::GetMiterLimit) { NanScope(); Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(cairo_get_miter_limit(context->context()))); + NanReturnValue(NanNew(cairo_get_miter_limit(context->context()))); } /* @@ -1072,7 +1088,7 @@ NAN_SETTER(Context2d::SetMiterLimit) { NAN_GETTER(Context2d::GetLineWidth) { NanScope(); Context2d *context = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(cairo_get_line_width(context->context()))); + NanReturnValue(NanNew(cairo_get_line_width(context->context()))); } /* @@ -1100,7 +1116,7 @@ NAN_GETTER(Context2d::GetLineJoin) { case CAIRO_LINE_JOIN_ROUND: join = "round"; break; default: join = "miter"; } - NanReturnValue(NanSymbol(join)); + NanReturnValue(NanNew(join)); } /* @@ -1110,7 +1126,7 @@ NAN_GETTER(Context2d::GetLineJoin) { NAN_SETTER(Context2d::SetLineJoin) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->context(); - String::AsciiValue type(value->ToString()); + String::Utf8Value type(value->ToString()); if (0 == strcmp("round", *type)) { cairo_set_line_join(ctx, CAIRO_LINE_JOIN_ROUND); } else if (0 == strcmp("bevel", *type)) { @@ -1133,7 +1149,7 @@ NAN_GETTER(Context2d::GetLineCap) { case CAIRO_LINE_CAP_SQUARE: cap = "square"; break; default: cap = "butt"; } - NanReturnValue(NanSymbol(cap)); + NanReturnValue(NanNew(cap)); } /* @@ -1143,7 +1159,7 @@ NAN_GETTER(Context2d::GetLineCap) { NAN_SETTER(Context2d::SetLineCap) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->context(); - String::AsciiValue type(value->ToString()); + String::Utf8Value type(value->ToString()); if (0 == strcmp("round", *type)) { cairo_set_line_cap(ctx, CAIRO_LINE_CAP_ROUND); } else if (0 == strcmp("square", *type)) { @@ -1164,9 +1180,9 @@ NAN_METHOD(Context2d::IsPointInPath) { cairo_t *ctx = context->context(); double x = args[0]->NumberValue() , y = args[1]->NumberValue(); - NanReturnValue(Boolean::New(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y))); + NanReturnValue(NanNew(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y))); } - NanReturnValue(False()); + NanReturnValue(NanFalse()); } /* @@ -1220,7 +1236,7 @@ NAN_METHOD(Context2d::SetStrokePattern) { NAN_SETTER(Context2d::SetShadowColor) { short ok; - String::AsciiValue str(value->ToString()); + String::Utf8Value str(value->ToString()); uint32_t rgba = rgba_from_string(*str, &ok); if (ok) { Context2d *context = ObjectWrap::Unwrap(args.This()); @@ -1237,7 +1253,7 @@ NAN_GETTER(Context2d::GetShadowColor) { char buf[64]; Context2d *context = ObjectWrap::Unwrap(args.This()); rgba_to_string(context->state->shadow, buf, sizeof(buf)); - NanReturnValue(String::New(buf)); + NanReturnValue(NanNew(buf)); } /* @@ -1248,7 +1264,7 @@ NAN_METHOD(Context2d::SetFillColor) { NanScope(); short ok; if (!args[0]->IsString()) NanReturnUndefined(); - String::AsciiValue str(args[0]); + String::Utf8Value str(args[0]); uint32_t rgba = rgba_from_string(*str, &ok); if (!ok) NanReturnUndefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); @@ -1266,7 +1282,7 @@ NAN_GETTER(Context2d::GetFillColor) { char buf[64]; Context2d *context = ObjectWrap::Unwrap(args.This()); rgba_to_string(context->state->fill, buf, sizeof(buf)); - NanReturnValue(String::New(buf)); + NanReturnValue(NanNew(buf)); } /* @@ -1277,7 +1293,7 @@ NAN_METHOD(Context2d::SetStrokeColor) { NanScope(); short ok; if (!args[0]->IsString()) NanReturnUndefined(); - String::AsciiValue str(args[0]); + String::Utf8Value str(args[0]); uint32_t rgba = rgba_from_string(*str, &ok); if (!ok) NanReturnUndefined(); Context2d *context = ObjectWrap::Unwrap(args.This()); @@ -1295,7 +1311,7 @@ NAN_GETTER(Context2d::GetStrokeColor) { char buf[64]; Context2d *context = ObjectWrap::Unwrap(args.This()); rgba_to_string(context->state->stroke, buf, sizeof(buf)); - NanReturnValue(String::New(buf)); + NanReturnValue(NanNew(buf)); } /* @@ -1763,11 +1779,11 @@ NAN_METHOD(Context2d::SetFont) { || !args[3]->IsString() || !args[4]->IsString()) NanReturnUndefined(); - String::AsciiValue weight(args[0]); - String::AsciiValue style(args[1]); + String::Utf8Value weight(args[0]); + String::Utf8Value style(args[1]); double size = args[2]->NumberValue(); - String::AsciiValue unit(args[3]); - String::AsciiValue family(args[4]); + String::Utf8Value unit(args[3]); + String::Utf8Value family(args[4]); Context2d *context = ObjectWrap::Unwrap(args.This()); @@ -1876,7 +1892,7 @@ NAN_METHOD(Context2d::MeasureText) { cairo_t *ctx = context->context(); String::Utf8Value str(args[0]->ToString()); - Local obj = Object::New(); + Local obj = NanNew(); #if HAVE_PANGO @@ -1917,21 +1933,21 @@ NAN_METHOD(Context2d::MeasureText) { y_offset = 0.0; } - obj->Set(String::New("width"), Number::New(logical_rect.width)); - obj->Set(String::New("actualBoundingBoxLeft"), - Number::New(x_offset - PANGO_LBEARING(logical_rect))); - obj->Set(String::New("actualBoundingBoxRight"), - Number::New(x_offset + PANGO_RBEARING(logical_rect))); - obj->Set(String::New("actualBoundingBoxAscent"), - Number::New(-(y_offset+ink_rect.y))); - obj->Set(String::New("actualBoundingBoxDescent"), - Number::New((PANGO_DESCENT(ink_rect) + y_offset))); - obj->Set(String::New("emHeightAscent"), - Number::New(PANGO_ASCENT(logical_rect) - y_offset)); - obj->Set(String::New("emHeightDescent"), - Number::New(PANGO_DESCENT(logical_rect) + y_offset)); - obj->Set(String::New("alphabeticBaseline"), - Number::New((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) + obj->Set(NanNew("width"), NanNew(logical_rect.width)); + obj->Set(NanNew("actualBoundingBoxLeft"), + NanNew(x_offset - PANGO_LBEARING(logical_rect))); + obj->Set(NanNew("actualBoundingBoxRight"), + NanNew(x_offset + PANGO_RBEARING(logical_rect))); + obj->Set(NanNew("actualBoundingBoxAscent"), + NanNew(-(y_offset+ink_rect.y))); + obj->Set(NanNew("actualBoundingBoxDescent"), + NanNew((PANGO_DESCENT(ink_rect) + y_offset))); + obj->Set(NanNew("emHeightAscent"), + NanNew(PANGO_ASCENT(logical_rect) - y_offset)); + obj->Set(NanNew("emHeightDescent"), + NanNew(PANGO_DESCENT(logical_rect) + y_offset)); + obj->Set(NanNew("alphabeticBaseline"), + NanNew((pango_font_metrics_get_ascent(metrics) / PANGO_SCALE) + y_offset)); pango_font_metrics_unref(metrics); @@ -1972,18 +1988,18 @@ NAN_METHOD(Context2d::MeasureText) { y_offset = 0.0; } - obj->Set(String::New("width"), Number::New(te.x_advance)); - obj->Set(String::New("actualBoundingBoxLeft"), - Number::New(x_offset - te.x_bearing)); - obj->Set(String::New("actualBoundingBoxRight"), - Number::New((te.x_bearing + te.width) - x_offset)); - obj->Set(String::New("actualBoundingBoxAscent"), - Number::New(-(te.y_bearing + y_offset))); - obj->Set(String::New("actualBoundingBoxDescent"), - Number::New(te.height + te.y_bearing + y_offset)); - obj->Set(String::New("emHeightAscent"), Number::New(fe.ascent - y_offset)); - obj->Set(String::New("emHeightDescent"), Number::New(fe.descent + y_offset)); - obj->Set(String::New("alphabeticBaseline"), Number::New(y_offset)); + obj->Set(NanNew("width"), NanNew(te.x_advance)); + obj->Set(NanNew("actualBoundingBoxLeft"), + NanNew(x_offset - te.x_bearing)); + obj->Set(NanNew("actualBoundingBoxRight"), + NanNew((te.x_bearing + te.width) - x_offset)); + obj->Set(NanNew("actualBoundingBoxAscent"), + NanNew(-(te.y_bearing + y_offset))); + obj->Set(NanNew("actualBoundingBoxDescent"), + NanNew(te.height + te.y_bearing + y_offset)); + obj->Set(NanNew("emHeightAscent"), NanNew(fe.ascent - y_offset)); + obj->Set(NanNew("emHeightDescent"), NanNew(fe.descent + y_offset)); + obj->Set(NanNew("alphabeticBaseline"), NanNew(y_offset)); #endif @@ -2018,6 +2034,87 @@ NAN_METHOD(Context2d::SetTextAlignment) { NanReturnUndefined(); } +/* + * Set line dash + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_METHOD(Context2d::SetLineDash) { + NanScope(); + + if (!args[0]->IsArray()) NanReturnUndefined(); + Handle dash = Handle::Cast(args[0]); + uint32_t dashes = dash->Length() & 1 ? dash->Length() * 2 : dash->Length(); + + std::vector a(dashes); + for (uint32_t i=0; i d = dash->Get(i % dash->Length()); + if (!d->IsNumber()) NanReturnUndefined(); + a[i] = d->NumberValue(); + if (a[i] < 0 || isnan(a[i]) || isinf(a[i])) NanReturnUndefined(); + } + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double offset; + cairo_get_dash(ctx, NULL, &offset); + cairo_set_dash(ctx, a.data(), dashes, offset); + NanReturnUndefined(); +} + +/* + * Get line dash + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_METHOD(Context2d::GetLineDash) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + int dashes = cairo_get_dash_count(ctx); + std::vector a(dashes); + cairo_get_dash(ctx, a.data(), NULL); + + Local dash = NanNew(dashes); + for (int i=0; iSet(NanNew(i), NanNew(a[i])); + + NanReturnValue(dash); +} + +/* + * Set line dash offset + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_SETTER(Context2d::SetLineDashOffset) { + NanScope(); + + double offset = value->NumberValue(); + if (isnan(offset) || isinf(offset)) return; + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + int dashes = cairo_get_dash_count(ctx); + std::vector a(dashes); + cairo_get_dash(ctx, a.data(), NULL); + cairo_set_dash(ctx, a.data(), dashes, offset); +} + +/* + * Get line dash offset + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_GETTER(Context2d::GetLineDashOffset) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double offset; + cairo_get_dash(ctx, NULL, &offset); + + NanReturnValue(NanNew(offset)); +} + /* * Fill the rectangle defined by x, y, width and height. */ diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 086b816..c29ae3b 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -100,6 +100,8 @@ class Context2d: public node::ObjectWrap { static NAN_METHOD(SetStrokePattern); static NAN_METHOD(SetTextBaseline); static NAN_METHOD(SetTextAlignment); + static NAN_METHOD(SetLineDash); + static NAN_METHOD(GetLineDash); static NAN_METHOD(MeasureText); static NAN_METHOD(BezierCurveTo); static NAN_METHOD(QuadraticCurveTo); @@ -121,6 +123,7 @@ class Context2d: public node::ObjectWrap { static NAN_GETTER(GetLineCap); static NAN_GETTER(GetLineJoin); static NAN_GETTER(GetLineWidth); + static NAN_GETTER(GetLineDashOffset); static NAN_GETTER(GetShadowOffsetX); static NAN_GETTER(GetShadowOffsetY); static NAN_GETTER(GetShadowBlur); @@ -135,6 +138,7 @@ class Context2d: public node::ObjectWrap { static NAN_SETTER(SetLineCap); static NAN_SETTER(SetLineJoin); static NAN_SETTER(SetLineWidth); + static NAN_SETTER(SetLineDashOffset); static NAN_SETTER(SetShadowOffsetX); static NAN_SETTER(SetShadowOffsetY); static NAN_SETTER(SetShadowBlur); diff --git a/src/FontFace.cc b/src/FontFace.cc index af867a8..0277b4a 100644 --- a/src/FontFace.cc +++ b/src/FontFace.cc @@ -6,8 +6,6 @@ #include "FontFace.h" -#include "nan.h" - Persistent FontFace::constructor; /* @@ -30,13 +28,13 @@ FontFace::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(FontFace::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(FontFace::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("FontFace")); + ctor->SetClassName(NanNew("FontFace")); // Prototype - target->Set(NanSymbol("FontFace"), ctor->GetFunction()); + target->Set(NanNew("FontFace"), ctor->GetFunction()); } /* @@ -60,7 +58,7 @@ NAN_METHOD(FontFace::New) { return NanThrowError("Wrong argument types passed to FontFace constructor"); } - String::AsciiValue filePath(args[0]); + String::Utf8Value filePath(args[0]); int faceIdx = int(args[1]->NumberValue()); FT_Face ftFace; diff --git a/src/Image.cc b/src/Image.cc index 79ada71..836f0d3 100644 --- a/src/Image.cc +++ b/src/Image.cc @@ -38,28 +38,28 @@ void Image::Initialize(Handle target) { NanScope(); - Local ctor = FunctionTemplate::New(Image::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(Image::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("Image")); + ctor->SetClassName(NanNew("Image")); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("Image")); + ctor->SetClassName(NanNew("Image")); // Prototype Local proto = ctor->PrototypeTemplate(); - proto->SetAccessor(NanSymbol("source"), GetSource, SetSource); - proto->SetAccessor(NanSymbol("complete"), GetComplete); - proto->SetAccessor(NanSymbol("width"), GetWidth); - proto->SetAccessor(NanSymbol("height"), GetHeight); - proto->SetAccessor(NanSymbol("onload"), GetOnload, SetOnload); - proto->SetAccessor(NanSymbol("onerror"), GetOnerror, SetOnerror); + proto->SetAccessor(NanNew("source"), GetSource, SetSource); + proto->SetAccessor(NanNew("complete"), GetComplete); + proto->SetAccessor(NanNew("width"), GetWidth); + proto->SetAccessor(NanNew("height"), GetHeight); + proto->SetAccessor(NanNew("onload"), GetOnload, SetOnload); + proto->SetAccessor(NanNew("onerror"), GetOnerror, SetOnerror); #if CAIRO_VERSION_MINOR >= 10 - proto->SetAccessor(NanSymbol("dataMode"), GetDataMode, SetDataMode); - ctor->Set(NanSymbol("MODE_IMAGE"), Number::New(DATA_IMAGE)); - ctor->Set(NanSymbol("MODE_MIME"), Number::New(DATA_MIME)); + proto->SetAccessor(NanNew("dataMode"), GetDataMode, SetDataMode); + ctor->Set(NanNew("MODE_IMAGE"), NanNew(DATA_IMAGE)); + ctor->Set(NanNew("MODE_MIME"), NanNew(DATA_MIME)); #endif - target->Set(NanSymbol("Image"), ctor->GetFunction()); + target->Set(NanNew("Image"), ctor->GetFunction()); } /* @@ -81,7 +81,7 @@ NAN_METHOD(Image::New) { NAN_GETTER(Image::GetComplete) { NanScope(); Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Boolean::New(Image::COMPLETE == img->state)); + NanReturnValue(NanNew(Image::COMPLETE == img->state)); } #if CAIRO_VERSION_MINOR >= 10 @@ -93,7 +93,7 @@ NAN_GETTER(Image::GetComplete) { NAN_GETTER(Image::GetDataMode) { NanScope(); Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(img->data_mode)); + NanReturnValue(NanNew(img->data_mode)); } /* @@ -117,7 +117,7 @@ NAN_SETTER(Image::SetDataMode) { NAN_GETTER(Image::GetWidth) { NanScope(); Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(img->width)); + NanReturnValue(NanNew(img->width)); } /* * Get height. @@ -126,7 +126,7 @@ NAN_GETTER(Image::GetWidth) { NAN_GETTER(Image::GetHeight) { NanScope(); Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(img->height)); + NanReturnValue(NanNew(img->height)); } /* @@ -136,7 +136,7 @@ NAN_GETTER(Image::GetHeight) { NAN_GETTER(Image::GetSource) { NanScope(); Image *img = ObjectWrap::Unwrap(args.This()); - NanReturnValue(String::New(img->filename ? img->filename : "")); + NanReturnValue(NanNew(img->filename ? img->filename : "")); } /* @@ -147,7 +147,7 @@ void Image::clearData() { if (_surface) { cairo_surface_destroy(_surface); - V8::AdjustAmountOfExternalAllocatedMemory(-_data_len); + NanAdjustExternalMemory(-_data_len); _data_len = 0; _surface = NULL; } @@ -175,7 +175,7 @@ NAN_SETTER(Image::SetSource) { // url string if (value->IsString()) { - String::AsciiValue src(value); + String::Utf8Value src(value); if (img->filename) free(img->filename); img->filename = strdup(*src); status = img->load(); @@ -359,7 +359,7 @@ Image::loaded() { width = cairo_image_surface_get_width(_surface); height = cairo_image_surface_get_height(_surface); _data_len = height * cairo_image_surface_get_stride(_surface); - V8::AdjustAmountOfExternalAllocatedMemory(_data_len); + NanAdjustExternalMemory(_data_len); if (onload != NULL) { onload->Call(0, NULL); @@ -517,7 +517,7 @@ Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) { #endif if (GIF_OK != DGifSlurp(gif)) { - DGifCloseFile(gif); + GIF_CLOSE_FILE(gif); return CAIRO_STATUS_READ_ERROR; } @@ -526,7 +526,7 @@ Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) { uint8_t *data = (uint8_t *) malloc(width * height * 4); if (!data) { - DGifCloseFile(gif); + GIF_CLOSE_FILE(gif); return CAIRO_STATUS_NO_MEMORY; } @@ -608,7 +608,7 @@ Image::loadGIFFromBuffer(uint8_t *buf, unsigned len) { } } - DGifCloseFile(gif); + GIF_CLOSE_FILE(gif); // New image surface _surface = cairo_image_surface_create_for_data( @@ -807,7 +807,7 @@ Image::decodeJPEGBufferIntoMimeSurface(uint8_t *buf, unsigned len) { void clearMimeData(void *closure) { - V8::AdjustAmountOfExternalAllocatedMemory(-((read_closure_t *)closure)->len); + NanAdjustExternalMemory(-((read_closure_t *)closure)->len); free(((read_closure_t *) closure)->buf); free(closure); } @@ -834,7 +834,7 @@ Image::assignDataAsMime(uint8_t *data, int len, const char *mime_type) { mime_closure->buf = mime_data; mime_closure->len = len; - V8::AdjustAmountOfExternalAllocatedMemory(len); + NanAdjustExternalMemory(len); return cairo_surface_set_mime_data(_surface , mime_type diff --git a/src/Image.h b/src/Image.h index 9890f90..805fb80 100644 --- a/src/Image.h +++ b/src/Image.h @@ -8,7 +8,6 @@ #ifndef __NODE_IMAGE_H__ #define __NODE_IMAGE_H__ -#include "nan.h" #include "Canvas.h" #ifdef HAVE_JPEG @@ -18,8 +17,16 @@ #ifdef HAVE_GIF #include + + #if GIFLIB_MAJOR > 5 || GIFLIB_MAJOR == 5 && GIFLIB_MINOR >= 1 + #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif, NULL) + #else + #define GIF_CLOSE_FILE(gif) DGifCloseFile(gif) + #endif #endif + + class Image: public node::ObjectWrap { public: char *filename; diff --git a/src/ImageData.cc b/src/ImageData.cc index 0694917..bbacb75 100644 --- a/src/ImageData.cc +++ b/src/ImageData.cc @@ -18,16 +18,16 @@ ImageData::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(ImageData::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(ImageData::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("ImageData")); + ctor->SetClassName(NanNew("ImageData")); // Prototype Local proto = ctor->PrototypeTemplate(); - proto->SetAccessor(NanSymbol("width"), GetWidth); - proto->SetAccessor(NanSymbol("height"), GetHeight); - target->Set(NanSymbol("ImageData"), ctor->GetFunction()); + proto->SetAccessor(NanNew("width"), GetWidth); + proto->SetAccessor(NanNew("height"), GetHeight); + target->Set(NanNew("ImageData"), ctor->GetFunction()); } /* @@ -43,7 +43,7 @@ NAN_METHOD(ImageData::New) { PixelArray *arr = ObjectWrap::Unwrap(obj); ImageData *imageData = new ImageData(arr); - args.This()->Set(NanSymbol("data"), args[0]); + args.This()->Set(NanNew("data"), args[0]); imageData->Wrap(args.This()); NanReturnValue(args.This()); } @@ -55,7 +55,7 @@ NAN_METHOD(ImageData::New) { NAN_GETTER(ImageData::GetWidth) { NanScope(); ImageData *imageData = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(imageData->pixelArray()->width())); + NanReturnValue(NanNew(imageData->pixelArray()->width())); } /* @@ -65,5 +65,5 @@ NAN_GETTER(ImageData::GetWidth) { NAN_GETTER(ImageData::GetHeight) { NanScope(); ImageData *imageData = ObjectWrap::Unwrap(args.This()); - NanReturnValue(Number::New(imageData->pixelArray()->height())); + NanReturnValue(NanNew(imageData->pixelArray()->height())); } diff --git a/src/JPEGStream.h b/src/JPEGStream.h index 3f21a9c..5b1694b 100644 --- a/src/JPEGStream.h +++ b/src/JPEGStream.h @@ -6,7 +6,6 @@ #ifndef __NODE_JPEG_STREAM_H__ #define __NODE_JPEG_STREAM_H__ -#include "nan.h" #include "Canvas.h" #include #include @@ -34,11 +33,11 @@ empty_closure_output_buffer(j_compress_ptr cinfo){ closure_destination_mgr *dest = (closure_destination_mgr *) cinfo->dest; Local buf = NanNewBufferHandle((char *)dest->buffer, dest->bufsize); Local argv[3] = { - NanNewLocal(Null()) - , NanNewLocal(buf) - , Integer::New(dest->bufsize) + NanNew(NanNull()) + , NanNew(buf) + , NanNew(dest->bufsize) }; - dest->closure->fn->Call(Context::GetCurrent()->Global(), 3, argv); + NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, argv); cinfo->dest->next_output_byte = dest->buffer; cinfo->dest->free_in_buffer = dest->bufsize; return true; @@ -53,21 +52,21 @@ term_closure_destination(j_compress_ptr cinfo){ Local buf = NanNewBufferHandle((char *)dest->buffer, remaining); Local data_argv[3] = { - NanNewLocal(Null()) - , NanNewLocal(buf) - , Integer::New(remaining) + NanNew(NanNull()) + , NanNew(buf) + , NanNew(remaining) }; - dest->closure->fn->Call(Context::GetCurrent()->Global(), 3, data_argv); + NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, data_argv); // emit "end" Local end_argv[3] = { - NanNewLocal(Null()) - , NanNewLocal(Null()) - , Integer::New(0) + NanNew(NanNull()) + , NanNew(NanNull()) + , NanNew(0) }; - dest->closure->fn->Call(Context::GetCurrent()->Global(), 3, end_argv); + NanMakeCallback(NanGetCurrentContext()->Global(), dest->closure->fn, 3, end_argv); } void diff --git a/src/PixelArray.cc b/src/PixelArray.cc index 4abc181..0a773cc 100644 --- a/src/PixelArray.cc +++ b/src/PixelArray.cc @@ -9,8 +9,6 @@ #include #include -#include "nan.h" - Persistent PixelArray::constructor; /* @@ -22,15 +20,15 @@ PixelArray::Initialize(Handle target) { NanScope(); // Constructor - Local ctor = FunctionTemplate::New(PixelArray::New); - NanAssignPersistent(FunctionTemplate, constructor, ctor); + Local ctor = NanNew(PixelArray::New); + NanAssignPersistent(constructor, ctor); ctor->InstanceTemplate()->SetInternalFieldCount(1); - ctor->SetClassName(NanSymbol("CanvasPixelArray")); + ctor->SetClassName(NanNew("CanvasPixelArray")); // Prototype Local proto = ctor->InstanceTemplate(); - proto->SetAccessor(NanSymbol("length"), GetLength); - target->Set(NanSymbol("CanvasPixelArray"), ctor->GetFunction()); + proto->SetAccessor(NanNew("length"), GetLength); + target->Set(NanNew("CanvasPixelArray"), ctor->GetFunction()); } /* @@ -82,7 +80,7 @@ NAN_METHOD(PixelArray::New) { NAN_GETTER(PixelArray::GetLength) { NanScope(); - NanReturnValue(Number::New(args.This()->GetIndexedPropertiesPixelDataLength())); + NanReturnValue(NanNew(args.This()->GetIndexedPropertiesPixelDataLength())); } /* @@ -142,7 +140,7 @@ uint8_t * PixelArray::alloc() { int len = length(); _data = (uint8_t *) calloc(1, len); - V8::AdjustAmountOfExternalAllocatedMemory(len); + NanAdjustExternalMemory(len); return _data; } @@ -151,6 +149,6 @@ PixelArray::alloc() { */ PixelArray::~PixelArray() { - V8::AdjustAmountOfExternalAllocatedMemory(-length()); + NanAdjustExternalMemory(-length()); free(_data); } diff --git a/src/closure.h b/src/closure.h index 1b3147b..3ac6632 100644 --- a/src/closure.h +++ b/src/closure.h @@ -16,7 +16,7 @@ #define PAGE_SIZE 4096 #endif -#include "nan.h" +#include /* * PNG stream closure. @@ -50,7 +50,7 @@ closure_init(closure_t *closure, Canvas *canvas, unsigned int compression_level, } /* - * Free the given closure's data, + * Free the given closure's data, * and hint V8 at the memory dealloc. */ @@ -58,7 +58,7 @@ void closure_destroy(closure_t *closure) { if (closure->len) { free(closure->data); - V8::AdjustAmountOfExternalAllocatedMemory(- (intptr_t) closure->max_len); + NanAdjustExternalMemory(-((intptr_t) closure->max_len)); } } diff --git a/src/color.cc b/src/color.cc index e5cb758..5f7478d 100644 --- a/src/color.cc +++ b/src/color.cc @@ -350,10 +350,10 @@ rgba_from_rgba_string(const char *str, short *ok) { if ('0' == *str) ++str; if ('.' == *str) { ++str; - float n = .1; + float n = .1f; while (*str >= '0' && *str <= '9') { a += (*str++ - '0') * n; - n *= .1; + n *= .1f; } } } diff --git a/src/init.cc b/src/init.cc index f7c822d..6628cee 100755 --- a/src/init.cc +++ b/src/init.cc @@ -32,7 +32,7 @@ init (Handle target) { FontFace::Initialize(target); #endif - target->Set(String::New("cairoVersion"), String::New(cairo_version_string())); + target->Set(NanNew("cairoVersion"), NanNew(cairo_version_string())); #ifdef HAVE_JPEG #ifndef JPEG_LIB_VERSION_MAJOR @@ -57,16 +57,16 @@ init (Handle target) { } else { snprintf(jpeg_version, 10, "%d", JPEG_LIB_VERSION_MAJOR); } - target->Set(String::New("jpegVersion"), String::New(jpeg_version)); + target->Set(NanNew("jpegVersion"), NanNew(jpeg_version)); #endif #ifdef HAVE_GIF #ifndef GIF_LIB_VERSION char gif_version[10]; snprintf(gif_version, 10, "%d.%d.%d", GIFLIB_MAJOR, GIFLIB_MINOR, GIFLIB_RELEASE); - target->Set(String::New("gifVersion"), String::New(gif_version)); + target->Set(NanNew("gifVersion"), NanNew(gif_version)); #else - target->Set(String::New("gifVersion"), String::New(GIF_LIB_VERSION)); + target->Set(NanNew("gifVersion"), NanNew(GIF_LIB_VERSION)); #endif #endif } diff --git a/test/canvas.test.js b/test/canvas.test.js index af43cc7..c3861db 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -76,6 +76,10 @@ module.exports = { } }, + 'test .PixelArray': function(){ + assert.equal(typeof Canvas.PixelArray, 'function'); + }, + 'test color serialization': function(){ var canvas = new Canvas(200, 200) , ctx = canvas.getContext('2d'); @@ -161,6 +165,8 @@ module.exports = { assert('image' == canvas.type); var canvas = new Canvas(10, 10, 'pdf'); assert('pdf' == canvas.type); + var canvas = new Canvas(10, 10, 'svg'); + assert('svg' == canvas.type); var canvas = new Canvas(10, 10, 'hey'); assert('image' == canvas.type); }, diff --git a/test/public/tests.js b/test/public/tests.js index 784a2f4..e09ba82 100644 --- a/test/public/tests.js +++ b/test/public/tests.js @@ -1850,4 +1850,69 @@ tests['putImageData() png data 3'] = function(ctx, done){ }; img.onerror = function(){} img.src = 'state.png'; -}; \ No newline at end of file +}; + +tests['setLineDash'] = function(ctx, done){ + ctx.setLineDash([10, 5, 25, 15]); + ctx.lineWidth = 17; + + var y=5; + var line = function(lineDash, color){ + ctx.setLineDash(lineDash); + if (color) ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += ctx.lineWidth + 4; + }; + + line([15, 30], "blue"); + line([], "black"); + line([5,10,15,20,25,30,35,40,45,50], "purple"); + line([8], "green"); + line([3, 3, -30], "red"); + line([4, Infinity, 4]); + line([10, 10, NaN]); + line((function(){ + ctx.setLineDash([8]); + var a = ctx.getLineDash(); + a[0] -= 3; + a.push(20); + return a; + })(), "orange"); +}; + +tests['lineDashOffset'] = function(ctx, done){ + ctx.setLineDash([10, 5, 25, 15]); + ctx.lineWidth = 4; + + var y=5; + var line = function(lineDashOffset, color){ + ctx.lineDashOffset = lineDashOffset; + if (color) ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += ctx.lineWidth + 4; + }; + + line(-10, "black"); + line(0); + line(10); + line(20); + line(30); + line(40, "blue"); + line(NaN) + line(50, "green"); + line(Infinity) + line(60, "orange"); + line(-Infinity) + line(70, "purple"); + line(void 0) + line(80, "black"); + line(ctx.lineDashOffset + 10); + for (var i=0; i<10; i++) + line(90 + i/5, "red"); +}