From a8202da8d86bbdf3f45d6e103120f7601c91b3c0 Mon Sep 17 00:00:00 2001 From: Tj Holowaychuk Date: Mon, 8 Nov 2010 10:46:59 -0800 Subject: [PATCH] Added Context2d::shadow() --- src/CanvasRenderingContext2d.cc | 83 +++++++++++++++++++++++++++------ src/CanvasRenderingContext2d.h | 7 ++- test/public/tests.js | 58 +++++++++++++++++++++++ 3 files changed, 131 insertions(+), 17 deletions(-) diff --git a/src/CanvasRenderingContext2d.cc b/src/CanvasRenderingContext2d.cc index e5a9278..01324c1 100644 --- a/src/CanvasRenderingContext2d.cc +++ b/src/CanvasRenderingContext2d.cc @@ -792,7 +792,18 @@ Context2d::Stroke(const Arguments &args) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); SET_SOURCE(context->state->stroke); + + if (!context->hasShadow()) { + cairo_stroke_preserve(ctx); + return Undefined(); + } + + context->shadowStart(); + cairo_stroke_preserve(ctx); + + context->shadowApply(); cairo_stroke_preserve(ctx); + return Undefined(); } @@ -1049,22 +1060,8 @@ Context2d::FillRect(const Arguments &args) { Context2d *context = ObjectWrap::Unwrap(args.This()); cairo_t *ctx = context->getContext(); cairo_new_path(ctx); - - if (!context->hasShadow()) { - cairo_rectangle(ctx, x, y, width, height); - SET_SOURCE(context->state->fill); - cairo_fill(ctx); - return Undefined(); - } - - context->shadowStart(); - cairo_rectangle(ctx, x, y, width, height); - cairo_fill(ctx); - - context->shadowApply(); cairo_rectangle(ctx, x, y, width, height); - cairo_fill(ctx); - + context->fill(); return Undefined(); } @@ -1169,6 +1166,58 @@ Context2d::Arc(const Arguments &args) { return Undefined(); } +/* + * Fill and apply shadow. + */ + +void +Context2d::fill() { + setSourceRGBA(state->fill); + hasShadow() + ? shadow(cairo_fill) + : cairo_fill(_context); +} + +/* + * Apply shadow with the given draw fn. + */ + +void +Context2d::shadow(void (fn)(cairo_t *cr)) { + cairo_path_t *path = cairo_copy_path_flat(_context); + cairo_save(_context); + + // Offset + cairo_translate( + _context + , state->shadowOffsetX + , state->shadowOffsetY); + + // Apply shadow + cairo_push_group(_context); + cairo_new_path(_context); + cairo_append_path(_context, path); + setSourceRGBA(state->shadow); + fn(_context); + + // No need to invoke blur if shadowBlur is 0 + if (state->shadowBlur) { + Canvas::blur(cairo_get_group_target(_context), state->shadowBlur); + } + + // Paint the shadow + cairo_pop_group_to_source(_context); + cairo_paint(_context); + + // Restore state + cairo_restore(_context); + cairo_new_path(_context); + cairo_append_path(_context, path); + fn(_context); + + cairo_path_destroy(path); +} + /* * Set source RGBA. */ @@ -1189,6 +1238,7 @@ Context2d::setSourceRGBA(rgba_t color) { void Context2d::shadowStart() { + savePath(); cairo_save(_context); cairo_translate( _context @@ -1196,6 +1246,7 @@ Context2d::shadowStart() { , state->shadowOffsetY); cairo_push_group(_context); setSourceRGBA(state->shadow); + restorePath(); } /* @@ -1204,12 +1255,14 @@ Context2d::shadowStart() { void Context2d::shadowApply() { + savePath(); if (state->shadowBlur) { Canvas::blur(cairo_get_group_target(_context), state->shadowBlur); } cairo_pop_group_to_source(_context); cairo_paint(_context); cairo_restore(_context); + restorePath(); } /* diff --git a/src/CanvasRenderingContext2d.h b/src/CanvasRenderingContext2d.h index 8f6ce9d..c54b816 100644 --- a/src/CanvasRenderingContext2d.h +++ b/src/CanvasRenderingContext2d.h @@ -103,14 +103,17 @@ class Context2d: public node::ObjectWrap { inline bool hasShadow(); void inline setSourceRGBA(rgba_t color); void setTextPath(const char *str, double x, double y); + void shadow(void (fn)(cairo_t *cr)); void shadowStart(); void shadowApply(); void savePath(); void restorePath(); - void save(); - void restore(); void saveState(); void restoreState(); + void fill(); + void stroke(); + void save(); + void restore(); protected: Context2d(Canvas *canvas); diff --git a/test/public/tests.js b/test/public/tests.js index 9dbca28..8378097 100644 --- a/test/public/tests.js +++ b/test/public/tests.js @@ -952,5 +952,63 @@ tests['shadowBlur strokeRect()'] = function(ctx){ ctx.lineTo(100,180); ctx.stroke(); + ctx.strokeRect(150,150,20,20); +}; + +tests['shadowBlur fill()'] = function(ctx){ + ctx.strokeRect(150,10,20,20); + + ctx.lineTo(20,5); + ctx.lineTo(100,5); + ctx.stroke(); + + ctx.shadowColor = '#000'; + ctx.shadowBlur = 5; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.rect(20,20,100,100); + ctx.fill(); + + ctx.beginPath(); + ctx.lineTo(20,150); + ctx.lineTo(100,150); + ctx.stroke(); + + ctx.shadowColor = 'rgba(0,0,0,0)'; + + ctx.beginPath(); + ctx.lineTo(20,180); + ctx.lineTo(100,180); + ctx.stroke(); + + ctx.strokeRect(150,150,20,20); +}; + +tests['shadowBlur stroke()'] = function(ctx){ + ctx.strokeRect(150,10,20,20); + + ctx.lineTo(20,5); + ctx.lineTo(100,5); + ctx.stroke(); + + ctx.shadowColor = '#000'; + ctx.shadowBlur = 5; + ctx.shadowOffsetX = 2; + ctx.shadowOffsetY = 2; + ctx.rect(20,20,100,100); + ctx.stroke(); + + ctx.beginPath(); + ctx.lineTo(20,150); + ctx.lineTo(100,150); + ctx.stroke(); + + ctx.shadowColor = 'rgba(0,0,0,0)'; + + ctx.beginPath(); + ctx.lineTo(20,180); + ctx.lineTo(100,180); + ctx.stroke(); + ctx.strokeRect(150,150,20,20); }; \ No newline at end of file