Browse Source

Merge branch 'strokeStyle'

v1.x
Tj Holowaychuk 15 years ago
parent
commit
7271eb8f49
  1. 41
      lib/canvas.js
  2. 84
      src/context2d.cc
  3. 8
      src/context2d.h
  4. 23
      test/canvas.test.js

41
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){ Context2d.prototype.__defineSetter__('fillStyle', function(val){
var rgba = exports.parseColor(val) || [0,0,0,1]; var rgba = exports.parseColor(val) || [0,0,0,1];
this.lastFillStyle = rgba; this.lastFillStyle = rgba;
@ -121,7 +128,41 @@ Context2d.prototype.__defineSetter__('fillStyle', function(val){
, rgba[3]); , rgba[3]);
}); });
/**
* Get the current fill style string.
*
* @api public
*/
Context2d.prototype.__defineGetter__('fillStyle', function(){ Context2d.prototype.__defineGetter__('fillStyle', function(){
var rgba = this.lastFillStyle; var rgba = this.lastFillStyle;
return 'rgba(' + rgba[0] + ',' + rgba[1] + ',' + rgba[2] + ',' + rgba[3] + ')'; 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] + ')';
});

84
src/context2d.cc

@ -12,6 +12,27 @@
using namespace v8; using namespace v8;
using namespace node; using namespace node;
/*
* Set RGBA.
*/
#define RGBA(_,R,G,B,A) \
_.r = R; \
_.g = G; \
_.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. * Rectangle arg assertions.
*/ */
@ -30,6 +51,24 @@ using namespace node;
int width = args[2]->Int32Value(); \ int width = args[2]->Int32Value(); \
int height = args[3]->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(); \
double a = args[3]->NumberValue();
/* /*
* Initialize Context2d. * Initialize Context2d.
*/ */
@ -55,6 +94,7 @@ Context2d::Initialize(Handle<Object> target) {
NODE_SET_PROTOTYPE_METHOD(t, "closePath", ClosePath); NODE_SET_PROTOTYPE_METHOD(t, "closePath", ClosePath);
NODE_SET_PROTOTYPE_METHOD(t, "arc", Arc); NODE_SET_PROTOTYPE_METHOD(t, "arc", Arc);
NODE_SET_PROTOTYPE_METHOD(t, "setFillRGBA", SetFillRGBA); NODE_SET_PROTOTYPE_METHOD(t, "setFillRGBA", SetFillRGBA);
NODE_SET_PROTOTYPE_METHOD(t, "setStrokeRGBA", SetStrokeRGBA);
target->Set(String::NewSymbol("Context2d"), t->GetFunction()); target->Set(String::NewSymbol("Context2d"), t->GetFunction());
} }
@ -78,7 +118,8 @@ Context2d::New(const Arguments &args) {
Context2d::Context2d(Canvas *canvas): ObjectWrap() { Context2d::Context2d(Canvas *canvas): ObjectWrap() {
_canvas = canvas; _canvas = canvas;
_context = cairo_create(canvas->getSurface()); _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);
} }
/* /*
@ -90,30 +131,28 @@ Context2d::~Context2d() {
} }
/* /*
* Set fill RGBA, use internally for fillStyle= * Set fill RGBA, used internally for fillStyle=
*/ */
Handle<Value> Handle<Value>
Context2d::SetFillRGBA(const Arguments &args) { Context2d::SetFillRGBA(const Arguments &args) {
HandleScope scope; HandleScope scope;
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")));
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This()); Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
RGBA(context->fill,r,g,b,a);
return Undefined();
}
cairo_set_source_rgba(context->getContext() /*
, args[0]->Int32Value() * Set stroke RGBA, used internally for strokeStyle=
, args[1]->Int32Value() */
, args[2]->Int32Value()
, args[3]->NumberValue());
Handle<Value>
Context2d::SetStrokeRGBA(const Arguments &args) {
HandleScope scope;
RGBA_ARGS;
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
RGBA(context->stroke,r,g,b,a);
return Undefined(); return Undefined();
} }
@ -182,7 +221,9 @@ Handle<Value>
Context2d::Fill(const Arguments &args) { Context2d::Fill(const Arguments &args) {
HandleScope scope; HandleScope scope;
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This()); Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_fill(context->getContext()); cairo_t *ctx = context->getContext();
SET_SOURCE_RGBA(context->fill);
cairo_fill_preserve(ctx);
return Undefined(); return Undefined();
} }
@ -194,7 +235,9 @@ Handle<Value>
Context2d::Stroke(const Arguments &args) { Context2d::Stroke(const Arguments &args) {
HandleScope scope; HandleScope scope;
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This()); Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_stroke(context->getContext()); cairo_t *ctx = context->getContext();
SET_SOURCE_RGBA(context->stroke);
cairo_stroke_preserve(ctx);
return Undefined(); return Undefined();
} }
@ -251,6 +294,7 @@ Context2d::FillRect(const Arguments &args) {
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This()); Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_t *ctx = context->getContext(); cairo_t *ctx = context->getContext();
cairo_rectangle(ctx, x, y, width, height); cairo_rectangle(ctx, x, y, width, height);
SET_SOURCE_RGBA(context->fill);
cairo_fill(ctx); cairo_fill(ctx);
return Undefined(); return Undefined();
} }
@ -266,6 +310,7 @@ Context2d::StrokeRect(const Arguments &args) {
Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This()); Context2d *context = ObjectWrap::Unwrap<Context2d>(args.This());
cairo_t *ctx = context->getContext(); cairo_t *ctx = context->getContext();
cairo_rectangle(ctx, x, y, width, height); cairo_rectangle(ctx, x, y, width, height);
SET_SOURCE_RGBA(context->stroke);
cairo_stroke(ctx); cairo_stroke(ctx);
return Undefined(); return Undefined();
} }
@ -282,6 +327,7 @@ Context2d::ClearRect(const Arguments &args) {
cairo_t *ctx = context->getContext(); cairo_t *ctx = context->getContext();
cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR); cairo_set_operator(ctx, CAIRO_OPERATOR_CLEAR);
cairo_rectangle(ctx, x, y, width, height); cairo_rectangle(ctx, x, y, width, height);
SET_SOURCE_RGBA(context->fill);
cairo_fill(ctx); cairo_fill(ctx);
cairo_set_operator(ctx, CAIRO_OPERATOR_OVER); cairo_set_operator(ctx, CAIRO_OPERATOR_OVER);
return Undefined(); return Undefined();

