WhatsCanvas Shadow Model¶
This document defines the current shadow contract for Paint::setShadowLayer and the intended direction for future shadow work.
Public Paint Contract¶
Paint::setShadowLayer(radius, dx, dy, color) attaches a paint-level shadow to path-based drawing.
radiusis a softening radius. Values below zero are treated as zero by the renderer path that consumes the value.dxanddyoffset the shadow in the same local coordinate space as the drawing operation.colorcarries the shadow color and alpha.Paint::setAlphais multiplied into the shadow color.- A fully transparent shadow color means
Paint::hasShadowLayer()returns false. Paint::clearShadowLayer()disables the shadow.
Shape And Path Shadows¶
The current implementation applies shadows to path-based drawing:
- Rects, round rects, circles, ovals, arcs, polygons, and custom paths all flow through path rendering.
- Fill shadows are submitted before the normal fill.
- Stroke shadows are submitted before the normal stroke.
- Fill-and-stroke paints can produce both fill and stroke shadows.
- Corner path effects are applied before shadow geometry is generated.
- Dash path effects are applied to the stroke shadow through the same dashed-stroke path as normal strokes.
- The current matrix is applied before the shadow offset, so the offset follows the drawing transform.
- Current rectangular clips and clip masks are carried into the shadow pass.
Blur Approximation¶
The current blur is a lightweight multi-pass approximation:
radius <= epsilonemits one offset shadow pass.- Positive radius emits one central pass plus eight lower-alpha ring samples.
- The ring radius is currently
radius * 0.45. - This does not allocate an offscreen blur target and does not run a Gaussian blur shader.
- Bounds calculations conservatively expand by
radiusplus the configured offset.
This model favors simple portability and predictable command submission over high-end soft-shadow quality.
Text Shadows¶
Text shadow is not a separate text-specific API today. drawText and drawTextBox consume the same
paint-level shadow layer used by shape drawing.
- Geometry text submits shadow passes before the normal text command.
- Bitmap text submits tinted shadow image passes before the normal tinted text image.
- Atlas text submits dedicated multi-sample shadow image passes tuned for glyph texture quads.
- The current matrix, rectangular clips, clip masks, alpha, and blend mode are preserved for shadow passes.
- A future high-quality implementation can route text shadows through a general offscreen effect pass.
Box Shadow Or Box Gradient¶
Canvas::drawBoxShadow provides the current shadow-oriented box primitive. It expands or shrinks the rounded rectangle by spread, applies blurRadius, dx, dy, and color, then routes the draw through the existing paint shadow pipeline.
The current primitive supports:
- rounded rectangle bounds
- per-corner radius
- spread
- blur radius
- offset
- color
- clip behavior matching normal draw calls
A future optimized implementation can render rounded-rect shadows without tessellating repeated offset copies.
Regression Coverage¶
Current coverage:
PaintStateTestsvalidates shadow state and transparent-color behavior.ContextLifecycleTestsvalidates command submission for box shadows and text shadows.- The validation scene suite includes a gradient/effect scene using paint-level shadows.
quickReject(path, paint)expands path bounds for shadow offset and radius.- Future coverage should add fuzzy visual comparison for shadow scenes because exact pixel hashes can be driver-sensitive.