diff --git a/lib/canvas.js b/lib/canvas.js index 5c6385f..99cf0b7 100644 --- a/lib/canvas.js +++ b/lib/canvas.js @@ -500,4 +500,40 @@ Context2d.prototype.__defineSetter__('font', function(val){ Context2d.prototype.__defineGetter__('font', function(){ return this.lastFontString || '10px sans-serif'; +}); + +/** + * Set text alignment. + * + * @api public + */ + +Context2d.prototype.__defineSetter__('textAlign', function(val){ + switch (val) { + case 'center': + this.setTextAlignment(0); + this.lastTextAlignment = val; + break; + case 'left': + case 'start': + this.setTextAlignment(-1); + this.lastTextAlignment = val; + break; + case 'right': + case 'end': + this.setTextAlignment(1); + this.lastTextAlignment = val; + break; + } +}); + +/** + * Get the current font. + * + * @see exports.parseFont() + * @api public + */ + +Context2d.prototype.__defineGetter__('textAlign', function(){ + return this.lastTextAlignment || 'start'; }); \ No newline at end of file diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index bfc51de..41816a1 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -88,6 +88,7 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(t, "strokeRect", StrokeRect); NODE_SET_PROTOTYPE_METHOD(t, "clearRect", ClearRect); NODE_SET_PROTOTYPE_METHOD(t, "rect", Rect); + NODE_SET_PROTOTYPE_METHOD(t, "setTextAlignment", SetTextAlignment); NODE_SET_PROTOTYPE_METHOD(t, "setTextPath", SetTextPath); NODE_SET_PROTOTYPE_METHOD(t, "measureText", MeasureText); NODE_SET_PROTOTYPE_METHOD(t, "moveTo", MoveTo); @@ -139,6 +140,7 @@ Context2d::Context2d(Canvas *canvas): ObjectWrap() { shadowBlur = shadowOffsetX = shadowOffsetY = 0; state = states[stateno = 0] = (canvas_state_t *) malloc(sizeof(canvas_state_t)); state->globalAlpha = 1; + state->textAlignment = -1; state->fillPattern = state->strokePattern = NULL; RGBA(state->fill,0,0,0,1); RGBA(state->stroke,0,0,0,1); @@ -866,6 +868,22 @@ Context2d::MeasureText(const Arguments &args) { return scope.Close(obj); } +/* + * Set text alignment. -1 0 1 + */ + +Handle +Context2d::SetTextAlignment(const Arguments &args) { + HandleScope scope; + + if (!args[0]->IsInt32()) return Undefined(); + Context2d *context = ObjectWrap::Unwrap(args.This()); + context->state->textAlignment = args[0]->Int32Value(); + + return Undefined(); +} + + /* * Set text path at x, y. */ @@ -886,7 +904,23 @@ Context2d::SetTextPath(const Arguments &args) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); + + // Text extents cairo_text_extents_t te; + cairo_text_extents(ctx, *str, &te); + + // Alignment + switch (context->state->textAlignment) { + // center + case 0: + x -= te.width / 2 + te.x_bearing; + break; + // right + case 1: + x -= te.width + te.x_bearing; + break; + } + cairo_move_to(ctx, x, y); cairo_text_path(ctx, *str); diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 077bf7c..8e16de3 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -32,6 +32,7 @@ typedef struct { cairo_pattern_t *fillPattern; cairo_pattern_t *strokePattern; float globalAlpha; + short textAlignment; } canvas_state_t; class Context2d: public node::ObjectWrap { @@ -64,6 +65,7 @@ class Context2d: public node::ObjectWrap { static Handle SetShadowRGBA(const Arguments &args); static Handle SetFillPattern(const Arguments &args); static Handle SetStrokePattern(const Arguments &args); + static Handle SetTextAlignment(const Arguments &args); static Handle SetTextPath(const Arguments &args); static Handle MeasureText(const Arguments &args); static Handle BezierCurveTo(const Arguments &args); diff --git a/test/canvas.test.js b/test/canvas.test.js index d6fbc9d..29c8152 100644 --- a/test/canvas.test.js +++ b/test/canvas.test.js @@ -747,6 +747,99 @@ module.exports = { , 'Context2d#strokeText()'); }, + 'test Context2d#textAlign': function(assert){ + var canvas = new Canvas(200,200) + , ctx = canvas.getContext('2d'); + + assert.equal('start', ctx.textAlign); + ctx.textAlign = 'center'; + assert.equal('center', ctx.textAlign); + ctx.textAlign = 'right'; + assert.equal('right', ctx.textAlign); + ctx.textAlign = 'end'; + assert.equal('end', ctx.textAlign); + ctx.textAlign = 'fail'; + assert.equal('end', ctx.textAlign); + }, + + 'test Context2d#textAlign= right': function(assert){ + var canvas = new Canvas(200, 200) + , ctx = canvas.getContext('2d') + , path = __dirname + '/images/textAlign-right.png'; + + ctx.strokeRect(0,0,200,200); + ctx.lineTo(0,100); + ctx.lineTo(200,100); + ctx.stroke(); + + ctx.beginPath(); + ctx.lineTo(100,0); + ctx.lineTo(100,200); + ctx.stroke(); + + ctx.font = 'normal 20px Arial'; + ctx.textAlign = 'right'; + ctx.fillText("Wahoo", 100, 100); + + assertChecksum( + canvas + , path + , 'cde33254c5c6de39e1a549edcb23d93e' + , 'Context2d#textAlign= right failed'); + }, + + 'test Context2d#textAlign= center': function(assert){ + var canvas = new Canvas(200, 200) + , ctx = canvas.getContext('2d') + , path = __dirname + '/images/textAlign-center.png'; + + ctx.strokeRect(0,0,200,200); + ctx.lineTo(0,100); + ctx.lineTo(200,100); + ctx.stroke(); + + ctx.beginPath(); + ctx.lineTo(100,0); + ctx.lineTo(100,200); + ctx.stroke(); + + ctx.font = 'normal 20px Arial'; + ctx.textAlign = 'center'; + ctx.fillText("Wahoo", 100, 100); + + assertChecksum( + canvas + , path + , '31b217e572ce2d78f11c1ecf21713579' + , 'Context2d#textAlign= center failed'); + }, + + 'test Context2d#textAlign= left': function(assert){ + var canvas = new Canvas(200, 200) + , ctx = canvas.getContext('2d') + , path = __dirname + '/images/textAlign-left.png'; + + ctx.strokeRect(0,0,200,200); + ctx.lineTo(0,100); + ctx.lineTo(200,100); + ctx.stroke(); + + ctx.beginPath(); + ctx.lineTo(100,0); + ctx.lineTo(100,200); + ctx.stroke(); + + ctx.font = 'normal 20px Arial'; + ctx.textAlign = 'left'; + ctx.fillText("Wahoo", 100, 100); + + assertChecksum( + canvas + , path + , 'f22146910b2df4b96550611f45dda77a' + , 'Context2d#textAlign= left failed'); + }, + 'test Context2d#measureText()': function(assert){ var canvas = new Canvas(200, 200) , ctx = canvas.getContext('2d');