xref: /plan9/sys/src/cmd/unix/drawterm/libmemlayer/layerop.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1 #include "../lib9.h"
2 
3 #include "../libdraw/draw.h"
4 #include "../libmemdraw/memdraw.h"
5 #include "../libmemlayer/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
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 		front = front->layer->rear;
30 		goto Top;
31 	}
32 	if(fr.max.y < r.max.y){
33 		RECUR(r.min, fr.max, r.max, r.max);
34 		r.max.y = fr.max.y;
35 	}
36 	if(r.min.y < fr.min.y){
37 		RECUR(r.min, r.min, r.max, fr.min);
38 		r.min.y = fr.min.y;
39 	}
40 	if(fr.max.x < r.max.x){
41 		RECUR(fr.max, r.min, r.max, r.max);
42 		r.max.x = fr.max.x;
43 	}
44 	if(r.min.x < fr.min.x){
45 		RECUR(r.min, r.min, fr.min, r.max);
46 		r.min.x = fr.min.x;
47 	}
48 	/* r is covered by front, so put in save area */
49 	(*fn)(i->layer->save, r, clipr, etc, 1);
50 }
51 
52 /*
53  * Assumes incoming rectangle has already been clipped to i's logical r and clipr
54  */
55 void
56 memlayerop(
57 	void (*fn)(Memimage*, Rectangle, Rectangle, void*, int),
58 	Memimage *i,
59 	Rectangle screenr,	/* clipped to window boundaries */
60 	Rectangle clipr,		/* clipped also to clipping rectangles of hierarchy */
61 	void *etc)
62 {
63 	Memlayer *l;
64 	Rectangle r, scr;
65 
66 	l = i->layer;
67 	if(!rectclip(&screenr, l->screenr))
68 		return;
69 	if(l->clear){
70 		fn(l->screen->image, screenr, clipr, etc, 0);
71 		return;
72 	}
73 	r = screenr;
74 	scr = l->screen->image->clipr;
75 
76 	/*
77 	 * Do the piece on the screen
78 	 */
79 	if(rectclip(&screenr, scr))
80 		_layerop(fn, i, screenr, clipr, etc, l->screen->frontmost);
81 	if(rectinrect(r, scr))
82 		return;
83 
84 	/*
85 	 * Do the piece off the screen
86 	*/
87 	if(!rectXrect(r, scr)){
88 		/* completely offscreen; easy */
89 		fn(l->save, r, clipr, etc, 1);
90 		return;
91 	}
92 	if(r.min.y < scr.min.y){
93 		/* above screen */
94 		fn(l->save, Rect(r.min.x, r.min.y, r.max.x, scr.min.y), clipr, etc, 1);
95 		r.min.y = scr.min.y;
96 	}
97 	if(r.max.y > scr.max.y){
98 		/* below screen */
99 		fn(l->save, Rect(r.min.x, scr.max.y, r.max.x, r.max.y), clipr, etc, 1);
100 		r.max.y = scr.max.y;
101 	}
102 	if(r.min.x < scr.min.x){
103 		/* left of screen */
104 		fn(l->save, Rect(r.min.x, r.min.y, scr.min.x, r.max.y), clipr, etc, 1);
105 		r.min.x = scr.min.x;
106 	}
107 	if(r.max.x > scr.max.x){
108 		/* right of screen */
109 		fn(l->save, Rect(scr.max.x, r.min.y, r.max.x, r.max.y), clipr, etc, 1);
110 	}
111 }
112