jsPDF
jsPDF copied to clipboard
Context2D does not implement clip() correctly
clip() is supposed to take an argument to specify the clipping rule. Context2D drops this argument on the floor and implements the default clipping rule, I guess.
It can also be given two arguments where one argument is the path. This is also not implemented.
https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/clip
Thanks. Pull requests welcome ;)
I'm pretty confused by the code that is currently there so I'm going to leave this one alone.
I believe arcs are the only problem. If I have no arcs in my clip path, everything is fine. If I add any arcs, it breaks.
A quick inspection leads me to believe that the problem is the handling of the drawArc internal helper function in context2d.js which is always calling the doClip function; doClip must only be called at the end of the complete path, as it (among other things) discards the remaining path.
https://github.com/parallax/jsPDF/blob/5d09af9135a2fe049c7d3c8b95df280d22e4a6db/src/modules/context2d.js#L2234 https://github.com/parallax/jsPDF/blob/5d09af9135a2fe049c7d3c8b95df280d22e4a6db/src/modules/context2d.js#L2251
A very quick monkey patch that got me unblocked on my particular project:
const clip = ctx.clip.bind(ctx)
const pdfClip = (ctx as any).pdf.clip
const pdfDiscardPath = (ctx as any).pdf.discardPath
const patchClip = function (this: Context2d): jsPDF {
const self = this as any
// clip is recursive for some cases; disable recursion into ourselves
ctx.clip = clip
// disable the problem calls into the pdf backend
self.pdf.clip = () => {}
self.pdf.discardPath = () => {}
// perform real clipping
clip()
// restore problem calls into the pdf backend
self.pdf.clip = pdfClip
self.pdf.discardPath = pdfDiscardPath
// finalize the real clipping operation (was disabled)
self.pdf.clip()
self.pdf.discardPath()
// restore patched clip
ctx.clip = patchClip
return self.pdf
}
ctx.clip = patchClip
A proper fix would likely just be to make the drawArc not automatically do the doClip function and require any callers to perform that operation, which would be correct for the general clipping case at least.