git: 9front

Download patch

ref: 1feadc683b7c15c2fa9ffc76fabbf3599fd26962
parent: 55b324e76e40ca444d38b4a2707a3e6da02dcf2c
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun Jan 12 21:27:51 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/sys/src/libdraw/bytesperline.c
+++ b/sys/src/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/sys/src/libmemdraw/alloc.c
+++ b/sys/src/libmemdraw/alloc.c
@@ -24,7 +24,6 @@
 allocmemimaged(Rectangle r, ulong chan, Memdata *md)
 {
 	int d;
-	ulong l;
 	Memimage *i;
 
 	if((d = chantodepth(chan)) == 0) {
@@ -36,21 +35,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;
@@ -67,8 +60,8 @@
 allocmemimage(Rectangle r, ulong chan)
 {
 	int d;
+	ulong nw;
 	uchar *p;
-	ulong l, nw;
 	Memdata *md;
 	Memimage *i;
 
@@ -80,10 +73,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;
@@ -141,23 +132,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
--