Skip to content

Commit faae57a

Browse files
wsw0108LinusU
authored andcommitted
Add support for evenodd fill rule
1 parent 8b45c4c commit faae57a

File tree

4 files changed

+201
-1
lines changed

4 files changed

+201
-1
lines changed

examples/fill-evenodd.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
var fs = require('fs')
2+
var path = require('path')
3+
var Canvas = require('..')
4+
5+
var canvas = new Canvas(100, 100)
6+
var ctx = canvas.getContext('2d')
7+
8+
ctx.fillStyle = '#f00'
9+
ctx.rect(0, 0, 100, 50)
10+
ctx.arc(50, 50, 50, 0, 2 * Math.PI)
11+
ctx.fill('evenodd')
12+
13+
canvas.createJPEGStream().pipe(fs.createWriteStream(path.join(__dirname, '/fill-evenodd.jpg')))

src/CanvasRenderingContext2d.cc

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,18 @@ Context2d::restorePath() {
296296
* Fill and apply shadow.
297297
*/
298298

299+
void
300+
Context2d::setFillRule(v8::Local<v8::Value> value) {
301+
cairo_fill_rule_t rule = CAIRO_FILL_RULE_WINDING;
302+
if (value->IsString()) {
303+
String::Utf8Value str(value);
304+
if (std::strcmp(*str, "evenodd") == 0) {
305+
rule = CAIRO_FILL_RULE_EVEN_ODD;
306+
}
307+
}
308+
cairo_set_fill_rule(_context, rule);
309+
}
310+
299311
void
300312
Context2d::fill(bool preserve) {
301313
if (state->fillPattern) {
@@ -1400,6 +1412,7 @@ NAN_METHOD(Context2d::IsPointInPath) {
14001412
cairo_t *ctx = context->context();
14011413
double x = info[0]->NumberValue()
14021414
, y = info[1]->NumberValue();
1415+
context->setFillRule(info[2]);
14031416
info.GetReturnValue().Set(Nan::New<Boolean>(cairo_in_fill(ctx, x, y) || cairo_in_stroke(ctx, x, y)));
14041417
return;
14051418
}
@@ -1677,6 +1690,7 @@ NAN_METHOD(Context2d::Scale) {
16771690

16781691
NAN_METHOD(Context2d::Clip) {
16791692
Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1693+
context->setFillRule(info[0]);
16801694
cairo_t *ctx = context->context();
16811695
cairo_clip_preserve(ctx);
16821696
}
@@ -1687,6 +1701,7 @@ NAN_METHOD(Context2d::Clip) {
16871701

16881702
NAN_METHOD(Context2d::Fill) {
16891703
Context2d *context = Nan::ObjectWrap::Unwrap<Context2d>(info.This());
1704+
context->setFillRule(info[0]);
16901705
context->fill(true);
16911706
}
16921707

src/CanvasRenderingContext2d.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ class Context2d: public Nan::ObjectWrap {
161161
void restorePath();
162162
void saveState();
163163
void restoreState();
164+
void inline setFillRule(v8::Local<v8::Value> value);
164165
void fill(bool preserve = false);
165166
void stroke(bool preserve = false);
166167
void save();

test/canvas.test.js

Lines changed: 172 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -833,5 +833,176 @@ describe('Canvas', function () {
833833
assert(chunk.length < SIZE);
834834
});
835835
s.on('end', done);
836-
})
836+
});
837+
838+
it('Context2d#fill()', function() {
839+
var canvas = new Canvas(2, 2);
840+
var ctx = canvas.getContext('2d');
841+
842+
// fill whole canvas with white
843+
ctx.fillStyle = '#fff';
844+
ctx.fillRect(0, 0, 2, 2);
845+
846+
var imageData, n;
847+
848+
// black
849+
ctx.fillStyle = '#000';
850+
ctx.rect(0, 0, 2, 1);
851+
ctx.rect(1, 0, 1, 2);
852+
853+
ctx.fill('evenodd');
854+
// b | w
855+
// -----
856+
// w | b
857+
imageData = ctx.getImageData(0, 0, 2, 2);
858+
// (0, 0) black
859+
n = 0;
860+
assert.equal(imageData.data[n*4+0], 0);
861+
assert.equal(imageData.data[n*4+1], 0);
862+
assert.equal(imageData.data[n*4+2], 0);
863+
assert.equal(imageData.data[n*4+3], 255);
864+
// (0, 1) white
865+
n = 1;
866+
assert.equal(imageData.data[n*4+0], 255);
867+
assert.equal(imageData.data[n*4+1], 255);
868+
assert.equal(imageData.data[n*4+2], 255);
869+
assert.equal(imageData.data[n*4+3], 255);
870+
// (1, 0) white
871+
n = 2;
872+
assert.equal(imageData.data[n*4+0], 255);
873+
assert.equal(imageData.data[n*4+1], 255);
874+
assert.equal(imageData.data[n*4+2], 255);
875+
assert.equal(imageData.data[n*4+3], 255);
876+
// (1, 1) black
877+
n = 3;
878+
assert.equal(imageData.data[n*4+0], 0);
879+
assert.equal(imageData.data[n*4+1], 0);
880+
assert.equal(imageData.data[n*4+2], 0);
881+
assert.equal(imageData.data[n*4+3], 255);
882+
883+
// should not retain previous value 'evenodd'
884+
ctx.fill();
885+
// b | b
886+
// -----
887+
// w | b
888+
imageData = ctx.getImageData(0, 0, 2, 2);
889+
// (0, 0) black
890+
n = 0;
891+
assert.equal(imageData.data[n*4+0], 0);
892+
assert.equal(imageData.data[n*4+1], 0);
893+
assert.equal(imageData.data[n*4+2], 0);
894+
assert.equal(imageData.data[n*4+3], 255);
895+
// (0, 1) black
896+
n = 1;
897+
assert.equal(imageData.data[n*4+0], 0);
898+
assert.equal(imageData.data[n*4+1], 0);
899+
assert.equal(imageData.data[n*4+2], 0);
900+
assert.equal(imageData.data[n*4+3], 255);
901+
// (1, 0) white
902+
n = 2;
903+
assert.equal(imageData.data[n*4+0], 255);
904+
assert.equal(imageData.data[n*4+1], 255);
905+
assert.equal(imageData.data[n*4+2], 255);
906+
assert.equal(imageData.data[n*4+3], 255);
907+
// (1, 1) black
908+
n = 3;
909+
assert.equal(imageData.data[n*4+0], 0);
910+
assert.equal(imageData.data[n*4+1], 0);
911+
assert.equal(imageData.data[n*4+2], 0);
912+
assert.equal(imageData.data[n*4+3], 255);
913+
});
914+
915+
it('Context2d#clip()', function () {
916+
var canvas = new Canvas(2, 2);
917+
var ctx = canvas.getContext('2d');
918+
919+
// fill whole canvas with white
920+
ctx.fillStyle = '#fff';
921+
ctx.fillRect(0, 0, 2, 2);
922+
923+
var imageData, n;
924+
925+
// black
926+
ctx.fillStyle = '#000';
927+
ctx.rect(0, 0, 2, 1);
928+
ctx.rect(1, 0, 1, 2);
929+
930+
ctx.clip('evenodd');
931+
ctx.fillRect(0, 0, 2, 2);
932+
// b | w
933+
// -----
934+
// w | b
935+
imageData = ctx.getImageData(0, 0, 2, 2);
936+
// (0, 0) black
937+
n = 0;
938+
assert.equal(imageData.data[n*4+0], 0);
939+
assert.equal(imageData.data[n*4+1], 0);
940+
assert.equal(imageData.data[n*4+2], 0);
941+
assert.equal(imageData.data[n*4+3], 255);
942+
// (0, 1) white
943+
n = 1;
944+
assert.equal(imageData.data[n*4+0], 255);
945+
assert.equal(imageData.data[n*4+1], 255);
946+
assert.equal(imageData.data[n*4+2], 255);
947+
assert.equal(imageData.data[n*4+3], 255);
948+
// (1, 0) white
949+
n = 2;
950+
assert.equal(imageData.data[n*4+0], 255);
951+
assert.equal(imageData.data[n*4+1], 255);
952+
assert.equal(imageData.data[n*4+2], 255);
953+
assert.equal(imageData.data[n*4+3], 255);
954+
// (1, 1) black
955+
n = 3;
956+
assert.equal(imageData.data[n*4+0], 0);
957+
assert.equal(imageData.data[n*4+1], 0);
958+
assert.equal(imageData.data[n*4+2], 0);
959+
assert.equal(imageData.data[n*4+3], 255);
960+
961+
ctx.clip();
962+
ctx.fillRect(0, 0, 2, 2);
963+
// b | b
964+
// -----
965+
// w | b
966+
imageData = ctx.getImageData(0, 0, 2, 2);
967+
// (0, 0) black
968+
n = 0;
969+
assert.equal(imageData.data[n*4+0], 0);
970+
assert.equal(imageData.data[n*4+1], 0);
971+
assert.equal(imageData.data[n*4+2], 0);
972+
assert.equal(imageData.data[n*4+3], 255);
973+
// (0, 1) white
974+
n = 1;
975+
assert.equal(imageData.data[n*4+0], 255);
976+
assert.equal(imageData.data[n*4+1], 255);
977+
assert.equal(imageData.data[n*4+2], 255);
978+
assert.equal(imageData.data[n*4+3], 255);
979+
// (1, 0) white
980+
n = 2;
981+
assert.equal(imageData.data[n*4+0], 255);
982+
assert.equal(imageData.data[n*4+1], 255);
983+
assert.equal(imageData.data[n*4+2], 255);
984+
assert.equal(imageData.data[n*4+3], 255);
985+
// (1, 1) black
986+
n = 3;
987+
assert.equal(imageData.data[n*4+0], 0);
988+
assert.equal(imageData.data[n*4+1], 0);
989+
assert.equal(imageData.data[n*4+2], 0);
990+
assert.equal(imageData.data[n*4+3], 255);
991+
});
992+
993+
it('Context2d#IsPointInPath()', function () {
994+
var canvas = new Canvas(4, 4);
995+
var ctx = canvas.getContext('2d');
996+
997+
ctx.rect(0, 0, 4, 2);
998+
ctx.rect(2, 0, 2, 4);
999+
ctx.stroke();
1000+
1001+
assert.ok(ctx.isPointInPath(1, 1, 'evenodd'));
1002+
assert.ok(!ctx.isPointInPath(3, 1, 'evenodd'));
1003+
assert.ok(ctx.isPointInPath(3, 1));
1004+
assert.ok(!ctx.isPointInPath(1, 3, 'evenodd'));
1005+
assert.ok(ctx.isPointInPath(3, 3, 'evenodd'));
1006+
});
1007+
8371008
});

0 commit comments

Comments
 (0)