W3C home > Mailing lists > Public > whatwg@whatwg.org > January 2014

Re: [whatwg] Drawing shapes on canvas

From: Joe Gregorio <jcgregorio@google.com>
Date: Mon, 27 Jan 2014 18:15:38 -0500
Message-ID: <CAA6qSUCsGB1njL1zx7KHnD_S1krV7o2oLBswYenVVoVBvtRGjA@mail.gmail.com>
To: Rik Cabanier <cabanier@gmail.com>
Cc: whatwg <whatwg@lists.whatwg.org>
On Mon, Jan 27, 2014 at 1:26 PM, Rik Cabanier <cabanier@gmail.com> wrote:

>
>
>
> On Fri, Jan 24, 2014 at 12:08 PM, Joe Gregorio <jcgregorio@google.com>wrote:
>
>> Rik,
>>   From the Skia perspective we have the following feedback on the
>> proposal.
>>
>
> Thanks for your feedback!
>
>
>>
>>   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.
>>
>
> I agree.
> Maybe it's OK to have a staged approach where we introduce the concept of
> Path first and possible add shapes later.
>
>
>>   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.
>>
>
> That is an interesting concept. Do you have a more detailed proposal or a
> prototype in the works?
>

My tentative plan for this quarter includes prototyping to inform a
proposal.


> At first blush, this seems more like streamlined SVG :-)
>
>   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);
>>
>
> My issue with this add* methods is that they likely will not do what an
> author expects since the path segments will interact in unexpected ways.
> In addition, I think no browser follows the spec for "tracing a path" [1].
> Since paths will interact with the segments that that algorithm generates,
> we will get into interoperability issues.
>

Agreed on the complexity and the interactions. Unfortunately dropping all
of them but addPath does seem to leave
Path with a hole in functionality since CanvasRenderingContext2D has both a
fillText() and strokeText(). How about simplifying
to just these two add* methods:

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

Note the removal of the CanvasDrawingStyles from addText.


>
>
>> >
>> > 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)
>>
>
> No particular reason. It's a bit more compact to do it with a method so
> you don't have to call 'new'.
>
>
>>
>> >     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?
>>
>
> Yes
>
>
>>
>> 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().
>>
>
> The reason I didn't add them, is that it's straightforward for
> implementation that don't have access to such a library.
>  For instance, if there was a union of a fill and a stroke, you could call
> 'fill' and 'stroke' under the hood.
>
>
>>
>> > }
>> >
>> > 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:
>>
>
> 1:
> http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#trace-a-path
>
>
Received on Monday, 27 January 2014 23:16:34 UTC

This archive was generated by hypermail 2.4.0 : Wednesday, 22 January 2020 17:00:15 UTC