- From: Rik Cabanier <cabanier@gmail.com>
- Date: Mon, 27 Jan 2014 18:28:10 -0800
- To: Joe Gregorio <jcgregorio@google.com>
- Cc: whatwg <whatwg@lists.whatwg.org>
On Mon, Jan 27, 2014 at 3:15 PM, Joe Gregorio <jcgregorio@google.com> wrote: > > > > 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. > Unfortunately, that doesn't really help. For instance, let's say you request the path for the letter 'o'. It's represented by 2 closed paths. What winding rule should you use when you fill that path? Should the paths be oriented so you have to use a NZO fill or so you can use any winding rule? What happens if the path for a letter intersect with another path (or another letter)? > > >>> > 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 Tuesday, 28 January 2014 02:28:43 UTC