code: drawterm

Download patch

ref: daf2ab4550e555cdb6c58f2a9e647c2259a634de
parent: d7620e8d528a87a3d6cf7285a839d52d4f705771
author: cinap_lenrek <[email protected]>
date: Sun Jan 12 21:34:18 EST 2025

libdraw: fix bytesperline() for negative coordinates (thanks qwx)

The bytesperline() and wordsperline() functions return one-too-large
count for negative r.min.x and depth >= 8. (see [1])

The underlying issue is some funky rounding function
that works around integer division for < 8 bit depth
images.

Instead, as the bitsperunit is always a power-of-two,
we can just make a inverse mask and truncate the
low bits for r.min.x before it gets subtracted from
r.max.x and then the sum being rounded up to
the bitsperunit.

This works for all bit depths.

Other funky uses of this negative check have
been replaced by stright forward bitshifts in
allocimage*(), byteaddr() ect.

PS: [1]

unitsperline([-2 0] [-1 1],8,8) -> 2, expected 1
unitsperline([-8 0] [-7 1],8,8) -> 2, expected 1
unitsperline([-2 0] [-1 1],8,8) -> 2, expected 1
unitsperline([-2 0] [-1 1],8,8) -> 2, expected 1
unitsperline([-3 0] [-2 1],8,8) -> 2, expected 1
unitsperline([-3 0] [-2 1],8,8) -> 2, expected 1
unitsperline([-3 0] [-1 1],8,8) -> 3, expected 2
unitsperline([-3 0] [-1 1],8,8) -> 3, expected 2
unitsperline([-4 0] [-3 1],8,8) -> 2, expected 1
unitsperline([-4 0] [-3 1],8,8) -> 2, expected 1
unitsperline([-4 0] [-2 1],8,8) -> 3, expected 2
unitsperline([-4 0] [-2 1],8,8) -> 3, expected 2
unitsperline([-4 0] [-1 1],8,8) -> 4, expected 3
unitsperline([-4 0] [-1 1],8,8) -> 4, expected 3
unitsperline([-5 0] [-4 1],8,8) -> 2, expected 1
unitsperline([-5 0] [-4 1],8,8) -> 2, expected 1
unitsperline([-5 0] [-3 1],8,8) -> 3, expected 2
unitsperline([-5 0] [-3 1],8,8) -> 3, expected 2
unitsperline([-5 0] [-2 1],8,8) -> 4, expected 3
unitsperline([-5 0] [-2 1],8,8) -> 4, expected 3
unitsperline([-5 0] [-1 1],8,8) -> 5, expected 4
unitsperline([-5 0] [-1 1],8,8) -> 5, expected 4
unitsperline([-6 0] [-5 1],8,8) -> 2, expected 1
unitsperline([-6 0] [-5 1],8,8) -> 2, expected 1
unitsperline([-6 0] [-4 1],8,8) -> 3, expected 2
unitsperline([-6 0] [-4 1],8,8) -> 3, expected 2
unitsperline([-6 0] [-3 1],8,8) -> 4, expected 3
unitsperline([-6 0] [-3 1],8,8) -> 4, expected 3
unitsperline([-6 0] [-2 1],8,8) -> 5, expected 4
unitsperline([-6 0] [-2 1],8,8) -> 5, expected 4
unitsperline([-6 0] [-1 1],8,8) -> 6, expected 5
unitsperline([-6 0] [-1 1],8,8) -> 6, expected 5
unitsperline([-7 0] [-6 1],8,8) -> 2, expected 1
unitsperline([-7 0] [-6 1],8,8) -> 2, expected 1
unitsperline([-7 0] [-5 1],8,8) -> 3, expected 2
unitsperline([-7 0] [-5 1],8,8) -> 3, expected 2
unitsperline([-7 0] [-4 1],8,8) -> 4, expected 3
unitsperline([-7 0] [-4 1],8,8) -> 4, expected 3
unitsperline([-7 0] [-3 1],8,8) -> 5, expected 4
unitsperline([-7 0] [-3 1],8,8) -> 5, expected 4
unitsperline([-7 0] [-2 1],8,8) -> 6, expected 5
unitsperline([-7 0] [-2 1],8,8) -> 6, expected 5
unitsperline([-7 0] [-1 1],8,8) -> 7, expected 6
unitsperline([-7 0] [-1 1],8,8) -> 7, expected 6
unitsperline([-8 0] [-7 1],8,8) -> 2, expected 1
unitsperline([-8 0] [-7 1],8,8) -> 2, expected 1
unitsperline([-8 0] [-6 1],8,8) -> 3, expected 2
unitsperline([-8 0] [-6 1],8,8) -> 3, expected 2
unitsperline([-8 0] [-5 1],8,8) -> 4, expected 3
unitsperline([-8 0] [-5 1],8,8) -> 4, expected 3
unitsperline([-8 0] [-4 1],8,8) -> 5, expected 4
unitsperline([-8 0] [-4 1],8,8) -> 5, expected 4
unitsperline([-8 0] [-3 1],8,8) -> 6, expected 5
unitsperline([-8 0] [-3 1],8,8) -> 6, expected 5
unitsperline([-8 0] [-2 1],8,8) -> 7, expected 6
unitsperline([-8 0] [-2 1],8,8) -> 7, expected 6
unitsperline([-8 0] [-1 1],8,8) -> 8, expected 7
unitsperline([-8 0] [-1 1],8,8) -> 8, expected 7
unitsperline([-9 0] [-8 1],8,8) -> 2, expected 1
unitsperline([-9 0] [-8 1],8,8) -> 2, expected 1
unitsperline([-9 0] [-7 1],8,8) -> 3, expected 2
unitsperline([-9 0] [-7 1],8,8) -> 3, expected 2
unitsperline([-9 0] [-6 1],8,8) -> 4, expected 3
unitsperline([-9 0] [-6 1],8,8) -> 4, expected 3
unitsperline([-9 0] [-5 1],8,8) -> 5, expected 4
unitsperline([-9 0] [-5 1],8,8) -> 5, expected 4
unitsperline([-9 0] [-4 1],8,8) -> 6, expected 5
unitsperline([-9 0] [-4 1],8,8) -> 6, expected 5
unitsperline([-9 0] [-3 1],8,8) -> 7, expected 6
unitsperline([-9 0] [-3 1],8,8) -> 7, expected 6
unitsperline([-9 0] [-2 1],8,8) -> 8, expected 7
unitsperline([-9 0] [-2 1],8,8) -> 8, expected 7
unitsperline([-9 0] [-1 1],8,8) -> 9, expected 8
unitsperline([-9 0] [-1 1],8,8) -> 9, expected 8

