ref: c274f902e102c75e129572bdbbd2c65df83422ee
parent: c4c1ce10933423f5378cd68972ee12137152ad1f
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
--
⑨