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