xref: /plan9/sys/src/cmd/unix/drawterm/libmemdraw/alloc.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 
6 #define poolalloc(a, b) malloc(b)
7 #define poolfree(a, b) free(b)
8 
9 void
10 memimagemove(void *from, void *to)
11 {
12 	Memdata *md;
13 
14 	md = *(Memdata**)to;
15 	if(md->base != from){
16 		print("compacted data not right: #%p\n", md->base);
17 		abort();
18 	}
19 	md->base = to;
20 
21 	/* if allocmemimage changes this must change too */
22 	md->bdata = (uchar*)&md->base[2];
23 }
24 
25 Memimage*
26 allocmemimaged(Rectangle r, ulong chan, Memdata *md, void *X)
27 {
28 	int d;
29 	ulong l;
30 	Memimage *i;
31 
32 	if(Dx(r) <= 0 || Dy(r) <= 0){
33 		werrstr("bad rectangle %R", r);
34 		return nil;
35 	}
36 	if((d = chantodepth(chan)) == 0) {
37 		werrstr("bad channel descriptor %.8lux", chan);
38 		return nil;
39 	}
40 
41 	l = wordsperline(r, d);
42 
43 	i = mallocz(sizeof(Memimage), 1);
44 	if(i == nil)
45 		return nil;
46 
47 	i->X = X;
48 	i->data = md;
49 	i->zero = sizeof(ulong)*l*r.min.y;
50 
51 	if(r.min.x >= 0)
52 		i->zero += (r.min.x*d)/8;
53 	else
54 		i->zero -= (-r.min.x*d+7)/8;
55 	i->zero = -i->zero;
56 	i->width = l;
57 	i->r = r;
58 	i->clipr = r;
59 	i->flags = 0;
60 	i->layer = nil;
61 	i->cmap = memdefcmap;
62 	if(memsetchan(i, chan) < 0){
63 		free(i);
64 		return nil;
65 	}
66 	return i;
67 }
68 
69 Memimage*
70 _allocmemimage(Rectangle r, ulong chan)
71 {
72 	int d;
73 	ulong l, nw;
74 	Memdata *md;
75 	Memimage *i;
76 
77 	if((d = chantodepth(chan)) == 0) {
78 		werrstr("bad channel descriptor %.8lux", chan);
79 		return nil;
80 	}
81 
82 	l = wordsperline(r, d);
83 	nw = l*Dy(r);
84 	md = malloc(sizeof(Memdata));
85 	if(md == nil)
86 		return nil;
87 
88 	md->ref = 1;
89 	md->base = poolalloc(imagmem, (2+nw)*sizeof(ulong));
90 	if(md->base == nil){
91 		free(md);
92 		return nil;
93 	}
94 
95 	md->base[0] = (ulong)md;
96 	md->base[1] = getcallerpc(&r);
97 
98 	/* if this changes, memimagemove must change too */
99 	md->bdata = (uchar*)&md->base[2];
100 
101 	md->allocd = 1;
102 
103 	i = allocmemimaged(r, chan, md, nil);
104 	if(i == nil){
105 		poolfree(imagmem, md->base);
106 		free(md);
107 		return nil;
108 	}
109 	md->imref = i;
110 	return i;
111 }
112 
113 void
114 _freememimage(Memimage *i)
115 {
116 	if(i == nil)
117 		return;
118 	if(i->data->ref-- == 1 && i->data->allocd){
119 		if(i->data->base)
120 			poolfree(imagmem, i->data->base);
121 		free(i->data);
122 	}
123 	free(i);
124 }
125 
126 /*
127  * Wordaddr is deprecated.
128  */
129 ulong*
130 wordaddr(Memimage *i, Point p)
131 {
132 	return (ulong*) ((ulong)byteaddr(i, p) & ~(sizeof(ulong)-1));
133 }
134 
135 uchar*
136 byteaddr(Memimage *i, Point p)
137 {
138 	uchar *a;
139 
140 	a = i->data->bdata+i->zero+sizeof(ulong)*p.y*i->width;
141 
142 	if(i->depth < 8){
143 		/*
144 		 * We need to always round down,
145 		 * but C rounds toward zero.
146 		 */
147 		int np;
148 		np = 8/i->depth;
149 		if(p.x < 0)
150 			return a+(p.x-np+1)/np;
151 		else
152 			return a+p.x/np;
153 	}
154 	else
155 		return a+p.x*(i->depth/8);
156 }
157 
158 int
159 memsetchan(Memimage *i, ulong chan)
160 {
161 	int d;
162 	int t, j, k;
163 	ulong cc;
164 	int bytes;
165 
166 	if((d = chantodepth(chan)) == 0) {
167 		werrstr("bad channel descriptor");
168 		return -1;
169 	}
170 
171 	i->depth = d;
172 	i->chan = chan;
173 	i->flags &= ~(Fgrey|Falpha|Fcmap|Fbytes);
174 	bytes = 1;
175 	for(cc=chan, j=0, k=0; cc; j+=NBITS(cc), cc>>=8, k++){
176 		t=TYPE(cc);
177 		if(t < 0 || t >= NChan){
178 			werrstr("bad channel string");
179 			return -1;
180 		}
181 		if(t == CGrey)
182 			i->flags |= Fgrey;
183 		if(t == CAlpha)
184 			i->flags |= Falpha;
185 		if(t == CMap && i->cmap == nil){
186 			i->cmap = memdefcmap;
187 			i->flags |= Fcmap;
188 		}
189 
190 		i->shift[t] = j;
191 		i->mask[t] = (1<<NBITS(cc))-1;
192 		i->nbits[t] = NBITS(cc);
193 		if(NBITS(cc) != 8)
194 			bytes = 0;
195 	}
196 	i->nchan = k;
197 	if(bytes)
198 		i->flags |= Fbytes;
199 	return 0;
200 }
201