Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ stroked text painted with a shader.
reach it. They are made by the first band that draws the shape, so the
work stays in the workers. Byte-identical to `Fill`/`Stroke`; 2 000
hatch lines drawn as 64 bands on one core: 87 → 54 ms (one band: 46 ms).
- **Bands and tiles**: a pixel gets the same value in whatever region it
is drawn (`Canvas.Reset`). An edge is the line of its segment in device
space, not the segment cut at the clip and rounded there; a run blends
as coverage does; an analytic row measures every pixel from its own
place. A scene drawn in tiles is byte-identical to the scene drawn at
once (`TestCanvasTiles`), so neither the number of workers nor the
tiling of a viewer shows in a page.
- **Rectangle clips** (91 % of real PDF clips) cost nothing per pixel;
other clips are rasterized once into a mask that is never cleared as a
whole and keeps fully opaque runs as runs.
Expand Down
20 changes: 18 additions & 2 deletions blit.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,14 @@ func (b *SolidBlitter) SetColor(c color.RGBA) {

func (b *SolidBlitter) BlitRun(y, x0, x1 int, alpha uint8) {
d := b.t.row(y, x0, x1)
if alpha == 255 && b.opaque {
fill32(d, b.c)
if b.opaque {
if alpha == 255 {
fill32(d, b.c)
} else if alpha != 0 {
// As BlitCoverage blends it: how a row is cut into runs and
// coverage depends on the clip, the pixels must not.
runLerp(d, b.c, uint32(alpha))
}
return
}
s := b.c
Expand Down Expand Up @@ -193,6 +199,16 @@ func runOverScalar(d []uint32, s uint32) {
}
}

// runLerpScalar blends the opaque color c into every pixel with coverage
// a: the pixels of covOpaqueScalar for a constant coverage.
func runLerpScalar(d []uint32, c, a uint32) {
ca := expand(c) * uint64(a)
inv := uint64(255 - a)
for i, v := range d {
d[i] = compact(div255x(expand(v)*inv + ca))
}
}

// covOpaqueScalar blends an opaque color c (cx expanded) with coverage.
func covOpaqueScalar(d []uint32, cov []uint8, c uint32, cx uint64) {
d = d[:len(cov)]
Expand Down
5 changes: 5 additions & 0 deletions doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
// concurrent use; use one per worker and give each worker its own band or
// tile of the destination (Canvas.Reset takes a region).
//
// A pixel gets the same value in whatever region it is drawn: a scene
// drawn in bands or tiles is, byte for byte, the scene drawn at once. How
// many workers draw a page, and how a viewer cuts it into tiles, does not
// show in it.
//
// # Robustness
//
// NaN and infinite coordinates are rejected, huge ones are clipped
Expand Down
Loading
Loading