[whatwg] Proposal: Add CanvasRenderingContext2D.fillRule with "nonzero" (default) and "evenodd" options

Dirk Schulze dschulze at adobe.com
Tue Jan 8 21:08:39 PST 2013

On Jan 8, 2013, at 9:35 AM, Rik Cabanier <cabanier at gmail.com> wrote:

> I looked at pdf2js which is using this fillRule property. As I expected, introduction of the property results in code like this:
>     eoFill: function CanvasGraphics_eoFill() {
>       var savedFillRule = this.setEOFillRule();
>       this.fill();
>       this.restoreFillRule(savedFillRule);
>     },
> ...
>     // 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;
>     },
> So, for even odd winding, all this code needs to run. With my proposal, this gets much simpler:
>    eoFill: function CanvasGraphics_eoFill() {
>       this.eoFill();
>     },
> You can find a pull request with the needed changes to pdf2js here:
> https://github.com/cabanier/pdf.js/commit/8e80b086376013a5438087714a4d2abb6fe67de1

For PDF.js it would probably be easier to set the fillRule every time right before a fill or clip operation, then checking and storing the fill rule in the background. This would reduce the code a lot more.

> I also created patches (with test files) for WebKit and mozilla:
> https://bugs.webkit.org/show_bug.cgi?id=106188
> https://bugzilla.mozilla.org/show_bug.cgi?id=827053

I looked at the patch for webkit. There are two parts where I would disagree and that are potentially confusing.

	eoFill(), eoClip()

It is not obvious what these functions do and how they are different to fill() and clip(). The name should be clear about the usage. But I don't think that introducing two new functions to the Canvas API is a lot better either. An alternative proposal instead of new functions or attributes could be an optional argument for the fill() and stroke() functions. This argument would be an enumeration of 'nonzero' and 'evenodd'.

	ctx.fill(); // fill with 'nonzero'
	ctx.fill('nonzero') // fill with 'nonzero' as well
	ctx.fill('evenodd') // fill with winding rule 'evenodd'

The boolean argument in isPointInPath seems not to be very descriptive as well: 

	boolean isPointInPath(unrestricted double x, unrestricted double y, boolean windingRule);

It is not obvious if 'true' means 'nonzero' or 'evenodd'. I would recommend to use an optional enumeration here, with the default value 'nonzero'.

You mentioned that the winding rule should be a part of the Path object. I can see the use case that you want to address with it. And things like a union path of two path object with different winding rules (as you suggested before) is possible, as long as the union path just needs to get drawn (can be done with compositing or masking in the implementation). But the SVG WG would like to use the Path object as a way to share path data between Canvas and SVG. In this case, the implementation must be able to flatten a path and provide the path data directly. This is beyond the capability of current graphic libraries and requires third party planarizer. This needs to be considered before adding this functionality to the Path API.


> On Thu, Jan 3, 2013 at 3:38 PM, Ian Hickson <ian at hixie.ch> wrote:
> On Fri, 10 Jun 2011, Chris Jones wrote:
> >
> > In 2D canvas, determining whether a point is "inside" a path is
> > currently always done using the non-zero winding rule.  I propose
> > extending 2D canvas to allow determining inside-ness using the even-odd
> > rule.
> I've added this to the spec.
> On Wed, 2 Jan 2013, Dirk Schulze wrote:
> >
> > There was a complain on the webkit bug report if fillRule should be part
> > of the graphics state or not. Did you investigate what current 2d
> > graphics libraries do (qt, Cairo, CG, ...)? Is it part of the graphics
> > state there?
> I have made it be part of the graphics state in the spec; it would be
> unusual in the API for it not to be. However, if this doesn't match
> implementations, please let me know.
> On Wed, 2 Jan 2013, Rik Cabanier wrote:
> >
> > this features is not a trivial as it seems. Adding this will necessitate
> > updates to the algorithms that deal with paths and the outlining of
> > strokes and text.
> Can you elaborate on what updates are needed? I couldn't see any that
> actually needed to be changed.
> > As Dirk mentioned, instead of making it part of the graphics state, it's
> > more likely better to make it part of the fill or clip operator like
> > SVG, PDF and PostScript.
> That seems like it would be inconsistent with the rest of the canvas API.
> > In addition, the path object will need to be extended so it can deal
> > with this idiom.
> Can you elaborate on how this affects the Path object? It seems like it
> would be somewhat orthogonal.
> > The easiest way to implement this, would be to leave the core interface of
> > canvas alone and just extend the path object with winding rules and a
> > method to 'simplify' a path so it can be drawn with any winding rule.
> This doesn't seem like it would be easier... in particular, fillRule is
> now implemented in two browsers, so the implementation cost for them would
> be zero, and they don't yet implement Path at all, so the implementation
> cost for Path would be quite high, even without "simplify". :-)
> On Wed, 2 Jan 2013, Rik Cabanier wrote:
> >
> > However, just look at how stroke is implemented in the Canvas 2d spec or
> > how you can create paths by stroking or stroked text. They're all
> > affected by the winding rules.
> How so?
> > (The description on how to do strokes in the spec is very wrong, but
> > that can be addressed later)
> Can you elaborate on this? If there's a mistake obviously I'd like to fix
> it...
> > Dirk and I did a bit more research and found that SVG, PDF, Flash,
> > PostScript, Skia, Core Graphics and Direct2D all have the winding rules
> > as part of the fill operator. It seems strange that canvas would choose
> > to have a different interface...
> People using the canvas API are more likely to know the canvas API, and
> thus want extensions to be consistent with the canvas API, than they are
> to be familiar with PDF, Flash, PostScript, Skia, Core Graphics, or
> Direct2D. Incidentally, of those, I'm only familiar with SVG, and SVG is
> similar to what I specced (indeed I don't see how it could be part of the
> operator since it's a declarative language).
> --
> Ian Hickson               U+1047E                )\._.,--....,'``.    fL
> http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
> Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

More information about the whatwg mailing list