gcs.c - sam - An updated version of the sam text editor. | |
git clone git://vernunftzentrum.de/sam.git | |
Log | |
Files | |
Refs | |
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 i… | |
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, … | |
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 } |