8
src/context2d.h

@ -10,8 +10,15 @@
#include "canvas.h" #include "canvas.h"
typedef struct {
unsigned char r, g, b;
double a;
} rgba_t;
class Context2d: public node::ObjectWrap { class Context2d: public node::ObjectWrap {
public: public:
rgba_t fill;
rgba_t stroke;
static void Initialize(Handle<Object> target); static void Initialize(Handle<Object> target);
static Handle<Value> New(const Arguments &args); static Handle<Value> New(const Arguments &args);
static Handle<Value> BeginPath(const Arguments &args); static Handle<Value> BeginPath(const Arguments &args);
@ -19,6 +26,7 @@ class Context2d: public node::ObjectWrap {
static Handle<Value> Fill(const Arguments &args); static Handle<Value> Fill(const Arguments &args);
static Handle<Value> Stroke(const Arguments &args); static Handle<Value> Stroke(const Arguments &args);
static Handle<Value> SetFillRGBA(const Arguments &args); static Handle<Value> SetFillRGBA(const Arguments &args);
static Handle<Value> SetStrokeRGBA(const Arguments &args);
static Handle<Value> BezierCurveTo(const Arguments &args); static Handle<Value> BezierCurveTo(const Arguments &args);
static Handle<Value> LineTo(const Arguments &args); static Handle<Value> LineTo(const Arguments &args);
static Handle<Value> MoveTo(const Arguments &args); static Handle<Value> MoveTo(const Arguments &args);

23
test/canvas.test.js

@ -171,6 +171,29 @@ module.exports = {
, 'Canvas#bezierCurveTo() failed'); , '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){ 'test Canvas#fillStyle=': function(assert){
var canvas = new Canvas(200, 200) var canvas = new Canvas(200, 200)
, ctx = canvas.getContext('2d') , ctx = canvas.getContext('2d')

Loading…
Cancel
Save