From 31dd7d6d21c4f6ed37ed547aa79f077e570b71fa Mon Sep 17 00:00:00 2001 From: David Caldwell Date: Sun, 12 Jan 2014 17:15:58 -0800 Subject: [PATCH] Add support for the lineDash API. Described here: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash The test images match on Chrome, but not on Firefox. It looks like Firefox resets the lineDash to [] when given invalid parameters. My reading of the spec agrees with Chrome. --- src/CanvasRenderingContext2d.cc | 84 +++++++++++++++++++++++++++++++++ src/CanvasRenderingContext2d.h | 4 ++ test/public/tests.js | 67 +++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 1 deletion(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index 40618dc..21be057 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -117,6 +117,8 @@ Context2d::Initialize(Handle target) { NODE_SET_PROTOTYPE_METHOD(ctor, "closePath", ClosePath); NODE_SET_PROTOTYPE_METHOD(ctor, "arc", Arc); NODE_SET_PROTOTYPE_METHOD(ctor, "arcTo", ArcTo); + NODE_SET_PROTOTYPE_METHOD(ctor, "setLineDash", SetLineDash); + NODE_SET_PROTOTYPE_METHOD(ctor, "getLineDash", GetLineDash); NODE_SET_PROTOTYPE_METHOD(ctor, "_setFont", SetFont); #ifdef HAVE_FREETYPE NODE_SET_PROTOTYPE_METHOD(ctor, "_setFontFace", SetFontFace); @@ -137,6 +139,7 @@ Context2d::Initialize(Handle target) { proto->SetAccessor(NanSymbol("lineWidth"), GetLineWidth, SetLineWidth); proto->SetAccessor(NanSymbol("lineCap"), GetLineCap, SetLineCap); proto->SetAccessor(NanSymbol("lineJoin"), GetLineJoin, SetLineJoin); + proto->SetAccessor(NanSymbol("lineDashOffset"), GetLineDashOffset, SetLineDashOffset); proto->SetAccessor(NanSymbol("shadowOffsetX"), GetShadowOffsetX, SetShadowOffsetX); proto->SetAccessor(NanSymbol("shadowOffsetY"), GetShadowOffsetY, SetShadowOffsetY); proto->SetAccessor(NanSymbol("shadowBlur"), GetShadowBlur, SetShadowBlur); @@ -2018,6 +2021,87 @@ NAN_METHOD(Context2d::SetTextAlignment) { NanReturnUndefined(); } +/* + * Set line dash + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_METHOD(Context2d::SetLineDash) { + NanScope(); + + if (!args[0]->IsArray()) NanReturnUndefined(); + Handle dash = Handle::Cast(args[0]); + uint32_t dashes = dash->Length() & 1 ? dash->Length() * 2 : dash->Length(); + + double a[dashes]; + for (uint32_t i=0; i d = dash->Get(i % dash->Length()); + if (!d->IsNumber()) NanReturnUndefined(); + a[i] = d->NumberValue(); + if (a[i] < 0 || isnan(a[i]) || isinf(a[i])) NanReturnUndefined(); + } + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double offset; + cairo_get_dash(ctx, NULL, &offset); + cairo_set_dash(ctx, a, dashes, offset); + NanReturnUndefined(); +} + +/* + * Get line dash + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_METHOD(Context2d::GetLineDash) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + int dashes = cairo_get_dash_count(ctx); + double a[dashes]; + cairo_get_dash(ctx, a, NULL); + + Local dash = NanNew(dashes); + for (int i=0; iSet(NanNew(i), NanNew(a[i])); + + NanReturnValue(dash); +} + +/* + * Set line dash offset + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_SETTER(Context2d::SetLineDashOffset) { + NanScope(); + + double offset = value->NumberValue(); + if (isnan(offset) || isinf(offset)) return; + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + + int dashes = cairo_get_dash_count(ctx); + double a[dashes]; + cairo_get_dash(ctx, a, NULL); + cairo_set_dash(ctx, a, dashes, offset); +} + +/* + * Get line dash offset + * ref: http://www.w3.org/TR/2dcontext/#dom-context-2d-setlinedash + */ +NAN_GETTER(Context2d::GetLineDashOffset) { + NanScope(); + + Context2d *context = ObjectWrap::Unwrap(args.This()); + cairo_t *ctx = context->context(); + double offset; + cairo_get_dash(ctx, NULL, &offset); + + NanReturnValue(NanNew(offset)); +} + /* * Fill the rectangle defined by x, y, width and height. */ diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 086b816..c29ae3b 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -100,6 +100,8 @@ class Context2d: public node::ObjectWrap { static NAN_METHOD(SetStrokePattern); static NAN_METHOD(SetTextBaseline); static NAN_METHOD(SetTextAlignment); + static NAN_METHOD(SetLineDash); + static NAN_METHOD(GetLineDash); static NAN_METHOD(MeasureText); static NAN_METHOD(BezierCurveTo); static NAN_METHOD(QuadraticCurveTo); @@ -121,6 +123,7 @@ class Context2d: public node::ObjectWrap { static NAN_GETTER(GetLineCap); static NAN_GETTER(GetLineJoin); static NAN_GETTER(GetLineWidth); + static NAN_GETTER(GetLineDashOffset); static NAN_GETTER(GetShadowOffsetX); static NAN_GETTER(GetShadowOffsetY); static NAN_GETTER(GetShadowBlur); @@ -135,6 +138,7 @@ class Context2d: public node::ObjectWrap { static NAN_SETTER(SetLineCap); static NAN_SETTER(SetLineJoin); static NAN_SETTER(SetLineWidth); + static NAN_SETTER(SetLineDashOffset); static NAN_SETTER(SetShadowOffsetX); static NAN_SETTER(SetShadowOffsetY); static NAN_SETTER(SetShadowBlur); diff --git a/test/public/tests.js b/test/public/tests.js index 784a2f4..e09ba82 100644 --- a/test/public/tests.js +++ b/test/public/tests.js @@ -1850,4 +1850,69 @@ tests['putImageData() png data 3'] = function(ctx, done){ }; img.onerror = function(){} img.src = 'state.png'; -}; \ No newline at end of file +}; + +tests['setLineDash'] = function(ctx, done){ + ctx.setLineDash([10, 5, 25, 15]); + ctx.lineWidth = 17; + + var y=5; + var line = function(lineDash, color){ + ctx.setLineDash(lineDash); + if (color) ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += ctx.lineWidth + 4; + }; + + line([15, 30], "blue"); + line([], "black"); + line([5,10,15,20,25,30,35,40,45,50], "purple"); + line([8], "green"); + line([3, 3, -30], "red"); + line([4, Infinity, 4]); + line([10, 10, NaN]); + line((function(){ + ctx.setLineDash([8]); + var a = ctx.getLineDash(); + a[0] -= 3; + a.push(20); + return a; + })(), "orange"); +}; + +tests['lineDashOffset'] = function(ctx, done){ + ctx.setLineDash([10, 5, 25, 15]); + ctx.lineWidth = 4; + + var y=5; + var line = function(lineDashOffset, color){ + ctx.lineDashOffset = lineDashOffset; + if (color) ctx.strokeStyle = color; + ctx.beginPath(); + ctx.moveTo(0, y); + ctx.lineTo(200, y); + ctx.stroke(); + y += ctx.lineWidth + 4; + }; + + line(-10, "black"); + line(0); + line(10); + line(20); + line(30); + line(40, "blue"); + line(NaN) + line(50, "green"); + line(Infinity) + line(60, "orange"); + line(-Infinity) + line(70, "purple"); + line(void 0) + line(80, "black"); + line(ctx.lineDashOffset + 10); + for (var i=0; i<10; i++) + line(90 + i/5, "red"); +}