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