Phase 18: Canvas 2D API — Issue 4/10#
Implement the full canvas path API with fill and stroke rasterization.
Dependencies#
- Canvas element infrastructure (issue 1)
- Canvas state management & transformation matrix (issue 2)
- Canvas rectangle operations & color styles (issue 3, for fillStyle/strokeStyle)
Requirements#
Path construction:
beginPath()— reset the current pathclosePath()— add a straight line from current point to sub-path startmoveTo(x, y)— begin a new sub-path at the given pointlineTo(x, y)— add a straight line to the given pointrect(x, y, w, h)— add a closed rectangle sub-path
Curves:
arc(x, y, radius, startAngle, endAngle, counterclockwise)— add a circular arcarcTo(x1, y1, x2, y2, radius)— add an arc tangent to two linesbezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y)— cubic Bézier curvequadraticCurveTo(cpx, cpy, x, y)— quadratic Bézier curveellipse(x, y, radiusX, radiusY, rotation, startAngle, endAngle, ccw)— elliptical arc
Fill and stroke:
fill()/fill('nonzero')— fill using nonzero winding rule (default)fill('evenodd')— fill using even-odd rulestroke()— stroke the current path outline- Apply current CTM to all path coordinates
- Scanline rasterization for fill (winding number or ray casting)
- Offset path generation for stroke (based on lineWidth)
Path2D:
new Path2D()— empty pathnew Path2D(path)— copy constructornew Path2D(svgPathString)— parse SVG pathdattribute (M, L, C, Q, Z, etc.)- Path2D has the same path construction methods
ctx.fill(path2d),ctx.stroke(path2d)
Hit testing:
isPointInPath(x, y, fillRule)/isPointInPath(path, x, y, fillRule)isPointInStroke(x, y)/isPointInStroke(path, x, y)
Acceptance criteria#
- Draw a triangle with moveTo/lineTo and fill it
- Draw a circle with arc() and both fill and stroke
- Bézier curves render smooth curves
- Even-odd vs nonzero fill rules produce correct results for overlapping sub-paths
- Path2D can be constructed and used for drawing
- isPointInPath returns correct results
- Unit tests for Bézier flattening, scanline fill, winding number calculation