1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <memlayer.h>
6 
7 #define	RECUR(a,b,c,d)	_layerop(fn, i, Rect(a.x, b.y, c.x, d.y), clipr, etc, front->layer->rear);
8 
9 static void
_layerop(void (* fn)(Memimage *,Rectangle,Rectangle,void *,int),Memimage * i,Rectangle r,Rectangle clipr,void * etc,Memimage * front)10 _layerop(
11 	void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
12 	Memimage *i,
13 	Rectangle r,
14 	Rectangle clipr,
15 	void *etc,
16 	Memimage *front)
17 {
18 	Rectangle fr;
19 
20     Top:
21 	if(front == i){
22 		/* no one is in front of this part of window; use the screen */
23 		fn(i->layer->screen->image, r, clipr, etc, 0);
24 		return;
25 	}
26 	fr = front->layer->screenr;
27 	if(rectXrect(r, fr) == 0){
28 		/* r doesn't touch this window; continue on next rearmost */
29 		// assert(front && front->layer && front->layer->screen && front->layer->rear);
30 		front = front->layer->rear;
31 		goto Top;
32 	}
33 	if(fr.max.y < r.max.y){
34 		RECUR(r.min, fr.max, r.max, r.max);
35 		r.max.y = fr.max.y;
36 	}
37 	if(r.min.y < fr.min.y){
38 		RECUR(r.min, r.min, r.max, fr.min);
39 		r.min.y = fr.min.y;
40 	}
41 	if(fr.max.x < r.max.x){
42 		RECUR(fr.max, r.min, r.max, r.max);
43 		r.max.x = fr.max.x;
44 	}
45 	if(r.min.x < fr.min.x){
46 		RECUR(r.min, r.min, fr.min, r.max);
47 		r.min.x = fr.min.x;
48 	}
49 	/* r is covered by front, so put in save area */
50 	(*fn)(i->layer->save, r, clipr, etc, 1);
51 }
52 
53 /*
54  * Assumes incoming rectangle has already been clipped to i's logical r and clipr
55  */
56 void
_memlayerop(void (* fn)(Memimage *,Rectangle,Rectangle,void *,int),Memimage * i,Rectangle screenr,Rectangle clipr,void * etc)57 _memlayerop(
58 	void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
59 	Memimage *i,
60 	Rectangle screenr,	/* clipped to window boundaries */
61 	Rectangle clipr,		/* clipped also to clipping rectangles of hierarchy */
62 	void *etc)
63 {
64 	Memlayer *l;
65 	Rectangle r, scr;
66 
67 	l = i->layer;
68 	if(!rectclip(&screenr, l->screenr))
69 		return;
70 	if(l->clear){
71 		fn(l->screen->image, screenr, clipr, etc, 0);
72 		return;
73 	}
74 	r = screenr;
75 	scr = l->screen->image->clipr;
76 
77 	/*
78 	 * Do the piece on the screen
79 	 */
80 	if(rectclip(&screenr, scr))
81 		_layerop(fn, i, screenr, clipr, etc, l->screen->frontmost);
82 	if(rectinrect(r, scr))
83 		return;
84 
85 	/*
86 	 * Do the piece off the screen
87 	*/
88 	if(!rectXrect(r, scr)){
89 		/* completely offscreen; easy */
90 		fn(l->save, r, clipr, etc, 1);
91 		return;
92 	}
93 	if(r.min.y < scr.min.y){
94 		/* above screen */
95 		fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1);
96 		r.min.y = scr.min.y;
97 	}
98 	if(r.max.y > scr.max.y){
99 		/* below screen */
100 		fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1);
101 		r.max.y = scr.max.y;
102 	}
103 	if(r.min.x < scr.min.x){
104 		/* left of screen */
105 		fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1);
106 		r.min.x = scr.min.x;
107 	}
108 	if(r.max.x > scr.max.x){
109 		/* right of screen */
110 		fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1);
111 	}
112 }
113