Phase 18: Canvas 2D API — Issue 2/10#
Implement the canvas 2D context state stack and affine transformation matrix.
Dependencies#
- Canvas element & 2D rendering context infrastructure (issue 1)
Requirements#
State stack (save/restore):
save()pushes the current drawing state onto a stackrestore()pops and restores the most recently saved state- State includes: CTM, clipping region, fillStyle, strokeStyle, lineWidth, lineCap, lineJoin, miterLimit, lineDash, lineDashOffset, globalAlpha, globalCompositeOperation, font, textAlign, textBaseline, direction, shadowColor, shadowBlur, shadowOffsetX, shadowOffsetY, imageSmoothingEnabled, imageSmoothingQuality
- Nested save/restore works correctly
Current transformation matrix (CTM):
- Internal 3×3 affine matrix representation (6 components: a, b, c, d, e, f)
- Starts as identity matrix
translate(tx, ty)— post-multiply translationrotate(angle)— post-multiply rotation (angle in radians)scale(sx, sy)— post-multiply scaletransform(a, b, c, d, e, f)— post-multiply arbitrary affine transformsetTransform(a, b, c, d, e, f)— reset CTM then applyresetTransform()— reset to identitygetTransform()— return current matrix as DOMMatrix-like object
Integration:
- All subsequent drawing operations (rects, paths, text, images) must transform coordinates through the CTM before rasterizing
- save/restore correctly preserves and restores the CTM
Acceptance criteria#
ctx.save()/ctx.restore()round-trips the transformation matrixctx.translate(100, 50)shifts subsequent drawing by (100, 50)ctx.rotate(Math.PI / 4)rotates subsequent drawing 45°ctx.scale(2, 0.5)scales subsequent drawingctx.setTransform(1, 0, 0, 1, 0, 0)resets to identity- Nested save/restore with different transforms works correctly
- Unit tests for matrix multiplication, inversion, and point transformation