diff --git a/src/modules/context2d.js b/src/modules/context2d.js index e7b4ca5fb..c533edab3 100644 --- a/src/modules/context2d.js +++ b/src/modules/context2d.js @@ -48,6 +48,7 @@ import { this.globalCompositeOperation = ctx.globalCompositeOperation || "normal"; this.globalAlpha = ctx.globalAlpha || 1.0; this.clip_path = ctx.clip_path || []; + this.clip_path_rule = ctx.clip_path_rule; this.currentPoint = ctx.currentPoint || new Point(); this.miterLimit = ctx.miterLimit || 10.0; this.lastPoint = ctx.lastPoint || new Point(); @@ -869,10 +870,19 @@ import { * * @name clip * @function + * @param {"nonzero"|"evenodd"} [fillRule="nonzero"] The algorithm by which to determine if a point is inside or outside the clipping region. * @description The clip() method clips a region of any shape and size from the original canvas. */ - Context2D.prototype.clip = function() { + Context2D.prototype.clip = function(fillRule) { + // The optional path argument (clip(path[, fillRule])) is not supported, so + // pick the fill rule from whichever argument is a string. + for (var i = 0; i < arguments.length; i++) { + if (typeof arguments[i] === "string") { + fillRule = arguments[i]; + } + } this.ctx.clip_path = JSON.parse(JSON.stringify(this.path)); + this.ctx.clip_path_rule = fillRule; pathPreProcess.call(this, null, true); }; @@ -2254,7 +2264,7 @@ import { }; var doClip = function() { - this.pdf.clip(); + this.pdf.clip(this.ctx.clip_path_rule); this.pdf.discardPath(); }; diff --git a/test/specs/context2d.spec.js b/test/specs/context2d.spec.js index 8ed45ba38..71b571ab9 100644 --- a/test/specs/context2d.spec.js +++ b/test/specs/context2d.spec.js @@ -745,6 +745,40 @@ describe("Context2D: standard tests", () => { ]); }); + it("clip uses the nonzero rule by default", () => { + var doc = new jsPDF({ floatPrecision: 2 }); + var ctx = doc.context2d; + var writeArray = []; + doc.__private__.setCustomOutputDestination(writeArray); + + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(10, 0); + ctx.lineTo(10, 10); + ctx.closePath(); + ctx.clip(); + + expect(writeArray).toContain("W"); + expect(writeArray).not.toContain("W*"); + }); + + it("clip respects the evenodd fill rule", () => { + var doc = new jsPDF({ floatPrecision: 2 }); + var ctx = doc.context2d; + var writeArray = []; + doc.__private__.setCustomOutputDestination(writeArray); + + ctx.beginPath(); + ctx.moveTo(0, 0); + ctx.lineTo(10, 0); + ctx.lineTo(10, 10); + ctx.closePath(); + ctx.clip("evenodd"); + + expect(writeArray).toContain("W*"); + expect(writeArray).not.toContain("W"); + }); + it("margin property shorthands", () => { const doc = new jsPDF(); const ctx = doc.context2d; diff --git a/types/index.d.ts b/types/index.d.ts index fd21f959a..95a1217d1 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -430,7 +430,7 @@ declare module "jspdf" { y: number ): void; clearRect(x: number, y: number, w: number, h: number): void; - clip(): jsPDF; + clip(fillRule?: "nonzero" | "evenodd"): jsPDF; clipEvenOdd(): jsPDF; closePath(): void; createLinearGradient(