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
16 changes: 16 additions & 0 deletions paint/background_paint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,22 @@ func BenchmarkPaintBgBitmapRepeat(b *testing.B) {
}
}

// BenchmarkBlitImageLargePhoto exercises a plain <img> blit (no repeat
// multiplier, unlike BenchmarkPaintBgBitmapRepeat above) at a realistic
// full-bleed photo size, since blitImage has the IDENTICAL
// src.At(...).RGBA() pattern blitTileClipped had before round 175's fix —
// flagged in that round's PR as a known, smaller instance of the same
// anti-pattern, unmeasured at the time. One element, not stamped many
// times, so the question here is whether a SINGLE large image's own pixel
// count alone makes the interface-boxing/premultiply cost worth fixing.
func BenchmarkBlitImageLargePhoto(b *testing.B) {
dst := white(1920, 1080)
src := solidImage(1920, 1080, color.RGBA{10, 20, 200, 255})
for i := 0; i < b.N; i++ {
blitImage(dst, src, 0, 0, dst.Rect)
}
}

func TestBgMode(t *testing.T) {
if bgMode(nil) != resample.Bicubic {
t.Error("nil style should default to bicubic")
Expand Down
21 changes: 17 additions & 4 deletions paint/paint.go
Original file line number Diff line number Diff line change
Expand Up @@ -1660,8 +1660,19 @@ func toNRGBA(src image.Image) *image.NRGBA {

// blitImage draws src onto dst with its top-left at (dx, dy), confined to clip
// (an ancestor's overflow clip; always within the image bounds).
//
// src is normalised to *image.NRGBA once, here, rather than read through the
// image.Image/color.Color interface per pixel — the same fix round 175 made
// for blitTileClipped's background-repeat path (see toNRGBA's own doc
// comment), flagged there as a known, smaller instance of the same pattern:
// no repeat multiplier here, but a full-bleed photo is still hundreds of
// thousands to millions of pixels for one element, and the interface read
// also double-applied alpha the same way (At().RGBA() already premultiplies;
// passing that as blendPixel's straight colour argument alongside the same
// alpha again as coverage), invisible at alpha=255.
func blitImage(dst *image.RGBA, src image.Image, dx, dy int, clip image.Rectangle) {
b := src.Bounds()
tile := toNRGBA(src)
b := tile.Bounds()
for sy := b.Min.Y; sy < b.Max.Y; sy++ {
ty := dy + (sy - b.Min.Y)
if ty < clip.Min.Y || ty >= clip.Max.Y {
Expand All @@ -1672,9 +1683,11 @@ func blitImage(dst *image.RGBA, src image.Image, dx, dy int, clip image.Rectangl
if tx < clip.Min.X || tx >= clip.Max.X {
continue
}
r, g, bl, a := src.At(sx, sy).RGBA()
cov := uint8(a >> 8)
blendPixel(dst, tx, ty, css.Color{R: uint8(r >> 8), G: uint8(g >> 8), B: uint8(bl >> 8), A: 255}, cov)
c := tile.NRGBAAt(sx, sy)
if c.A == 0 {
continue
}
blendPixel(dst, tx, ty, css.Color{R: c.R, G: c.G, B: c.B, A: 255}, c.A)
}
}
}
Expand Down
Loading