git: 9front

Download patch

ref: a950d02475406191882f98499eed95faff0f0104
parent: 056daa9c800c4a02173a06630aca9fb46ce66fb8
author: qwx <qwx@sciops.net>
date: Sun Apr 20 16:52:19 EDT 2025

vdiff: fix scrolling and image allocation failures with large diffs

vdiff used to allocate images proportional to the diff size.
allocation may easily fail, and scrolling is also glitchy and slow.
instead, draw to an image the size of the screen.

--- a/sys/src/cmd/vdiff.c
+++ b/sys/src/cmd/vdiff.c
@@ -15,7 +15,6 @@
 typedef struct Patch Patch;
 
 struct Block {
-	Image *b;
 	Rectangle r;
 	Rectangle sr;
 	int v;
@@ -80,6 +79,7 @@
 Col scrlcol;
 Image *bord;
 Image *expander[2];
+Image *fb;
 int totalh;
 int viewh;
 int scrollsize;
@@ -168,7 +168,7 @@
 }
 
 void
-renderblock(Block *b)
+renderblock(Block *b, Rectangle sr)
 {
 	Rectangle r, lr, br;
 	Line *l;
@@ -175,16 +175,15 @@
 	int i, pad;
 
 	pad = 0;
-	r = insetrect(b->r, 1);
-	draw(b->b, b->r, cols[Lnone].bg, nil, ZP);
+	r = insetrect(sr, 1);
 	if(b->f != nil){
 		pad = Margin;
 		lr = r;
-		lr.max.y = lineh;
+		lr.max.y = lr.min.y + lineh;
 		br = rectaddpt(expander[0]->r, Pt(lr.min.x+Hpadding, lr.min.y+Vpadding));
-		border(b->b, b->r, 1, bord, ZP);
-		renderline(b->b, lr, Dx(expander[0]->r)+Hpadding, Lfile, b->f);
-		draw(b->b, br, expander[b->v], nil, ZP);
+		border(fb, sr, 1, bord, ZP);
+		renderline(fb, lr, Dx(expander[0]->r)+Hpadding, Lfile, b->f);
+		draw(fb, br, expander[b->v], nil, ZP);
 		r.min.y += lineh;
 	}
 	if(b->v == 0)
@@ -192,7 +191,7 @@
 	for(i = 0; i < b->nlines; i++){
 		l = b->lines[i];
 		lr = Rect(r.min.x, r.min.y+i*lineh, r.max.x, r.min.y+(i+1)*lineh);
-		renderline(b->b, lr, pad, l->t, l->s);
+		renderline(fb, lr, pad, l->t, l->s);
 	}
 }
 
@@ -203,8 +202,8 @@
 	int i, h, y, ye, vmin, vmax;
 	Block *b;
 
-	draw(screen, sr, cols[Lnone].bg, nil, ZP);
-	draw(screen, scrollr, scrlcol.bg, nil, ZP);
+	draw(fb, fb->r, cols[Lnone].bg, nil, ZP);
+	draw(fb, scrollr, scrlcol.bg, nil, ZP);
 	if(viewh < totalh){
 		h = ((double)viewh/totalh)*Dy(scrollr);
 		y = ((double)offset/totalh)*Dy(scrollr);
@@ -214,19 +213,18 @@
 		scrposr = Rect(scrollr.min.x, scrollr.min.y+y+1, scrollr.max.x-1, ye);
 	}else
 		scrposr = Rect(scrollr.min.x, scrollr.min.y, scrollr.max.x-1, scrollr.max.y);
-	draw(screen, scrposr, scrlcol.fg, nil, ZP);
+ 	draw(fb, scrposr, scrlcol.fg, nil, ZP);
 	vmin = viewr.min.y + offset;
 	vmax = viewr.max.y + offset;
 	clipr = screen->clipr;
-	replclipr(screen, 0, viewr);
+	replclipr(fb, 0, viewr);
 	for(i = 0; i < cur->nblocks; i++){
 		b = cur->blocks[i];
-		if(b->sr.min.y <= vmax && b->sr.max.y >= vmin){
-			renderblock(b);
-			draw(screen, rectaddpt(b->sr, Pt(0, -offset)), b->b, nil, ZP);
-		}
+		if(b->sr.min.y <= vmax && b->sr.max.y >= vmin)
+			renderblock(b, rectaddpt(b->sr, Pt(0, -offset)));
 	}
-	replclipr(screen, 0, clipr);
+	replclipr(fb, 0, clipr);
+	draw(screen, screen->r, fb, nil, fb->r.min);
 	flushimage(display, 1);
 }
 
@@ -281,10 +279,6 @@
 	if(b->v)
 		h += b->nlines*lineh;
 	b->r = Rect(0, 0, w, h);
-	freeimage(b->b);
-	b->b = allocimage(display, b->r, screen->chan, 0, DNofill);
-	if(b-> b == nil)
-		sysfatal("allocimage: %r");
 }
 
 void
@@ -320,6 +314,10 @@
 		clampoffset(1);
 	else
 		clampoffset(0);
+	free(fb);
+	fb = allocimage(display, screen->r, screen->chan, 0, DBlack);
+	if(fb == nil)
+		sysfatal("allocimage: %r");
 	redraw();
 }
 
@@ -517,6 +515,8 @@
 	w = font->height;
 	h = font->height;
 	expander[0] = allocimage(display, Rect(0, 0, w, h), screen->chan, 0, DNofill);
+	if(expander[0] == nil)
+		sysfatal("allocimage: %r");
 	draw(expander[0], expander[0]->r, cols[Lfile].bg, nil, ZP);
 	p[0] = Pt(0.25*w, 0.25*h);
 	p[1] = Pt(0.25*w, 0.75*h);
@@ -524,6 +524,8 @@
 	p[3] = p[0];
 	fillpoly(expander[0], p, 4, 0, bord, ZP);
 	expander[1] = allocimage(display, Rect(0, 0, w, h), screen->chan, 0, DNofill);
+	if(expander[1] == nil)
+		sysfatal("allocimage: %r");
 	draw(expander[1], expander[1]->r, cols[Lfile].bg, nil, ZP);
 	p[0] = Pt(0.25*w, 0.25*h);
 	p[1] = Pt(0.75*w, 0.25*h);
@@ -539,7 +541,6 @@
 	Block *b;
 
 	b = emalloc(sizeof *b);
-	b->b = nil;
 	b->v = 1;
 	b->f = nil;
 	b->lines = nil;
--