Skip to main content

Module lcd_coverage

Module lcd_coverage 

Source
Expand description

LCD subpixel text as a per-channel coverage mask that composites onto arbitrary backgrounds — no bg pre-fill, no destination-color knowledge required at rasterization time.

§Why this replaces the pre-fill approach

The older PixfmtRgba32Lcd path baked the caller’s background colour into the rasterised output via a per-channel src-over against the pre-filled framebuffer. That coupled the LCD glyphs to one specific destination and forced us to know that destination everywhere text is drawn — driving the walk / sample / push / pop complexity.

Instead, we keep the three subpixel coverage values independent: the output of the rasteriser is three 8-bit channels per pixel (cov_r, cov_g, cov_b) describing how much of each subpixel the glyph covered. At composite time a per-channel Porter-Duff over blend mixes the TEXT COLOUR into the live destination:

dst.r = src.r * cov.r + dst.r * (1 - cov.r)
dst.g = src.g * cov.g + dst.g * (1 - cov.g)
dst.b = src.b * cov.b + dst.b * (1 - cov.b)

The coverage mask is the same regardless of where it lands; the blend naturally produces the correct LCD chroma against any background.

See lcd-subpixel-compositing.md at the repository root for the full derivation.

§Pipeline

shape_text (rustybuzz kerning + fallback chain — unchanged)
  │
per-glyph PathStorage → ConvTransform(scale_x_3) → PixfmtGray8
  (8-bit grayscale coverage at 3× horizontal resolution)
  │
5-tap low-pass filter per output channel
  │
packed (cov_r, cov_g, cov_b) 3-byte mask

Structs§

CachedLcdText
Result of rasterize_text_lcd_cached. Callers composite the mask at (x - baseline_x_in_mask, y - baseline_y_in_mask) where (x, y) is the target baseline position in local / screen coordinates.
LcdBuffer
LCD coverage buffer, row 0 = bottom (matches Framebuffer convention).
LcdMask
3-byte-per-pixel LCD coverage mask. Callers composite via composite_lcd_mask. The distinction from a normal RGBA image is crucial: the three channels are independent coverage values, not an RGB colour — they drive a per-channel blend where each subpixel mixes the source colour with the destination colour by its own amount.
LcdMaskBuilder
Accumulator for an LcdMask. Build the gray buffer with one or more with_paths calls (each opens an AGG rasterizer scope), then finalize to apply the 5-tap filter and produce the packed mask.

Functions§

composite_lcd_mask
Composite an LcdMask onto dst_rgba using per-channel Porter-Duff “over”: each subpixel mixes src_color into the live destination by its own coverage. The destination colour is whatever pixels are currently at the target rect — so this works over any background.
identity_xform
Identity transform — exposed so call sites that don’t otherwise depend on agg_rust::trans_affine::TransAffine can pass one.
rasterize_lcd_mask
Rasterize text at baseline (x, y) into a 3-channel coverage mask of size mask_w × mask_h. transform is applied before the 3× X scale that puts the path into the high-resolution grayscale buffer.
rasterize_lcd_mask_multi
Multi-span variant: raster several (text, x, y) tuples into a single mask. Used by wrapped-text Label so every line shares one 3×-wide gray buffer and one filter pass. The gray buffer is written cumulatively by AGG (glyphs in different pixels don’t interact, so non-overlapping lines just occupy disjoint rows).
rasterize_text_lcd_cached
Rasterise text in font at size into a 3-channel LCD coverage mask, caching the result so subsequent calls with the same (text, font, size) return the shared Arc without re-running AGG.
rect_to_pixel_clip
Convert a screen-space float clip rect (x, y, w, h) to the integer pixel clip box (x1, y1, x2, y2) (half-open) used by [LcdBuffer::composite_mask]. Floor on the left/bottom and ceil on the right/top so any pixel touched by the clip rect (even partially) is included — matches the AGG raster-clip convention.