HTML Canvas Path object in WebKit

Update 25-03-2017: All browsers do support the Path object now. The interface name changed to Path2D though. Chrome (and Blink based browsers) do not support the addPath method yet. Most other browsers do so. The HTML Canvas poperty currentPath did not make it into the spec. Instead the canvas context methods clip(), stroke() and fill() take two additional arguments: A Path2D object and a WindingRule enumeration. The specification can be found here: WHATWG.

HTML Canvas provides several path methods to create a path on the canvas context. This context path can then be used for filling and stroking a shape or to specify a clipping region where drawing occurs. Each path method represents a path segment added to the end of the current path.

The canvas context does not allow multiple paths and therefore, it is necessary to clear the current path to paint another path. The WHAT WG HTML specification adds a Path object to create a reusable path segment container. This way it is not necessary to recreate an immutable path over and over again if more then one path needs to get drawn. This is especially useful for animations used in games with a lot of returning shapes.

WebKit has a first implementation of this part of the spec now - with some differences.

Introducing path methods

In the following code snippet the path methods lineTo and moveTo add new path segments to a new path (beginPath) with the shape of a rectangle:

ctx.beginPath();
ctx.moveTo(20,20);
ctx.lineTo(120,20);
ctx.lineTo(120,120);
ctx.lineTo(20,120);
ctx.closePath();

With the following styling and painting operations, this path gets filled with yellow and stroked with blue:

ctx.fillStyle = "yellow";
ctx.fill();
ctx.strokeStyle = "blue";
ctx.stroke();

The path can be used as a clipping region. Everything outside this region gets clipped.

ctx.clip();

The Path object in WebKit

The Path object implements the CanvasPathMethods interface. This interface provides methods like

  • moveTo,
  • lineTo,
  • quadraticCurveTo,
  • bezierCurveTo,
  • arcTo,
  • rect,
  • arc,
  • closePath
  • and others (partly not supported yet).

The interface description of Path in WebKit looks like in the following WebIDL snippet:

[Constructor,
  Constructor(DOMString svgPath),
  Constructor(Path)]
interface Path {
}
Path implements CanvasPathMethods;

The Path object has three different constructors.

var p1 = new Path();

This creates a new, empty path. New path segments can be added with the path methods from above.

var p2 = new Path("M20,20L120,20L120,120L20,120z");

This constructor takes a DOMString path argument. This string gets parsed as an SVG path data stream. Resulting sub paths get added to the new created path. The parsing follows the rules and error handling defined by SVG. New path segments can be added after the creation.

var p3 = new Path(p2);

This is a copy constructor. It creates a copy of the passed path. New path segments can be added but won't affect the original path.

Using the Path object with the canvas context

To use the Path object, the interface CanvasRenderingContext2d of the canvas context gets extended by a new attribute: currentPath. The attribute can be used to replace the current context path with the path of a Path object. This attribute is readable as well which can be used to copy the current path.

In the following snippet, the context path gets replaced by the previously created path object p2:

ctx.currentPath = p2;

The current context path was replaced with a copy of p2 and can now be modified further.

ctx.lineTo(120,120);

A new path segment will be added to the context path. The modifications do not affect p1.

The current context path can be read and stored in a new variable for later usage.

var p4 = ctx.currentPath;

Differences to the WHAT WG specification

The specification does not define the currentPath attribute at the moment. Instead, a Path object would need to get passed as argument to each painting or clipping operation.

ctx.fill(p2);
ctx.stroke(p2);
ctx.clip(p2);

These methods take an additional WindingRule argument in the latest versions of Firefox and WebKit which is not present in the WHAT WG specification. Therefore, in the future these methods may require both a Path and a WindingRule argument.

Accessing the current path of the context is not possible in the WHAT WG spec. The Path object is stateless. Therefore, transformation operations like rotate can not be applied while creating a Path. Transformations still make sense as shown in the following snippet:

ctx.beginPath();
ctx.rotate(-Math.PI * 0.5);
ctx.lineTo(100,0);

// Not in the WHAT WG spec, but allowed in WebKit:
var path = ctx.currentPath; // path would be a line from 0,0 to 0,100.

The transformation of the CTM above influences the path creation as well.

The Path object in the WHAT WG specification allows accessing the shape outline of glyphs on styled text. This is not yet implemented in WebKit.

The addPath method is not implemented yet. In the following example, two paths are created that an author might want to combine (added).

var p1 = new Path();
p1.moveTo(20,20);
p1.lineTo(120,20);

var p2 = new Path();
p2.lineTo(120,120);
p2.lineTo(20,120);
p2.closePath();

p1.addPath(p2); // Does not work on WebKit.

The user might expect that the first lineTo operation of the second path takes the last point of the first path and connects both paths. This would not be the case in WebKit for now. Creating a new Path object implies calling moveTo when the first operation is applied to the path (p2.lineTo(120,20);). This is the same behavior as for the canvas context which is necessary because of the underlying graphics libraries. Skipping this operation seems to be better then implementing it in a wrong way. This allows a correct implementation later.

Enabling support of Path in WebKit

The Path object is behind a compiler flag, disabled by default. It is necessary to download the source code of WebKit and build it with the flag --canvas-path.

build-webkit --canvas-path

Visit webkit.org for more information about how to get and build WebKit.

After a successful build, you can try the following example: example01. On success you should see three different colored rectangles.

I will post an update once the Path object is activated in the nightly builds by default.