gcs.c - sam - An updated version of the sam text editor.
(HTM) git clone git://vernunftzentrum.de/sam.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) LICENSE
---
gcs.c (11581B)
---
1 /* Copyright (c) 1998 Lucent Technologies - All rights reserved. */
2 #include <u.h>
3 #include <libg.h>
4 #include "libgint.h"
5
6 /*
7 * Libg applications are written assuming that black is ~0
8 * and white is 0. Some screens use the reverse convention.
9 * We get the effect the application desired by seeing what
10 * happens if both the source and dest are converted to the
11 * black==~0 convention, and then converting the dest back
12 * to whatever convention it uses.
13 *
14 * Offscreen bitmaps of depth 1 use the black==~0 convention.
15 *
16 * Bitmaps of depth > 1 are probably in color. Libg operations that
17 * would produce a 1 should produce the foreground color, and
18 * libg operations that would produce a 0 should produce the background
19 * color. Operations that use bitmaps of depth > 1 as source
20 * should interpret the foreground pixel as "black" (1) and the
21 * background pixel as "white" (0). It is hard to make this work,
22 * but the important cases are Fcodes Zero, F, S, and S^D, so
23 * we make sure that those work. When a fill value is given for
24 * a bitmap of depth > 1, assume ~0 means foreground, but otherwise
25 * take any other value literally (assume it came from rgbpix).
26 * This may be wrong for the case of 0, but libg programmers
27 * usually use Fcode Zero instead of passing 0 with Fcode S.
28 *
29 * We assume there are at most two depths of bitmaps: depth 1
30 * and depth of the screen.
31 */
32
33 /*
34 * gx func code corresponding to libg func code when both
35 * source and dest use 1 for black. This is a straight translation.
36 */
37 static int gx[16] = {
38 GXclear, /* Zero */
39 GXnor, /* DnorS */
40 GXandInverted, /* DandnotS */
41 GXcopyInverted, /* notS */
42 GXandReverse, /* notDandS */
43 GXinvert, /* notD */
44 GXxor, /* DxorS */
45 GXnand, /* DnandS */
46 GXand, /* DandS */
47 GXequiv, /* DxnorS */
48 GXnoop, /* D */
49 GXorInverted, /* DornotS */
50 GXcopy, /* S */
51 GXorReverse, /* notDorS */
52 GXor, /* DorS */
53 GXset, /* F */
54 };
55
56 /*
57 * gx func code corresponding to libg func code when 0 means black
58 * in dst and 1 means black in src. These means the table has op'
59 * where dst <- dst op' src == not ( not(dst) op src ).
60 * The comment on each line is op, in Fcode terms.
61 */
62 static int d0s1gx[16] = {
63 GXset, /* Zero */
64 GXorReverse, /* DnorS */
65 GXor, /* DandnotS */
66 GXcopy, /* notS */
67 GXnand, /* notDandS */
68 GXinvert, /* notD */
69 GXxor, /* DxorS */
70 GXandReverse, /* DnandS */
71 GXorInverted, /* DandS */
72 GXequiv, /* DxnorS */
73 GXnoop, /* D */
74 GXand, /* DornotS */
75 GXcopyInverted, /* S */
76 GXnor, /* notDorS */
77 GXandInverted, /* DorS */
78 GXclear, /* F */
79 };
80 /*
81 * gx func code corresponding to libg func code when 1 means black
82 * in dst and 0 means black in src. These means the table has op'
83 * where dst <- dst op' src == dst op not(src) )
84 * The comment on each line is op, in Fcode terms.
85 */
86 static int d1s0gx[16] = {
87 GXclear, /* Zero */
88 GXandReverse, /* DnorS */
89 GXand, /* DandnotS */
90 GXcopy, /* notS */
91 GXnor, /* notDandS */
92 GXinvert, /* notD */
93 GXequiv, /* DxorS */
94 GXorReverse, /* DnandS */
95 GXandInverted, /* DandS */
96 GXxor, /* DxnorS */
97 GXnoop, /* D */
98 GXor, /* DornotS */
99 GXcopyInverted, /* S */
100 GXnand, /* notDorS */
101 GXorInverted, /* DorS */
102 GXset, /* F */
103 };
104
105 /*
106 * gx func code corresponding to libg func code when 0 means black
107 * in both the src and the dst. These means the table has op'
108 * where dst <- dst op' src == not (not(dst) op not(src)) )
109 * The comment on each line is op, in Fcode terms.
110 */
111 static int d0s0gx[16] = {
112 GXset, /* Zero */
113 GXnand, /* DnorS */
114 GXorInverted, /* DandnotS */
115 GXcopyInverted, /* notS */
116 GXorReverse, /* notDandS */
117 GXinvert, /* notD */
118 GXequiv, /* DxorS */
119 GXnor, /* DnandS */
120 GXor, /* DandS */
121 GXxor, /* DxnorS */
122 GXnoop, /* D */
123 GXandInverted, /* DornotS */
124 GXcopy, /* S */
125 GXandReverse, /* notDorS */
126 GXand, /* DorS */
127 GXclear, /* F */
128 };
129
130 /*
131 * 1 for those Fcodes that are degenerate (don't involve src)
132 */
133 static int degengc[16] = {
134 1, /* Zero */
135 0, /* DnorS */
136 0, /* DandnotS */
137 0, /* notS */
138 0, /* notDandS */
139 1, /* notD */
140 0, /* DxorS */
141 0, /* DnandS */
142 0, /* DandS */
143 0, /* DxnorS */
144 1, /* D */
145 0, /* DornotS */
146 0, /* S */
147 0, /* notDorS */
148 0, /* DorS */
149 1, /* F */
150 };
151
152 /*
153 * GCs are all for same screen, and depth is either 1 or screen depth.
154 * Return a GC for the depth of b, with values as specified by gcv.
155 *
156 * Also, set (or unset) the clip rectangle if necessary.
157 * (This implementation should be improved if setting a clip rectangle is not rare).
158 */
159 GC
160 _getgc(Bitmap *b, uint64_t gcvm, XGCValues *pgcv)
161 {
162 static GC gc0, gcn;
163 static bool clipset = false;
164 GC g;
165 XRectangle xr;
166
167 g = (b->ldepth==0)? gc0 : gcn;
168 if(!g){
169 g = XCreateGC(_dpy, (Drawable)b->id, gcvm, pgcv);
170 if(b->ldepth==0)
171 gc0 = g;
172 else
173 gcn = g;
174 } else
175 XChangeGC(_dpy, g, gcvm, pgcv);
176 if(b->flag&CLIP){
177 xr.x = b->clipr.min.x;
178 xr.y = b->clipr.min.y;
179 xr.width = Dx(b->clipr);
180 xr.height = Dy(b->clipr);
181 if(b->flag&SHIFT){
182 xr.x -= b->r.min.x;
183 xr.y -= b->r.min.y;
184 }
185 XSetClipRectangles(_dpy, g, 0, 0, &xr, 1, YXBanded);
186 clipset = true;
187 }else if(clipset){
188 pgcv->clip_mask = None;
189 XChangeGC(_dpy, g, GCClipMask, pgcv);
190 clipset = false;
191 }
192 return g;
193 }
194
195 /*
196 * Return a GC that will fill bitmap b using a pixel value v and Fcode f.
197 * Pixel value v is according to libg convention, so 0 means
198 * white (or background) and ~0 means black (or foreground).
199 */
200 GC
201 _getfillgc(Fcode f, Bitmap *b, uint64_t val)
202 {
203 return _getfillgc2(f, b, val, _fgpixel, _bgpixel);
204 }
205
206 GC
207 _getfillgc2(Fcode f, Bitmap *b, uint64_t val, uint64_t fg, uint64_t bg)
208 {
209 int xf, m;
210 uint64_t v, spix, vmax;
211 XGCValues gcv;
212
213 f &= F;
214 vmax = _ld2dmask[b->ldepth];
215 v = val & vmax;
216 spix = v;
217 xf = GXcopy;
218 m = b->flag;
219 if(m & DP1){
220 xf = (m&BL1)? gx[f] : d0s1gx[f];
221 }else{
222 switch(f){
223 case Zero:
224 labZero:
225 spix = bg;
226 break;
227 case F:
228 labF:
229 spix = fg;
230 break;
231 case D:
232 labD:
233 xf = GXnoop;
234 break;
235 case notD:
236 labnotD:
237 xf = GXxor;
238 spix = fg^bg;
239 break;
240 case S:
241 if(val == ~0)
242 spix = fg;
243 else
244 spix = v;
245 break;
246 case notS:
247 if(val == ~0)
248 spix = bg;
249 else
250 spix = v;
251 break;
252 case DxorS:
253 xf = GXxor;
254 if(val == ~0)
255 spix = fg^bg;
256 else
257 spix = v;
258 break;
259 case DxnorS:
260 xf = GXxor;
261 if(val == 0)
262 spix = fg^bg;
263 else
264 spix = v;
265 break;
266 default:
267 /* hard to do anything other than v==0 or v==~0 case */
268 if(v < vmax-v){
269 /* v is closer to 0 than vmax */
270 switch(f&~S){
271 case D&~S: goto labD;
272 case notD&~S: goto labnotD;
273 case Zero&~S: goto labZero;
274 case F&~S: goto labF;
275 }
276 }else{
277 /* v is closer to vmax than 0 */
278 switch(f&S){
279 case D&S: goto labD;
280 case notD&S: goto labnotD;
281 case Zero&S: goto labZero;
282 case F&S: goto labF;
283 }
284 }
285
286 }
287 }
288 gcv.foreground = spix;
289 gcv.function = xf;
290 return _getgc(b, GCForeground|GCFunction, &gcv);
291 }
292
293 /*
294 * Return a GC to be used to copy an area from bitmap sb to
295 * bitmap db. Sometimes the calling function shouldn't use
296 * XCopyArea, but instead should use XCopyPlane or XFillRectangle.
297 * The *bltfunc arg is set to one of UseCopyArea, UseCopyPlane,
298 * UseFillRectangle.
299 */
300 GC
301 _getcopygc(Fcode f, Bitmap *db, Bitmap *sb, int *bltfunc)
302 {
303 return _getcopygc2(f, db, sb, bltfunc, _fgpixel, _bgpixel);
304 }
305
306 GC
307 _getcopygc2(Fcode f, Bitmap *db, Bitmap *sb, int *bltfunc, uint64_t fg, uint64_t bg)
308 {
309 uint64_t spix, df, sf;
310 int xf, c;
311 XGCValues gcv;
312 uint64_t gcvm;
313
314 spix = xf = 0;
315 f &= F;
316 gcvm = 0;
317 df = db->flag;
318 if(degengc[f]){
319 *bltfunc = UseFillRectangle;
320 if(df&SCR || !(df&DP1)){
321 // nothing XXX
322 }else{
323 /* must be DP1 and BL1 */
324 fg = 1;
325 bg = 0;
326 }
327 switch(f){
328 case Zero:
329 xf = GXcopy;
330 spix = bg;
331 break;
332 case F:
333 xf = GXcopy;
334 spix = fg;
335 break;
336 case D:
337 xf = GXnoop;
338 spix = fg;
339 break;
340 case notD:
341 xf = GXxor;
342 spix = fg^bg;
343 break;
344 default:
345 /* ignored */
346 break;
347 }
348 gcv.function = xf;
349 gcv.foreground = spix;
350 gcvm = GCFunction|GCForeground;
351 }else{
352 /* src is involved in f */
353
354 #define code(f1,f2) ((((f1)&(DP1|BL1))<<2)|((f2)&(DP1|BL1)))
355
356 sf = sb->flag;
357 c = code(df,sf);
358 *bltfunc = UseCopyArea;
359 switch(code(df,sf)){
360 case code(DP1|BL1,DP1|BL1):
361 case code(BL1,BL1):
362 xf = gx[f];
363 break;
364 case code(DP1|BL1,DP1):
365 xf = d1s0gx[f];
366 break;
367 case code(DP1,DP1|BL1):
368 xf = d0s1gx[f];
369 break;
370 case code(DP1,DP1):
371 case code(0,0):
372 xf = d0s0gx[f];
373 break;
374 default:
375 /*
376 * One bitmap has depth 1, the other has screen depth.
377 * We know the bitmap must have BL1.
378 * CopyPlane must be used; it won't really work
379 * for more than fcode==S.
380 */
381
382 *bltfunc = UseCopyPlane;
383 xf = GXcopy;
384 switch(c){
385
386 case code(0,DP1|BL1):
387 case code(BL1,DP1|BL1):
388 // nothing XXX
389 break;
390 case code(DP1|BL1,0):
391 fg = 0;
392 bg = 1;
393 break;
394 case code(DP1|BL1,BL1):
395 fg = 1;
396 bg = 0;
397 break;
398 default:
399 berror("bad combination of copy bitmaps");
400 }
401 gcv.foreground = fg;
402 gcv.background = bg;
403 gcvm |= GCForeground|GCBackground;
404 }
405 gcv.function = xf;
406 gcvm |= GCFunction;
407
408 #undef code
409 }
410
411 return _getgc(db, gcvm, &gcv);
412 }