xref: /plan9/sys/src/libmemlayer/draw.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <memlayer.h>
6 #include <pool.h>
7 
8 struct Draw
9 {
10 	Point	deltas;
11 	Point	deltam;
12 	Memlayer		*dstlayer;
13 	Memimage	*src;
14 	Memimage	*mask;
15 	int	op;
16 };
17 
18 static
19 void
20 ldrawop(Memimage *dst, Rectangle screenr, Rectangle clipr, void *etc, int insave)
21 {
22 	struct Draw *d;
23 	Point p0, p1;
24 	Rectangle oclipr, srcr, r, mr;
25 	int ok;
26 
27 	d = etc;
28 	if(insave && d->dstlayer->save==nil)
29 		return;
30 
31 	p0 = addpt(screenr.min, d->deltas);
32 	p1 = addpt(screenr.min, d->deltam);
33 
34 	if(insave){
35 		r = rectsubpt(screenr, d->dstlayer->delta);
36 		clipr = rectsubpt(clipr, d->dstlayer->delta);
37 	}else
38 		r = screenr;
39 
40 	/* now in logical coordinates */
41 
42 	/* clipr may have narrowed what we should draw on, so clip if necessary */
43 	if(!rectinrect(r, clipr)){
44 		oclipr = dst->clipr;
45 		dst->clipr = clipr;
46 		ok = drawclip(dst, &r, d->src, &p0, d->mask, &p1, &srcr, &mr);
47 		dst->clipr = oclipr;
48 		if(!ok)
49 			return;
50 	}
51 	memdraw(dst, r, d->src, p0, d->mask, p1, d->op);
52 }
53 
54 void
55 memdraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
56 {
57 	struct Draw d;
58 	Rectangle srcr, tr, mr;
59 	Memlayer *dl, *sl;
60 
61 	if(drawdebug)
62 		iprint("memdraw %p %R %p %P %p %P\n", dst, r, src, p0, mask, p1);
63 
64 	if(mask == nil)
65 		mask = memopaque;
66 
67 	if(mask->layer){
68 if(drawdebug)	iprint("mask->layer != nil\n");
69 		return;	/* too hard, at least for now */
70 	}
71 
72     Top:
73 	if(dst->layer==nil && src->layer==nil){
74 		memimagedraw(dst, r, src, p0, mask, p1, op);
75 		return;
76 	}
77 
78 	if(drawclip(dst, &r, src, &p0, mask, &p1, &srcr, &mr) == 0){
79 if(drawdebug)	iprint("drawclip dstcr %R srccr %R maskcr %R\n", dst->clipr, src->clipr, mask->clipr);
80 		return;
81 	}
82 
83 	/*
84  	 * Convert to screen coordinates.
85 	 */
86 	dl = dst->layer;
87 	if(dl != nil){
88 		r.min.x += dl->delta.x;
89 		r.min.y += dl->delta.y;
90 		r.max.x += dl->delta.x;
91 		r.max.y += dl->delta.y;
92 	}
93     Clearlayer:
94 	if(dl!=nil && dl->clear){
95 		if(src == dst){
96 			p0.x += dl->delta.x;
97 			p0.y += dl->delta.y;
98 			src = dl->screen->image;
99 		}
100 		dst = dl->screen->image;
101 		goto Top;
102 	}
103 
104 	sl = src->layer;
105 	if(sl != nil){
106 		p0.x += sl->delta.x;
107 		p0.y += sl->delta.y;
108 		srcr.min.x += sl->delta.x;
109 		srcr.min.y += sl->delta.y;
110 		srcr.max.x += sl->delta.x;
111 		srcr.max.y += sl->delta.y;
112 	}
113 
114 	/*
115 	 * Now everything is in screen coordinates.
116 	 * mask is an image.  dst and src are images or obscured layers.
117 	 */
118 
119 	/*
120 	 * if dst and src are the same layer, just draw in save area and expose.
121 	 */
122 	if(dl!=nil && dst==src){
123 		if(dl->save == nil)
124 			return;	/* refresh function makes this case unworkable */
125 		if(rectXrect(r, srcr)){
126 			tr = r;
127 			if(srcr.min.x < tr.min.x){
128 				p1.x += tr.min.x - srcr.min.x;
129 				tr.min.x = srcr.min.x;
130 			}
131 			if(srcr.min.y < tr.min.y){
132 				p1.y += tr.min.x - srcr.min.x;
133 				tr.min.y = srcr.min.y;
134 			}
135 			if(srcr.max.x > tr.max.x)
136 				tr.max.x = srcr.max.x;
137 			if(srcr.max.y > tr.max.y)
138 				tr.max.y = srcr.max.y;
139 			memlhide(dst, tr);
140 		}else{
141 			memlhide(dst, r);
142 			memlhide(dst, srcr);
143 		}
144 		memdraw(dl->save, rectsubpt(r, dl->delta), dl->save,
145 			subpt(srcr.min, src->layer->delta), mask, p1, op);
146 		memlexpose(dst, r);
147 		return;
148 	}
149 
150 	if(sl){
151 		if(sl->clear){
152 			src = sl->screen->image;
153 			if(dl != nil){
154 				r.min.x -= dl->delta.x;
155 				r.min.y -= dl->delta.y;
156 				r.max.x -= dl->delta.x;
157 				r.max.y -= dl->delta.y;
158 			}
159 			goto Top;
160 		}
161 		/* relatively rare case; use save area */
162 		if(sl->save == nil)
163 			return;	/* refresh function makes this case unworkable */
164 		memlhide(src, srcr);
165 		/* convert back to logical coordinates */
166 		p0.x -= sl->delta.x;
167 		p0.y -= sl->delta.y;
168 		srcr.min.x -= sl->delta.x;
169 		srcr.min.y -= sl->delta.y;
170 		srcr.max.x -= sl->delta.x;
171 		srcr.max.y -= sl->delta.y;
172 		src = src->layer->save;
173 	}
174 
175 	/*
176 	 * src is now an image.  dst may be an image or a clear layer
177 	 */
178 	if(dst->layer==nil)
179 		goto Top;
180 	if(dst->layer->clear)
181 		goto Clearlayer;
182 
183 	/*
184 	 * dst is an obscured layer
185 	 */
186 	d.deltas = subpt(p0, r.min);
187 	d.deltam = subpt(p1, r.min);
188 	d.dstlayer = dl;
189 	d.src = src;
190 	d.op = op;
191 	d.mask = mask;
192 	_memlayerop(ldrawop, dst, r, r, &d);
193 }
194