--- a/libdraw/bytesperline.c
+++ b/libdraw/bytesperline.c
@@ -6,19 +6,9 @@
 int
 unitsperline(Rectangle r, int d, int bitsperunit)
 {
-	ulong l, t;
-
 	if(d <= 0 || d > 32)	/* being called wrong.  d is image depth. */
 		abort();
-
-	if(r.min.x >= 0){
-		l = (r.max.x*d+bitsperunit-1)/bitsperunit;
-		l -= (r.min.x*d)/bitsperunit;
-	}else{			/* make positive before divide */
-		t = (-r.min.x*d+bitsperunit-1)/bitsperunit;
-		l = t+(r.max.x*d+bitsperunit-1)/bitsperunit;
-	}
-	return l;
+	return (r.max.x*d - (r.min.x*d & -bitsperunit) + bitsperunit - 1) / bitsperunit;
 }
 
 int
--- a/libmemdraw/alloc.c
+++ b/libmemdraw/alloc.c
@@ -26,7 +26,6 @@
 allocmemimaged(Rectangle r, ulong chan, Memdata *md)
 {
 	int d;
-	ulong l;
 	Memimage *i;
 
 	if((d = chantodepth(chan)) == 0) {
@@ -38,21 +37,15 @@
 		return nil;
 	}
 
-	l = wordsperline(r, d);
-
 	i = mallocz(sizeof(Memimage), 1);
 	if(i == nil)
 		return nil;
 
 	i->data = md;
-	i->zero = sizeof(ulong)*l*r.min.y;
-	
-	if(r.min.x >= 0)
-		i->zero += (r.min.x*d)/8;
-	else
-		i->zero -= (-r.min.x*d+7)/8;
+	i->width = wordsperline(r, d);
+	i->zero = r.min.y*(int)(sizeof(ulong)*i->width) + ((r.min.x*d) >> 3);
 	i->zero = -i->zero;
-	i->width = l;
+
 	i->r = r;
 	i->clipr = r;
 	i->flags = 0;
@@ -69,8 +62,8 @@
 allocmemimage(Rectangle r, ulong chan)
 {
 	int d;
+	ulong nw;
 	uchar *p;
-	ulong l, nw;
 	Memdata *md;
 	Memimage *i;
 
@@ -82,10 +75,8 @@
 		werrstr("bad rectangle %R", r);
 		return nil;
 	}
+	nw = wordsperline(r, d)*Dy(r);
 
-	l = wordsperline(r, d);
-
-	nw = l*Dy(r);
 	md = malloc(sizeof(Memdata));
 	if(md == nil)
 		return nil;
@@ -143,23 +134,8 @@
 uchar*
 byteaddr(Memimage *i, Point p)
 {
-	uchar *a;
-
-	a = i->data->bdata+i->zero+(int)(sizeof(ulong)*p.y*i->width);
-	if(i->depth < 8){
-		/*
-		 * We need to always round down,
-		 * but C rounds toward zero.
-		 */
-		int np;
-		np = 8/i->depth;
-		if(p.x < 0)
-			return a+(p.x-np+1)/np;
-		else
-			return a+p.x/np;
-	}
-	else
-		return a+p.x*(i->depth/8);
+	uchar *a = i->data->bdata+i->zero;
+	return a + p.y*(int)(sizeof(ulong)*i->width) + ((p.x*i->depth) >> 3);
 }
 
 int