From c20cc1336cecb73b3d702b9f8b3a831bfd24d22c Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 10:56:49 -0700 Subject: [PATCH 1/8] Added Context2d#strokeStyle --- lib/canvas.js | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/lib/canvas.js b/lib/canvas.js index d892b73..136484b 100644 --- a/lib/canvas.js +++ b/lib/canvas.js @@ -111,6 +111,13 @@ Canvas.prototype.getContext = function(contextId){ } }; +/** + * Set the fill style with the given css color string. + * + * @see exports.parseColor() + * @api public + */ + Context2d.prototype.__defineSetter__('fillStyle', function(val){ var rgba = exports.parseColor(val) || [0,0,0,1]; this.lastFillStyle = rgba; @@ -121,7 +128,41 @@ Context2d.prototype.__defineSetter__('fillStyle', function(val){ , rgba[3]); }); +/** + * Get the current fill style string. + * + * @api public + */ + Context2d.prototype.__defineGetter__('fillStyle', function(){ var rgba = this.lastFillStyle; return 'rgba(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ',' + rgba[3] + ')'; +}); + +/** + * Set the stroke style with the given css color string. + * + * @see exports.parseColor() + * @api public + */ + +Context2d.prototype.__defineSetter__('strokeStyle', function(val){ + var rgba = exports.parseColor(val) || [0,0,0,1]; + this.lastStrokeStyle = rgba; + this.setStrokeRGBA( + rgba[0] + , rgba[1] + , rgba[2] + , rgba[3]); +}); + +/** + * Get the current stroke style string. + * + * @api public + */ + +Context2d.prototype.__defineGetter__('strokeStyle', function(){ + var rgba = this.lastStrokeStyle; + return 'rgba(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ',' + rgba[3] + ')'; }); \ No newline at end of file From e224b70246ae9d0d0b52dfea2e08939938ffcf48 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 10:59:52 -0700 Subject: [PATCH 2/8] Added RGBA_ARGS --- src/context2d.cc | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/context2d.cc b/src/context2d.cc index 521db65..d1bb145 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -30,6 +30,24 @@ using namespace node; int width = args[2]->Int32Value(); \ int height = args[3]->Int32Value(); +/* + * RGBA arg assertions. + */ + +#define RGBA_ARGS \ + if (!args[0]->IsNumber()) \ + return ThrowException(Exception::TypeError(String::New("r required"))); \ + if (!args[1]->IsNumber()) \ + return ThrowException(Exception::TypeError(String::New("g required"))); \ + if (!args[2]->IsNumber()) \ + return ThrowException(Exception::TypeError(String::New("b required"))); \ + if (!args[3]->IsNumber()) \ + return ThrowException(Exception::TypeError(String::New("alpha required"))); \ + int r = args[0]->Int32Value(); \ + int g = args[1]->Int32Value(); \ + int b = args[2]->Int32Value(); \ + int a = args[3]->NumberValue(); + /* * Initialize Context2d. */ @@ -96,23 +114,10 @@ Context2d::~Context2d() { Handle Context2d::SetFillRGBA(const Arguments &args) { HandleScope scope; - - if (!args[0]->IsNumber()) - return ThrowException(Exception::TypeError(String::New("r required"))); - if (!args[1]->IsNumber()) - return ThrowException(Exception::TypeError(String::New("g required"))); - if (!args[2]->IsNumber()) - return ThrowException(Exception::TypeError(String::New("b required"))); - if (!args[3]->IsNumber()) - return ThrowException(Exception::TypeError(String::New("alpha required"))); - + RGBA_ARGS; Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_set_source_rgba(context->getContext() - , args[0]->Int32Value() - , args[1]->Int32Value() - , args[2]->Int32Value() - , args[3]->NumberValue()); + cairo_set_source_rgba(context->getContext(), r, g, b, a); return Undefined(); } From 0d30df6ae4f845793f74d04b0ff01e145b762ca9 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 11:21:16 -0700 Subject: [PATCH 3/8] Separated fill / stroke style --- src/context2d.cc | 42 +++++++++++++++++++++++++++++++++++++----- src/context2d.h | 8 ++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/context2d.cc b/src/context2d.cc index d1bb145..420c057 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -73,6 +73,7 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "closePath", ClosePath); NODE_SET_PROTOTYPE_METHOD(t, "arc", Arc); NODE_SET_PROTOTYPE_METHOD(t, "setFillRGBA", SetFillRGBA); + NODE_SET_PROTOTYPE_METHOD(t, "setStrokeRGBA", SetStrokeRGBA); target->Set(String::NewSymbol("Context2d"), t->GetFunction()); } @@ -108,7 +109,7 @@ Context2d::~Context2d() { } /* - * Set fill RGBA, use internally for fillStyle= + * Set fill RGBA, used internally for fillStyle= */ Handle @@ -116,9 +117,26 @@ Context2d::SetFillRGBA(const Arguments &args) { HandleScope scope; RGBA_ARGS; Context2d *context = ObjectWrap::Unwrap(args.This()); + context->fill.r = r; + context->fill.g = g; + context->fill.b = b; + context->fill.a = a; + return Undefined(); +} - cairo_set_source_rgba(context->getContext(), r, g, b, a); - +/* + * Set stroke RGBA, used internally for strokeStyle= + */ + +Handle +Context2d::SetStrokeRGBA(const Arguments &args) { + HandleScope scope; + RGBA_ARGS; + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->stroke.r = r; + context->stroke.g = g; + context->stroke.b = b; + context->stroke.a = a; return Undefined(); } @@ -187,7 +205,14 @@ Handle Context2d::Fill(const Arguments &args) { HandleScope scope; Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_fill(context->getContext()); + cairo_t *ctx = context->getContext(); + cairo_set_source_rgba( + ctx + , context->fill.r + , context->fill.g + , context->fill.b + , context->fill.a); + cairo_fill(ctx); return Undefined(); } @@ -199,7 +224,14 @@ Handle Context2d::Stroke(const Arguments &args) { HandleScope scope; Context2d *context = ObjectWrap::Unwrap(args.This()); - cairo_stroke(context->getContext()); + cairo_t *ctx = context->getContext(); + cairo_set_source_rgba( + ctx + , context->stroke.r + , context->stroke.g + , context->stroke.b + , context->stroke.a); + cairo_stroke(ctx); return Undefined(); } diff --git a/src/context2d.h b/src/context2d.h index 1a70d6b..fc73e57 100644 --- a/src/context2d.h +++ b/src/context2d.h @@ -10,8 +10,15 @@ #include "canvas.h" +typedef struct { + unsigned char r, g, b; + double a; +} rgba_t; + class Context2d: public node::ObjectWrap { public: + rgba_t fill; + rgba_t stroke; static void Initialize(Handle target); static Handle New(const Arguments &args); static Handle BeginPath(const Arguments &args); @@ -19,6 +26,7 @@ class Context2d: public node::ObjectWrap { static Handle Fill(const Arguments &args); static Handle Stroke(const Arguments &args); static Handle SetFillRGBA(const Arguments &args); + static Handle SetStrokeRGBA(const Arguments &args); static Handle BezierCurveTo(const Arguments &args); static Handle LineTo(const Arguments &args); static Handle MoveTo(const Arguments &args); From 6caa431682ce005bea26798445a09a09d19bcce4 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 11:23:48 -0700 Subject: [PATCH 4/8] Defaulting stroke / fill styles to rgba(0,0,0,1) --- src/context2d.cc | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/context2d.cc b/src/context2d.cc index 420c057..b20d5f9 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -12,6 +12,16 @@ using namespace v8; using namespace node; +/* + * Set RGBA. + */ + +#define RGBA(_,R,G,B,A) \ + _.r = R; \ + _.g = G; \ + _.b = B; \ + _.a = A; \ + /* * Rectangle arg assertions. */ @@ -97,7 +107,8 @@ Context2d::New(const Arguments &args) { Context2d::Context2d(Canvas *canvas): ObjectWrap() { _canvas = canvas; _context = cairo_create(canvas->getSurface()); - cairo_set_source_rgba(_context, 0, 0, 0, 1); + RGBA(fill,0,0,0,1); + RGBA(stroke,0,0,0,1); } /* @@ -117,10 +128,7 @@ Context2d::SetFillRGBA(const Arguments &args) { HandleScope scope; RGBA_ARGS; Context2d *context = ObjectWrap::Unwrap(args.This()); - context->fill.r = r; - context->fill.g = g; - context->fill.b = b; - context->fill.a = a; + RGBA(context->fill,r,g,b,a); return Undefined(); } @@ -133,10 +141,7 @@ Context2d::SetStrokeRGBA(const Arguments &args) { HandleScope scope; RGBA_ARGS; Context2d *context = ObjectWrap::Unwrap(args.This()); - context->stroke.r = r; - context->stroke.g = g; - context->stroke.b = b; - context->stroke.a = a; + RGBA(context->fill,r,g,b,a); return Undefined(); } From 20c2451b182a6897aa3782f21f67b4333bbc3abd Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 11:29:57 -0700 Subject: [PATCH 5/8] Typo --- src/context2d.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context2d.cc b/src/context2d.cc index b20d5f9..fea83bf 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -141,7 +141,7 @@ Context2d::SetStrokeRGBA(const Arguments &args) { HandleScope scope; RGBA_ARGS; Context2d *context = ObjectWrap::Unwrap(args.This()); - RGBA(context->fill,r,g,b,a); + RGBA(context->stroke,r,g,b,a); return Undefined(); } From a65f24b2d65687f0f85e970b00a816abcf1ab350 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 11:44:43 -0700 Subject: [PATCH 6/8] Added SET_SOURCE_RGBA --- src/context2d.cc | 29 +++++++++++++++-------------- test/canvas.test.js | 23 +++++++++++++++++++++++ 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/context2d.cc b/src/context2d.cc index fea83bf..19efbc2 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -22,6 +22,17 @@ using namespace node; _.b = B; \ _.a = A; \ +/* + * Set source RGBA. + */ + +#define SET_SOURCE_RGBA(C) \ + cairo_set_source_rgba(ctx \ + , C.r \ + , C.g \ + , C.b \ + , C.a); + /* * Rectangle arg assertions. */ @@ -211,13 +222,8 @@ Context2d::Fill(const Arguments &args) { HandleScope scope; Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); - cairo_set_source_rgba( - ctx - , context->fill.r - , context->fill.g - , context->fill.b - , context->fill.a); - cairo_fill(ctx); + SET_SOURCE_RGBA(context->fill); + cairo_fill_preserve(ctx); return Undefined(); } @@ -230,13 +236,8 @@ Context2d::Stroke(const Arguments &args) { HandleScope scope; Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); - cairo_set_source_rgba( - ctx - , context->stroke.r - , context->stroke.g - , context->stroke.b - , context->stroke.a); - cairo_stroke(ctx); + SET_SOURCE_RGBA(context->stroke); + cairo_stroke_preserve(ctx); return Undefined(); } diff --git a/test/canvas.test.js b/test/canvas.test.js index e412a3c..313573a 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -171,6 +171,29 @@ module.exports = { , 'Canvas#bezierCurveTo() failed'); }, + 'test fill with stroke': function(assert){ + var canvas = new Canvas(200, 200) + , ctx = canvas.getContext('2d') + , path = __dirname + '/fillWithStroke.png'; + + ctx.beginPath(); + ctx.arc(75,75,50,0,Math.PI*2,true); + ctx.fill(); + ctx.closePath(); + ctx.beginPath(); + ctx.fillStyle = 'red'; + ctx.strokeStyle = 'yellow'; + ctx.arc(75,75,30,0,Math.PI*2,true); + ctx.fill(); + ctx.stroke(); + + assertChecksum( + canvas + , path + , '0437605377cc9840c58cb166fb0b89d4' + , 'fill with stroke failed'); + }, + 'test Canvas#fillStyle=': function(assert){ var canvas = new Canvas(200, 200) , ctx = canvas.getContext('2d') From e1fa13247f2200bc44ef005372b2c105a52e08f6 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 11:48:40 -0700 Subject: [PATCH 7/8] Implemented SET_SOURCE_RGBA --- src/context2d.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/context2d.cc b/src/context2d.cc index 19efbc2..dbfb422 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -294,6 +294,7 @@ Context2d::FillRect(const Arguments &args) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); cairo_rectangle(ctx, x, y, width, height); + SET_SOURCE_RGBA(context->fill); cairo_fill(ctx); return Undefined(); } @@ -309,6 +310,7 @@ Context2d::StrokeRect(const Arguments &args) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); cairo_rectangle(ctx, x, y, width, height); + SET_SOURCE_RGBA(context->stroke); cairo_stroke(ctx); return Undefined(); } @@ -325,6 +327,7 @@ Context2d::ClearRect(const Arguments &args) { cairo_t *ctx = context->getContext(); cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); cairo_rectangle(ctx, x, y, width, height); + SET_SOURCE_RGBA(context->fill); cairo_fill(ctx); cairo_set_operator(ctx, CAIRO_OPERATOR_OVER); return Undefined(); From c35c4fff42f6101ea09876c5f392501fc3526014 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Wed, 29 Sep 2010 11:52:34 -0700 Subject: [PATCH 8/8] Fixed alpha channel --- src/context2d.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/context2d.cc b/src/context2d.cc index dbfb422..a5a2508 100644 --- a/src/context2d.cc +++ b/src/context2d.cc @@ -67,7 +67,7 @@ using namespace node; int r = args[0]->Int32Value(); \ int g = args[1]->Int32Value(); \ int b = args[2]->Int32Value(); \ - int a = args[3]->NumberValue(); + double a = args[3]->NumberValue(); /* * Initialize Context2d.