Browse Source

Add support for evenodd fill rule

v1.x
wsw 9 years ago
committed by Linus Unnebäck
parent
commit
faae57a90c
No known key found for this signature in database GPG Key ID: F23BD23774478D34
  1. 13
      examples/fill-evenodd.js
  2. 15
      src/CanvasRenderingContext2d.cc
  3. 1
      src/CanvasRenderingContext2d.h
  4. 173
      test/canvas.test.js

13
examples/fill-evenodd.js

@ -0,0 +1,13 @@
var fs = require('fs')
var path = require('path')
var Canvas = require('..')
var canvas = new Canvas(100, 100)
var ctx = canvas.getContext('2d')
ctx.fillStyle = '#f00'
ctx.rect(0, 0, 100, 50)
ctx.arc(50, 50, 50, 0, 2 * Math.PI)
ctx.fill('evenodd')
canvas.createJPEGStream().pipe(fs.createWriteStream(path.join(__dirname, '/fill-evenodd.jpg')))

15
src/CanvasRenderingContext2d.cc

@ -296,6 +296,18 @@ Context2d::restorePath() {
* Fill and apply shadow.
*/
void
Context2d::setFillRule(v8::Local<v8::Value> value) {
cairo_fill_rule_t rule = CAIRO_FILL_RULE_WINDING;
if (value->IsString()) {
String::Utf8Value str(value);
if (std::strcmp(*str, "evenodd") == 0) {
rule = CAIRO_FILL_RULE_EVEN_ODD;
}
}
cairo_set_fill_rule(_context, rule);
}
void
Context2d::fill(bool preserve) {
if (state->fillPattern) {
@ -1400,6 +1412,7 @@ NAN_METHOD(Context2d::IsPointInPath) {
cairo_t *ctx = context->context();
double x = info[0]->NumberValue()
, y = info[1]->NumberValue();
context->setFillRule(info[2]);
info.GetReturnValue().Set(Nan::New<Boolean>(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y)));
return;
}
@ -1677,6 +1690,7 @@ NAN_METHOD(Context2d::Scale) {
NAN_METHOD(Context2d::Clip) {
Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
context->setFillRule(info[0]);
cairo_t *ctx = context->context();
cairo_clip_preserve(ctx);
}
@ -1687,6 +1701,7 @@ NAN_METHOD(Context2d::Clip) {
NAN_METHOD(Context2d::Fill) {
Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
context->setFillRule(info[0]);
context->fill(true);
}

1
src/CanvasRenderingContext2d.h

@ -161,6 +161,7 @@ class Context2d: public Nan::ObjectWrap {
void restorePath();
void saveState();
void restoreState();
void inline setFillRule(v8::Local<v8::Value> value);
void fill(bool preserve = false);
void stroke(bool preserve = false);
void save();

173
test/canvas.test.js

@ -833,5 +833,176 @@ describe('Canvas', function () {
assert(chunk.length < SIZE);
});
s.on('end', done);
})
});
it('Context2d#fill()', function() {
var canvas = new Canvas(2, 2);
var ctx = canvas.getContext('2d');
// fill whole canvas with white
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, 2, 2);
var imageData, n;
// black
ctx.fillStyle = '#000';
ctx.rect(0, 0, 2, 1);
ctx.rect(1, 0, 1, 2);
ctx.fill('evenodd');
// b | w
// -----
// w | b
imageData = ctx.getImageData(0, 0, 2, 2);
// (0, 0) black
n = 0;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
// (0, 1) white
n = 1;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 0) white
n = 2;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 1) black
n = 3;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
// should not retain previous value 'evenodd'
ctx.fill();
// b | b
// -----
// w | b
imageData = ctx.getImageData(0, 0, 2, 2);
// (0, 0) black
n = 0;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
// (0, 1) black
n = 1;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
// (1, 0) white
n = 2;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 1) black
n = 3;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
});
it('Context2d#clip()', function () {
var canvas = new Canvas(2, 2);
var ctx = canvas.getContext('2d');
// fill whole canvas with white
ctx.fillStyle = '#fff';
ctx.fillRect(0, 0, 2, 2);
var imageData, n;
// black
ctx.fillStyle = '#000';
ctx.rect(0, 0, 2, 1);
ctx.rect(1, 0, 1, 2);
ctx.clip('evenodd');
ctx.fillRect(0, 0, 2, 2);
// b | w
// -----
// w | b
imageData = ctx.getImageData(0, 0, 2, 2);
// (0, 0) black
n = 0;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
// (0, 1) white
n = 1;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 0) white
n = 2;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 1) black
n = 3;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
ctx.clip();
ctx.fillRect(0, 0, 2, 2);
// b | b
// -----
// w | b
imageData = ctx.getImageData(0, 0, 2, 2);
// (0, 0) black
n = 0;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
// (0, 1) white
n = 1;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 0) white
n = 2;
assert.equal(imageData.data[n*4+0], 255);
assert.equal(imageData.data[n*4+1], 255);
assert.equal(imageData.data[n*4+2], 255);
assert.equal(imageData.data[n*4+3], 255);
// (1, 1) black
n = 3;
assert.equal(imageData.data[n*4+0], 0);
assert.equal(imageData.data[n*4+1], 0);
assert.equal(imageData.data[n*4+2], 0);
assert.equal(imageData.data[n*4+3], 255);
});
it('Context2d#IsPointInPath()', function () {
var canvas = new Canvas(4, 4);
var ctx = canvas.getContext('2d');
ctx.rect(0, 0, 4, 2);
ctx.rect(2, 0, 2, 4);
ctx.stroke();
assert.ok(ctx.isPointInPath(1, 1, 'evenodd'));
assert.ok(!ctx.isPointInPath(3, 1, 'evenodd'));
assert.ok(ctx.isPointInPath(3, 1));
assert.ok(!ctx.isPointInPath(1, 3, 'evenodd'));
assert.ok(ctx.isPointInPath(3, 3, 'evenodd'));
});
});

Loading…
Cancel
Save