From abc890a9be5ef1d860224dfd52f30c39bcce9202 Mon Sep 17 00:00:00 2001 From: Yury Delendik Date: Fri, 3 May 2013 18:47:40 -0500 Subject: [PATCH] Adds fill('evenodd') as alternative for mozFillRule --- src/canvas.js | 76 +++++++++++++++++++++++++----------------- test/features/tests.js | 11 +++--- 2 files changed, 53 insertions(+), 34 deletions(-) diff --git a/src/canvas.js b/src/canvas.js index 1b62bce4e..395c4fa1a 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -226,6 +226,7 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.current = new CanvasExtraState(); this.stateStack = []; this.pendingClip = null; + this.pendingEOFill = false; this.res = null; this.xobjs = null; this.commonObjs = commonObjs; @@ -706,23 +707,43 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { consumePath = typeof consumePath !== 'undefined' ? consumePath : true; var ctx = this.ctx; var fillColor = this.current.fillColor; + var needRestore = false; if (fillColor && fillColor.hasOwnProperty('type') && fillColor.type === 'Pattern') { ctx.save(); ctx.fillStyle = fillColor.getPattern(ctx); - ctx.fill(); - ctx.restore(); - } else { - ctx.fill(); + needRestore = true; } - if (consumePath) + + if (this.pendingEOFill) { + if ('mozFillRule' in this.ctx) { + this.ctx.mozFillRule = 'evenodd'; + this.ctx.fill(); + this.ctx.mozFillRule = 'nonzero'; + } else { + try { + this.ctx.fill('evenodd'); + } catch (ex) { + // shouldn't really happen, but browsers might think differently + this.ctx.fill(); + } + } + this.pendingEOFill = false; + } else { + this.ctx.fill(); + } + + if (needRestore) { + ctx.restore(); + } + if (consumePath) { this.consumePath(); + } }, eoFill: function CanvasGraphics_eoFill() { - var savedFillRule = this.setEOFillRule(); + this.pendingEOFill = true; this.fill(); - this.restoreFillRule(savedFillRule); }, fillStroke: function CanvasGraphics_fillStroke() { this.fill(false); @@ -731,19 +752,17 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { this.consumePath(); }, eoFillStroke: function CanvasGraphics_eoFillStroke() { - var savedFillRule = this.setEOFillRule(); + this.pendingEOFill = true; this.fillStroke(); - this.restoreFillRule(savedFillRule); }, closeFillStroke: function CanvasGraphics_closeFillStroke() { this.closePath(); this.fillStroke(); }, closeEOFillStroke: function CanvasGraphics_closeEOFillStroke() { - var savedFillRule = this.setEOFillRule(); + this.pendingEOFill = true; this.closePath(); this.fillStroke(); - this.restoreFillRule(savedFillRule); }, endPath: function CanvasGraphics_endPath() { this.consumePath(); @@ -1707,29 +1726,26 @@ var CanvasGraphics = (function CanvasGraphicsClosure() { consumePath: function CanvasGraphics_consumePath() { if (this.pendingClip) { - var savedFillRule = null; - if (this.pendingClip == EO_CLIP) - savedFillRule = this.setEOFillRule(); - - this.ctx.clip(); - + if (this.pendingClip == EO_CLIP) { + if ('mozFillRule' in this.ctx) { + this.ctx.mozFillRule = 'evenodd'; + this.ctx.clip(); + this.ctx.mozFillRule = 'nonzero'; + } else { + try { + this.ctx.clip('evenodd'); + } catch (ex) { + // shouldn't really happen, but browsers might think differently + this.ctx.clip(); + } + } + } else { + this.ctx.clip(); + } this.pendingClip = null; - if (savedFillRule !== null) - this.restoreFillRule(savedFillRule); } this.ctx.beginPath(); }, - // We generally keep the canvas context set for - // nonzero-winding, and just set evenodd for the operations - // that need them. - setEOFillRule: function CanvasGraphics_setEOFillRule() { - var savedFillRule = this.ctx.mozFillRule; - this.ctx.mozFillRule = 'evenodd'; - return savedFillRule; - }, - restoreFillRule: function CanvasGraphics_restoreFillRule(rule) { - this.ctx.mozFillRule = rule; - }, getSinglePixelWidth: function CanvasGraphics_getSinglePixelWidth(scale) { var inverse = this.ctx.mozCurrentTransformInverse; // max of the current horizontal and vertical scale diff --git a/test/features/tests.js b/test/features/tests.js index f0eab3ef7..6b1d1fb68 100644 --- a/test/features/tests.js +++ b/test/features/tests.js @@ -362,10 +362,13 @@ var tests = [ var ctx = canvas.getContext('2d'); ctx.rect(1, 1, 50, 50); ctx.rect(5, 5, 41, 41); - ['fillRule', 'mozFillRule', 'webkitFillRule'].forEach(function (name) { - if (name in ctx) ctx[name] = 'evenodd'; - }); - ctx.fill(); + + if ('mozFillRule' in ctx) { + ctx.mozFillRule = 'evenodd'; + ctx.fill(); + } else { + ctx.fill('evenodd'); + } var data = ctx.getImageData(0, 0, 50, 50).data; var isEvenOddFill = data[20 * 4 + 20 * 200 + 3] == 0 &&