[whatwg] Drawing shapes on canvas

Joe Gregorio jcgregorio at google.com
Fri Jan 24 12:08:21 PST 2014


Rik,
  From the Skia perspective we have the following feedback on the proposal.

  While we can see how Shape2D can be implemented, it isn't clear that it's
  such a large performance benefit over what Path provides, so we aren't
  opposed to Shape2D, but don't believe implementing Path should be held up
  for the sake of Shape2D.  Path itself is a huge win for performance over
  having only a single current default path and has utility without the need
  for Shape2D.

  In general we would like to see a layered approach to drawing objects,
  starting with something primitive like Path, and at the most general a
  Display List[1] that contains the full set of capabilities of
  CanvasRenderingContext2D.  That layering could be done in two or three
  objects, either [Path, DisplayList] or [Path, Shape2D, DisplayList]. In
all
  cases you can use the lower level objects to construct higher level
objects,
  i.e. use one or more Paths to build a Shape2D, and use Paths and Shape2Ds
to
  define a DisplayList.

  What we'd like to see happen:
    1. Review the Path add* methods and possibly simplify them, see below.
    2. Keep the rest of the Path object and the Path related methods on the
       CanvasRenderingContext2D.
    3. If Shape2D moves forward do it by adding different versions of fill,
       clip, etc to CanvasRenderingContext2D, such as:

       void fill(optional CanvasFillRule fillRule = "nonzero");
       void fill(Path path, optional CanvasFillRule fillRule = "nonzero");
       void fill(Shape2D shape);

    4. Possibly work on a DisplayList design, but only after some
       experimentation.

  We have some particular feedback on the Shape2D design that is inline
below:

[1] http://en.wikipedia.org/wiki/Display_list

> All,
>
> around a year ago, I wrote a blog post [1] that introduced a new 'Shape'
> class that described a filled or stroked region or an area of text. Java2D
> has a similar concept that they call 'Area' [2].
>
> We've had some discussions but it doesn't look like there was any sort of
> conclusion. I'd like to pick it back up now that we have a partial
> implementation of the Path object and people are starting to look into
> extending it.
>
> I'll reiterate my proposal:
> 1. remove all the addxxx methods from the Path2D object [3]
> Path object are just containers for segments. Aggregating segments will
> generally not give the desired results since the segments will interact
> (see [1]).
> AddPath *could* be kept if people see a strong use case.

The add* methods could be simplified to:

  void addPath(Path path, SVGMatrix? transformation);
  void addPathByStrokingPath(Path path, CanvasDrawingStyles styles,
SVGMatrix? transformation);
  void addText(DOMString text, CanvasDrawingStyles styles, SVGMatrix?
transformation, unrestricted double x, unrestricted double y, optional
unrestricted double maxWidth);
  void addTextAlongPath(DOMString text, CanvasDrawingStyles styles,
SVGMatrix? transformation, Path path, optional unrestricted double
maxWidth);

The functionality of the addPathByStrokingText methods below can be done by
applying the above methods.

  void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles,
SVGMatrix? transformation, unrestricted double x, unrestricted double y,
optional unrestricted double maxWidth);
  void addPathByStrokingText(DOMString text, CanvasDrawingStyles styles,
SVGMatrix? transformation, Path path, optional unrestricted double
maxWidth);

>
> 2. introduce a new class 'Shape2D'
> Interface:
>
> [Constructor,
>   Constructor(Path2D , CanvasWindingRule = "nonzero"),
>   Constructor(Path2D , CanvasDrawingStyles, SVGMatrix?), // strokes a path
>   Constructor(DomString text, CanvasDrawingStyles, SVGMatrix?,
unrestricted
> double, unrestricted double, boolean isStroked = false, optional
> unrestricted double)]
> interface Shape2D{
>     Shape2D transform(matrix); // returns a transformed path

Why not do this as another constructor?

  Constructor(Shape2D, SVGMatrix)

>     Shape2D add(Shape2D); // returns a path that is the union of the 2
paths

Just to clarify, add() means a union of the two shapes, with no side-effects
resulting from winding rules of the individual path?

Shape2D seems reasonable and useful just as an immutable capture of all
"coverage" aspects of geometry. If add() is hard for platforms to support,
or
is expensive and clients don't know that, perhaps we can leave it out of
this
version. If we really want to have add(), why not include the full
compliment
of Set operations  [ diff, xor, intersect ], which are no harder to
implement
(afaik) once you've implemented add().

> }
>
> This class will represent a painted area. Because it knows the winding and
> stroking rules, the browser will be able to do expensive math in advance.
> It can also cache the region on the GPU.
> constructors:
> a. default constructor that creates an empty region
> b. constructor that take a path and a winding rule. This represents a
> filled region
> c. constructor that takes a path, canvasDrawingStyles object and a matrix.
> This represent a stroked region.
> d. constructor that takes text + canvasDrawingStyles. This represent a
> region of filled or stroked text.
>
> methods:
> a. transform -> transform the shape by the matrix and returns a new shape
> b. add -> add the region of the shape to the current shape and return as a
> new shape
>
> 3. Add new methods:
fill(Shape2D)/clip(Shape2D)/isPointInShape(Shape2D,...)
>
> 4. remove stroke(path), fill(path), clip(path), isPointInPath(path,...)
>
> 5. HitRegionOptions takes a Shape2D instead of a path + winding rule
>
> What do people think?
>
>
> 1: http://blogs.adobe.com/webplatform/2013/01/31/revised-canvas-paths/
> 2: http://docs.oracle.com/javase/tutorial/2d/advanced/complexshapes.html
> 3:
>
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#path-objects

  Thanks,
  -joe



More information about the whatwg mailing list