|
|
1.1 root 1: #include "u.h"
2: #include "../port/lib.h"
3: #include <libg.h>
4: #include <gnot.h>
5: #include "mem.h"
6: #include "dat.h"
7: #include "fns.h"
8: #include "../port/error.h"
9:
10: #include "devtab.h"
11:
12: #include "screen.h"
13:
14: /*
15: * Some monochrome screens are reversed from what we like:
16: * We want 0's bright and 1's dark.
17: * Indexed by an Fcode, these compensate for the source bitmap being wrong
18: * (exchange S rows) and destination (exchange D columns and invert result)
19: */
20: int flipS[] = {
21: 0x0, 0x4, 0x8, 0xC, 0x1, 0x5, 0x9, 0xD,
22: 0x2, 0x6, 0xA, 0xE, 0x3, 0x7, 0xB, 0xF
23: };
24:
25: int flipD[] = {
26: 0xF, 0xD, 0xE, 0xC, 0x7, 0x5, 0x6, 0x4,
27: 0xB, 0x9, 0xA, 0x8, 0x3, 0x1, 0x2, 0x0,
28: };
29:
30: int flipping; /* are flip tables being used to transform Fcodes? */
31:
32: /*
33: * Device (#b/bitblt) is exclusive use on open, so no locks are necessary
34: * for i/o
35: */
36:
37: /*
38: * Arena is a word containing N, followed by a pointer to the Arena,
39: * followed by a pointer to the Bitmap, followed by N words.
40: * The bitmap pointer is zero if block is free.
41: * bit.map is an array of pointers to GBitmaps. The GBitmaps are
42: * freed individually and their corresponding entries in bit.map are zeroed.
43: * The index into bit.map is the Bitmap id as seen in libg. Subfonts and
44: * fonts are handled similarly.
45: */
46:
47: typedef struct Arena Arena;
48: struct Arena
49: {
50: ulong *words; /* storage */
51: ulong *wfree; /* pointer to next free word */
52: ulong nwords; /* total in arena */
53: int nbusy; /* number of busy blocks */
54: };
55:
56: typedef struct BSubfont BSubfont;
57: struct BSubfont
58: {
59: GSubfont;
60: int ref; /* number of times this subfont is open */
61: ulong qid[2]; /* unique id used as a cache tag */
62: };
63:
64: extern GSubfont *defont;
65: BSubfont *bdefont;
66: BSubfont bdefont0;
67:
68:
69: struct
70: {
71: Ref;
72: QLock;
73: GBitmap **map; /* indexed array */
74: int nmap; /* number allocated */
75: GFont **font; /* indexed array */
76: int nfont; /* number allocated */
77: BSubfont**subfont; /* indexed array */
78: int nsubfont; /* number allocated */
79: Arena *arena; /* array */
80: int narena; /* number allocated */
81: int mouseopen; /* flag: mouse open */
82: int bitbltopen; /* flag: bitblt open */
83: int bid; /* last allocated bitmap id */
84: int subfid; /* last allocated subfont id */
85: int cacheid; /* last cached subfont id */
86: int fid; /* last allocated font id */
87: int init; /* freshly opened; init message pending */
88: int rid; /* read bitmap id */
89: int rminy; /* read miny */
90: int rmaxy; /* read maxy */
91: int mid; /* colormap read bitmap id */
92: }bit;
93:
94: #define DMAP 16 /* delta increase in size of arrays */
95: #define FREE 0x80000000
96:
97: void bitcompact(void);
98: int bitalloc(Rectangle, int);
99: void bitfree(GBitmap*);
100: void fontfree(GFont*);
101: void subfontfree(BSubfont*, int);
102: void arenafree(Arena*);
103: void bitstring(GBitmap*, Point, GFont*, uchar*, long, Fcode);
104: void bitloadchar(GFont*, int, GSubfont*, int);
105: extern GBitmap gscreen;
106:
107: typedef struct Mouseinfo Mouseinfo;
108: typedef struct Cursorinfo Cursorinfo;
109:
110: struct Mouseinfo{
111: /*
112: * First three fields are known in some l.s's
113: */
114: int dx;
115: int dy;
116: int track; /* l.s has updated dx & dy */
117: Mouse;
118: int redraw; /* update cursor on screen */
119: ulong counter; /* increments every update */
120: ulong lastcounter; /* value when /dev/mouse read */
121: Rendez r;
122: };
123:
124: struct Cursorinfo{
125: Cursor;
126: Lock;
127: int visible; /* on screen */
128: Rectangle r; /* location */
129: };
130:
131: Mouseinfo mouse;
132: Cursorinfo cursor;
133: Cursor curs;
134: int mouseshifted;
135: int mousetype;
136: int mouseswap;
137: int islittle;
138: int hwcurs;
139:
140: Cursor arrow =
141: {
142: {-1, -1},
143: {0xFF, 0xE0, 0xFF, 0xE0, 0xFF, 0xC0, 0xFF, 0x00,
144: 0xFF, 0x00, 0xFF, 0x80, 0xFF, 0xC0, 0xFF, 0xE0,
145: 0xE7, 0xF0, 0xE3, 0xF8, 0xC1, 0xFC, 0x00, 0xFE,
146: 0x00, 0x7F, 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08,
147: },
148: {0x00, 0x00, 0x7F, 0xC0, 0x7F, 0x00, 0x7C, 0x00,
149: 0x7E, 0x00, 0x7F, 0x00, 0x6F, 0x80, 0x67, 0xC0,
150: 0x43, 0xE0, 0x41, 0xF0, 0x00, 0xF8, 0x00, 0x7C,
151: 0x00, 0x3E, 0x00, 0x1C, 0x00, 0x08, 0x00, 0x00,
152: }
153: };
154:
155: ulong setbits[16];
156: GBitmap set =
157: {
158: setbits,
159: 0,
160: 1,
161: 0,
162: {0, 0, 16, 16},
163: {0, 0, 16, 16}
164: };
165:
166: ulong clrbits[16];
167: GBitmap clr =
168: {
169: clrbits,
170: 0,
171: 1,
172: 0,
173: {0, 0, 16, 16},
174: {0, 0, 16, 16}
175: };
176:
177: ulong cursorbackbits[16*4];
178: GBitmap cursorback =
179: {
180: cursorbackbits,
181: 0,
182: 1,
183: 0,
184: {0, 0, 16, 16},
185: {0, 0, 16, 16}
186: };
187:
188: void Cursortocursor(Cursor*);
189: int mousechanged(void*);
190:
191: enum{
192: Qdir,
193: Qbitblt,
194: Qmouse,
195: Qmousectl,
196: Qscreen,
197: };
198:
199: Dirtab bitdir[]={
200: "bitblt", {Qbitblt}, 0, 0666,
201: "mouse", {Qmouse}, 0, 0666,
202: "mousectl", {Qmousectl}, 0, 0220,
203: "screen", {Qscreen}, 0, 0444,
204: };
205:
206: #define NBIT (sizeof bitdir/sizeof(Dirtab))
207: #define NINFO 8192 /* max chars per subfont; sanity check only */
208: #define HDR 3
209:
210: void
211: lockedupdate(void)
212: {
213: qlock(&bit);
214: if(waserror()){
215: qunlock(&bit);
216: return;
217: }
218: screenupdate();
219: qunlock(&bit);
220: poperror();
221: }
222:
223: void
224: bitfreeup(void)
225: {
226: int i;
227: BSubfont *s;
228:
229: /* free unused subfonts and compact */
230: for(i=0; i<bit.nsubfont; i++){
231: s = bit.subfont[i];
232: if(s && s!=bdefont && s->ref==0){
233: s->ref = 1;
234: s->qid[0] = ~0; /* force cleanup */
235: subfontfree(s, i);
236: }
237: }
238: bitcompact();
239: }
240:
241: void*
242: bitmalloc(ulong n)
243: {
244: void *p;
245:
246: p = malloc(n);
247: if(p)
248: return p;
249: bitfreeup();
250: return malloc(n);
251: }
252:
253: void
254: bitdebug(void)
255: {
256: int i;
257: long l;
258: Arena *a;
259:
260: l = 0;
261: for(i=0; i<bit.narena; i++){
262: a = &bit.arena[i];
263: if(a->words){
264: l += a->nwords;
265: print("%d: %ld bytes used; %ld total\n", i,
266: (a->wfree-a->words)*sizeof(ulong),
267: a->nwords*sizeof(ulong));
268: }
269: }
270: print("arena: %ld bytes\n", l*sizeof(ulong));
271: l = 0;
272: for(i=0; i<bit.nmap; i++)
273: if(bit.map[i])
274: l++;
275: print("%d bitmaps ", l);
276: l = 0;
277: for(i=0; i<bit.nfont; i++)
278: if(bit.font[i])
279: l++;
280: print("%d fonts ", l);
281: l = 0;
282: for(i=0; i<bit.nsubfont; i++)
283: if(bit.subfont[i]){
284: print("%d: %lux %lux ", i, bit.subfont[i]->qid[0], bit.subfont[i]->qid[1]);
285: l++;
286: }
287: print("%d subfonts\n", l);
288: }
289:
290: void
291: bitreset(void)
292: {
293: int ws;
294: ulong r;
295: Arena *a;
296:
297: if(!conf.monitor)
298: return;
299:
300: memmove(&bdefont0, defont, sizeof(*defont));
301: bdefont = &bdefont0;
302: bit.map = smalloc(DMAP*sizeof(GBitmap*));
303: bit.nmap = DMAP;
304: getcolor(0, &r, &r, &r);
305: if(r == 0)
306: flipping = 1;
307: bit.bid = -1;
308: bit.subfid = -1;
309: bit.fid = -1;
310: bit.cacheid = -1;
311: bit.font = smalloc(DMAP*sizeof(GFont*));
312: bit.nfont = DMAP;
313: bit.subfont = smalloc(DMAP*sizeof(BSubfont*));
314: bit.nsubfont = DMAP;
315: bit.arena = smalloc(DMAP*sizeof(Arena));
316: bit.narena = DMAP;
317: a = &bit.arena[0];
318: /*
319: * Somewhat of a heuristic: start with three screensful and
320: * allocate single screensful dynamically if needed.
321: */
322:
323: ws = BI2WD>>gscreen.ldepth; /* pixels per word */
324: a->nwords = 3*(HDR + gscreen.r.max.y*gscreen.r.max.x/ws);
325: a->words = xalloc(a->nwords*sizeof(ulong));
326: if(a->words == 0){
327: /* try again */
328: print("bitreset: allocating only 1 screenful\n");
329: a->nwords /= 3;
330: a->words = a->words = xalloc(a->nwords*sizeof(ulong));
331: if(a->words == 0)
332: panic("bitreset");
333: }
334: a->wfree = a->words;
335: a->nbusy = 1; /* keep 0th arena from being freed */
336: Cursortocursor(&arrow);
337: }
338:
339: /*
340: * screen bit depth changed, reset backup map for cursor
341: */
342: void
343: bitdepth(void)
344: {
345: cursoroff(1);
346: if(gscreen.ldepth > 3)
347: cursorback.ldepth = 0;
348: else{
349: cursorback.ldepth = gscreen.ldepth;
350: cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5;
351: }
352: cursoron(1);
353: }
354:
355: void
356: bitinit(void)
357: {
358: if(!conf.monitor)
359: return;
360: if(gscreen.ldepth > 3)
361: cursorback.ldepth = 0;
362: else{
363: cursorback.ldepth = gscreen.ldepth;
364: cursorback.width = ((16 << gscreen.ldepth) + 31) >> 5;
365: }
366: cursoron(1);
367: }
368:
369: Chan*
370: bitattach(char *spec)
371: {
372: if(!conf.monitor)
373: error(Egreg);
374: return devattach('b', spec);
375: }
376:
377: Chan*
378: bitclone(Chan *c, Chan *nc)
379: {
380: if(!conf.monitor)
381: error(Egreg);
382: nc = devclone(c, nc);
383: if(c->qid.path != CHDIR)
384: incref(&bit);
385: return nc;
386: }
387:
388: int
389: bitwalk(Chan *c, char *name)
390: {
391: if(!conf.monitor)
392: error(Egreg);
393: return devwalk(c, name, bitdir, NBIT, devgen);
394: }
395:
396: void
397: bitstat(Chan *c, char *db)
398: {
399: if(!conf.monitor)
400: error(Egreg);
401: devstat(c, db, bitdir, NBIT, devgen);
402: }
403:
404: Chan*
405: bitopen(Chan *c, int omode)
406: {
407: GBitmap *b;
408:
409: if(!conf.monitor)
410: error(Egreg);
411: switch(c->qid.path){
412: case CHDIR:
413: if(omode != OREAD)
414: error(Eperm);
415: break;
416: case Qmouse:
417: lock(&bit);
418: if(bit.mouseopen){
419: unlock(&bit);
420: error(Einuse);
421: }
422: bit.mouseopen = 1;
423: bit.ref++;
424: unlock(&bit);
425: break;
426: case Qbitblt:
427: lock(&bit);
428: if(bit.bitbltopen || bit.mouseopen){
429: unlock(&bit);
430: error(Einuse);
431: }
432: b = smalloc(sizeof(GBitmap));
433: *b = gscreen;
434: bit.map[0] = b; /* bitmap 0 is screen */
435: bit.subfont[0] = bdefont; /* subfont 0 is default */
436: bit.subfont[0]->ref = 1;
437: bit.subfont[0]->qid[0] = 0;
438: bit.subfont[0]->qid[1] = 0;
439: bit.bid = -1;
440: bit.fid = -1;
441: bit.subfid = -1;
442: bit.cacheid = -1;
443: bit.rid = -1;
444: bit.mid = -1;
445: bit.init = 0;
446: bit.bitbltopen = 1;
447: Cursortocursor(&arrow);
448: unlock(&bit);
449: break;
450: default:
451: incref(&bit);
452: }
453: c->mode = openmode(omode);
454: c->flag |= COPEN;
455: c->offset = 0;
456: return c;
457: }
458:
459: void
460: bitcreate(Chan *c, char *name, int omode, ulong perm)
461: {
462: if(!conf.monitor)
463: error(Egreg);
464: USED(c, name, omode, perm);
465: error(Eperm);
466: }
467:
468: void
469: bitremove(Chan *c)
470: {
471: if(!conf.monitor)
472: error(Egreg);
473: USED(c);
474: error(Eperm);
475: }
476:
477: void
478: bitwstat(Chan *c, char *db)
479: {
480: if(!conf.monitor)
481: error(Egreg);
482: USED(c, db);
483: error(Eperm);
484: }
485:
486: void
487: bitclose(Chan *c)
488: {
489: GBitmap *b, **bp, **ebp;
490: BSubfont *s, **sp, **esp;
491: GFont *f, **fp, **efp;
492:
493: if(!conf.monitor)
494: error(Egreg);
495: if(c->qid.path!=CHDIR && (c->flag&COPEN)){
496: lock(&bit);
497: if(c->qid.path == Qmouse)
498: bit.mouseopen = 0;
499: if(c->qid.path == Qbitblt)
500: bit.bitbltopen = 0;
501: if(--bit.ref == 0){
502: ebp = &bit.map[bit.nmap];
503: for(bp = bit.map; bp<ebp; bp++){
504: b = *bp;
505: if(b){
506: bitfree(b);
507: *bp = 0;
508: }
509: }
510: esp = &bit.subfont[bit.nsubfont];
511: for(sp=bit.subfont; sp<esp; sp++){
512: s = *sp;
513: if(s)
514: subfontfree(s, sp-bit.subfont);
515: /* don't clear *sp: cached */
516: }
517: efp = &bit.font[bit.nfont];
518: for(fp=bit.font; fp<efp; fp++){
519: f = *fp;
520: if(f){
521: fontfree(f);
522: *fp = 0;
523: }
524: }
525: }
526: unlock(&bit);
527: }
528: }
529:
530: long
531: bitread(Chan *c, void *va, long n, ulong offset)
532: {
533: uchar *p, *q;
534: long miny, maxy, t, x, y;
535: ulong l, nw, ws, rv, gv, bv;
536: int off, j;
537: Fontchar *i;
538: GBitmap *src;
539: BSubfont *s;
540: static int map[8] = {0, 4, 2, 6, 1, 5, 3, 7 };
541:
542: if(!conf.monitor)
543: error(Egreg);
544: if(c->qid.path & CHDIR)
545: return devdirread(c, va, n, bitdir, NBIT, devgen);
546:
547: if(c->qid.path == Qmouse){
548: /*
549: * mouse:
550: * 'm' 1
551: * buttons 1
552: * point 8
553: * msec 4
554: */
555: if(n < 14)
556: error(Ebadblt);
557: while(mousechanged(0) == 0)
558: sleep(&mouse.r, mousechanged, 0);
559: lock(&cursor);
560: p = va;
561: p[0] = 'm';
562: p[1] = mouseswap ? map[mouse.buttons&7] : mouse.buttons;
563: BPLONG(p+2, mouse.xy.x);
564: BPLONG(p+6, mouse.xy.y);
565: BPLONG(p+10, TK2MS(MACHP(0)->ticks));
566: mouse.lastcounter = mouse.counter;
567: unlock(&cursor);
568: return 14;
569: }
570: if(c->qid.path == Qscreen){
571: if(offset==0){
572: if(n < 5*12)
573: error(Eio);
574: sprint(va, "%11d %11d %11d %11d %11d ",
575: gscreen.ldepth, gscreen.r.min.x,
576: gscreen.r.min.y, gscreen.r.max.x,
577: gscreen.r.max.y);
578: return 5*12;
579: }
580: ws = 1<<(3-gscreen.ldepth); /* pixels per byte */
581: l = (gscreen.r.max.x+ws-1)/ws - gscreen.r.min.x/ws;
582: if(l == 0)
583: error(Ebadblt);
584: t = offset-5*12;
585: miny = t/l; /* unsigned computation */
586: maxy = (t+n)/l;
587: if(miny >= gscreen.r.max.y)
588: return 0;
589: if(maxy >= gscreen.r.max.y)
590: maxy = gscreen.r.max.y;
591: n = 0;
592: p = va;
593: for(y=miny; y<maxy; y++){
594: q = (uchar*)gaddr(&gscreen, Pt(0, y));
595: memmove(p, q, l);
596: if(flipping)
597: /* is screen, so must be word aligned */
598: for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong))
599: *(ulong*)p ^= ~0;
600: else
601: p += l;
602: n += l;
603: }
604: return n;
605: }
606: if(c->qid.path != Qbitblt)
607: error(Egreg);
608:
609: qlock(&bit);
610: if(waserror()){
611: qunlock(&bit);
612: nexterror();
613: }
614: p = va;
615: /*
616: * Fuss about and figure out what to say.
617: */
618: if(bit.init){
619: /*
620: * init:
621: * 'I' 1
622: * ldepth 1
623: * rectangle 16
624: * clip rectangle 16
625: * font info 3*12
626: * fontchars 6*(bdefont->n+1)
627: */
628: if(n < 34)
629: error(Ebadblt);
630: p[0] = 'I';
631: p[1] = gscreen.ldepth;
632: BPLONG(p+2, gscreen.r.min.x);
633: BPLONG(p+6, gscreen.r.min.y);
634: BPLONG(p+10, gscreen.r.max.x);
635: BPLONG(p+14, gscreen.r.max.y);
636: BPLONG(p+18, gscreen.clipr.min.x);
637: BPLONG(p+22, gscreen.clipr.min.y);
638: BPLONG(p+26, gscreen.clipr.max.x);
639: BPLONG(p+30, gscreen.clipr.max.y);
640: if(n >= 34+3*12+6*(bdefont->n+1)){
641: p += 34;
642: sprint((char*)p, "%11d %11d %11d ", bdefont->n,
643: bdefont->height, bdefont->ascent);
644: p += 3*12;
645: for(i=bdefont->info,j=0; j<=bdefont->n; j++,i++,p+=6){
646: BPSHORT(p, i->x);
647: p[2] = i->top;
648: p[3] = i->bottom;
649: p[4] = i->left;
650: p[5] = i->width;
651: }
652: n = 34+3*12+6*(bdefont->n+1);
653: }else
654: n = 34;
655: bit.init = 0;
656: }else if(bit.bid > 0){
657: /*
658: * allocate:
659: * 'A' 1
660: * bitmap id 2
661: */
662: if(n < 3)
663: error(Ebadblt);
664: if(bit.bid<0 || bit.map[bit.bid]==0)
665: error(Ebadbitmap);
666: p[0] = 'A';
667: BPSHORT(p+1, bit.bid);
668: bit.bid = -1;
669: n = 3;
670: }else if(bit.subfid > 0){
671: /*
672: * allocate subfont:
673: * 'K' 1
674: * subfont id 2
675: */
676: if(n<3 || bit.subfid<0)
677: error(Ebadblt);
678: s = bit.subfont[bit.subfid];
679: if(s==0 || s->ref==0)
680: error(Ebadfont);
681: p[0] = 'K';
682: BPSHORT(p+1, bit.subfid);
683: bit.subfid = -1;
684: n = 3;
685: }else if(bit.cacheid >= 0){
686: /*
687: * check cache for subfont:
688: * 'J' 1
689: * subfont id 2
690: * font info 3*12
691: * fontchars 6*(subfont->n+1)
692: */
693: p[0] = 'J';
694: if(bit.cacheid < 0)
695: error(Ebadfont);
696: s = bit.subfont[bit.cacheid];
697: if(s==0 || s->ref==0)
698: error(Ebadfont);
699: if(n < 3+3*12+6*(s->n+1))
700: error(Ebadblt);
701: BPSHORT(p+1, bit.cacheid);
702: p += 3;
703: sprint((char*)p, "%11d %11d %11d ", s->n, s->height, s->ascent);
704: p += 3*12;
705: for(i=s->info,j=0; j<=s->n; j++,i++,p+=6){
706: BPSHORT(p, i->x);
707: p[2] = i->top;
708: p[3] = i->bottom;
709: p[4] = i->left;
710: p[5] = i->width;
711: }
712: n = 3+3*12+6*(s->n+1);
713: bit.cacheid = -1;
714: }else if(bit.fid >= 0){
715: /*
716: * allocate font:
717: * 'N' 1
718: * font id 2
719: */
720: if(n < 3)
721: error(Ebadblt);
722: if(bit.fid<0 || bit.font[bit.fid]==0)
723: error(Ebadfont);
724: p[0] = 'N';
725: BPSHORT(p+1, bit.fid);
726: bit.fid = -1;
727: n = 3;
728: }else if(bit.mid >= 0){
729: /*
730: * read colormap:
731: * data 12*(2**bitmapdepth)
732: */
733: src = bit.map[bit.mid];
734: if(src == 0)
735: error(Ebadbitmap);
736: l = (1<<src->ldepth);
737: nw = 1 << l;
738: if(n < 12*nw)
739: error(Ebadblt);
740: for(j = 0; j < nw; j++){
741: if(bit.mid == 0){
742: getcolor(flipping? nw-j-1 : j, &rv, &gv, &bv);
743: }else{
744: rv = j;
745: for(off = 32-l; off > 0; off -= l)
746: rv = (rv << l) | j;
747: gv = bv = rv;
748: }
749: BPLONG(p, rv);
750: BPLONG(p+4, gv);
751: BPLONG(p+8, bv);
752: p += 12;
753: }
754: bit.mid = -1;
755: n = 12*nw;
756: }else if(bit.rid >= 0){
757: /*
758: * read bitmap:
759: * data bytewidth*(maxy-miny)
760: */
761: src = bit.map[bit.rid];
762: if(src == 0)
763: error(Ebadbitmap);
764: off = 0;
765: if(bit.rid == 0)
766: off = 1;
767: miny = bit.rminy;
768: maxy = bit.rmaxy;
769: if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
770: error(Ebadblt);
771: ws = 1<<(3-src->ldepth); /* pixels per byte */
772: /* set l to number of bytes of incoming data per scan line */
773: if(src->r.min.x >= 0)
774: l = (src->r.max.x+ws-1)/ws - src->r.min.x/ws;
775: else{ /* make positive before divide */
776: t = (-src->r.min.x)+ws-1;
777: t = (t/ws)*ws;
778: l = (t+src->r.max.x+ws-1)/ws;
779: }
780: if(n < l*(maxy-miny))
781: error(Ebadblt);
782: if(off)
783: cursoroff(1);
784: n = 0;
785: p = va;
786: for(y=miny; y<maxy; y++){
787: q = (uchar*)gaddr(src, Pt(src->r.min.x, y));
788: q += (src->r.min.x&((sizeof(ulong))*ws-1))/ws;
789: memmove(p, q, l);
790: if(islittle)
791: pixreverse(p, l, src->ldepth);
792: if(bit.rid==0 && flipping)
793: /* is screen, so must be word aligned */
794: for(x=0; x<l; x+=sizeof(ulong),p+=sizeof(ulong))
795: *(ulong*)p ^= ~0;
796: else
797: p += l;
798: n += l;
799: }
800: if(off)
801: cursoron(1);
802: bit.rid = -1;
803: }
804:
805: poperror();
806: qunlock(&bit);
807: return n;
808: }
809:
810: Point
811: bitstrsize(GFont *f, uchar *p, int l)
812: {
813: ushort r;
814: Point s = {0,0};
815: GCacheinfo *c;
816:
817: while(l > 0){
818: r = BGSHORT(p);
819: p += 2;
820: l -= 2;
821: if(r >= f->ncache)
822: continue;
823: c = &f->cache[r];
824: if(c->bottom > s.y)
825: s.y = c->bottom;
826: s.x += c->width;
827: }
828: return s;
829: }
830:
831: long
832: bitwrite(Chan *c, void *va, long n, ulong offset)
833: {
834: uchar *p, *q, *oq;
835: long m, v, miny, maxy, t, x, y;
836: ulong l, nw, ws, rv, q0, q1;
837: ulong *lp;
838: int off, isoff, i, j, ok;
839: ulong *endscreen = gaddr(&gscreen, Pt(0, gscreen.r.max.y));
840: Point pt, pt1, pt2;
841: Rectangle rect;
842: Fcode fc;
843: Fontchar *fcp;
844: GBitmap *src, *dst;
845: BSubfont *f, *tf, **fp;
846: GFont *ff, **ffp;
847: GCacheinfo *gc;
848: char buf[64];
849:
850: if(!conf.monitor)
851: error(Egreg);
852: USED(offset);
853:
854: if(c->qid.path == CHDIR)
855: error(Eisdir);
856:
857: if(c->qid.path == Qmousectl){
858: if(n >= sizeof(buf))
859: n = sizeof(buf)-1;
860: strncpy(buf, va, n);
861: buf[n] = 0;
862: mousectl(buf);
863: return n;
864: }
865:
866: if(c->qid.path != Qbitblt)
867: error(Egreg);
868:
869: isoff = 0;
870: qlock(&bit);
871: if(waserror()){
872: qunlock(&bit);
873: if(isoff)
874: cursoron(1);
875: nexterror();
876: }
877: p = va;
878: m = n;
879: SET(src, dst, f, ff);
880: while(m > 0)
881: switch(*p){
882: default:
883: pprint("bitblt request 0x%x\n", *p);
884: error(Ebadblt);
885:
886: case 'a':
887: /*
888: * allocate:
889: * 'a' 1
890: * ldepth 1
891: * Rectangle 16
892: * next read returns allocated bitmap id
893: */
894: if(m < 18)
895: error(Ebadblt);
896: v = *(p+1);
897: if(v > 3) /* BUG */
898: error(Ebadblt);
899: rect.min.x = BGLONG(p+2);
900: rect.min.y = BGLONG(p+6);
901: rect.max.x = BGLONG(p+10);
902: rect.max.y = BGLONG(p+14);
903: if(Dx(rect) < 0 || Dy(rect) < 0)
904: error(Ebadblt);
905: bit.bid = bitalloc(rect, v);
906: m -= 18;
907: p += 18;
908: break;
909:
910: case 'b':
911: /*
912: * bitblt
913: * 'b' 1
914: * dst id 2
915: * dst Point 8
916: * src id 2
917: * src Rectangle 16
918: * code 2
919: */
920: if(m < 31)
921: error(Ebadblt);
922: fc = BGSHORT(p+29) & 0xF;
923: v = BGSHORT(p+11);
924: if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
925: error(Ebadbitmap);
926: off = 0;
927: if(v == 0){
928: if(flipping)
929: fc = flipS[fc];
930: off = 1;
931: }
932: v = BGSHORT(p+1);
933: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
934: error(Ebadbitmap);
935: if(v == 0){
936: if(flipping)
937: fc = flipD[fc];
938: off = 1;
939: }
940: pt.x = BGLONG(p+3);
941: pt.y = BGLONG(p+7);
942: rect.min.x = BGLONG(p+13);
943: rect.min.y = BGLONG(p+17);
944: rect.max.x = BGLONG(p+21);
945: rect.max.y = BGLONG(p+25);
946: if(off && !isoff){
947: cursoroff(1);
948: isoff = 1;
949: }
950: gbitblt(dst, pt, src, rect, fc);
951: if(dst->base < endscreen)
952: mbbrect(Rpt(pt, add(pt, sub(rect.max, rect.min))));
953: m -= 31;
954: p += 31;
955: break;
956:
957: case 'c':
958: /*
959: * cursorswitch
960: * 'c' 1
961: * if nothing more: return to arrow; else
962: * Point 8
963: * clr 32
964: * set 32
965: */
966: if(m == 1){
967: if(!isoff){
968: cursoroff(1);
969: isoff = 1;
970: }
971: Cursortocursor(&arrow);
972: m -= 1;
973: p += 1;
974: break;
975: }
976: if(m < 73)
977: error(Ebadblt);
978: curs.offset.x = BGLONG(p+1);
979: curs.offset.y = BGLONG(p+5);
980: memmove(curs.clr, p+9, 2*16);
981: memmove(curs.set, p+41, 2*16);
982: if(islittle){
983: pixreverse(curs.clr, 2*16, 0);
984: pixreverse(curs.set, 2*16, 0);
985: }
986: if(!isoff){
987: cursoroff(1);
988: isoff = 1;
989: }
990: Cursortocursor(&curs);
991: m -= 73;
992: p += 73;
993: break;
994:
995: case 'e':
996: /*
997: * polysegment
998: *
999: * 'e' 1
1000: * id 2
1001: * pt 8
1002: * value 1
1003: * code 2
1004: * n 2
1005: * pts 2*n
1006: */
1007: if(m < 16)
1008: error(Ebadblt);
1009: l = BGSHORT(p+14);
1010: if(m < 16+2*l)
1011: error(Ebadblt);
1012: v = BGSHORT(p+1);
1013: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1014: error(Ebadbitmap);
1015: off = 0;
1016: fc = BGSHORT(p+12) & 0xF;
1017: if(v == 0){
1018: if(flipping)
1019: fc = flipD[fc];
1020: off = 1;
1021: }
1022: pt1.x = BGLONG(p+3);
1023: pt1.y = BGLONG(p+7);
1024: t = p[11];
1025: if(off && !isoff){
1026: cursoroff(1);
1027: isoff = 1;
1028: }
1029: p += 16;
1030: m -= 16;
1031: while(l > 0){
1032: pt2.x = pt1.x + (schar)p[0];
1033: pt2.y = pt1.y + (schar)p[1];
1034: gsegment(dst, pt1, pt2, t, fc);
1035: if(dst->base < endscreen){
1036: mbbpt(pt1);
1037: mbbpt(pt2);
1038: }
1039: pt1 = pt2;
1040: p += 2;
1041: m -= 2;
1042: l--;
1043: }
1044: break;
1045:
1046: case 'f':
1047: /*
1048: * free
1049: * 'f' 1
1050: * id 2
1051: */
1052: if(m < 3)
1053: error(Ebadblt);
1054: v = BGSHORT(p+1);
1055: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1056: error(Ebadbitmap);
1057: bitfree(dst);
1058: bit.map[v] = 0;
1059: m -= 3;
1060: p += 3;
1061: break;
1062:
1063: case 'g':
1064: /*
1065: * free subfont
1066: * 'g' 1
1067: * id 2
1068: */
1069: if(m < 3)
1070: error(Ebadblt);
1071: v = BGSHORT(p+1);
1072: if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0)
1073: error(Ebadfont);
1074: subfontfree(f, v);
1075: m -= 3;
1076: p += 3;
1077: break;
1078:
1079: case 'h':
1080: /*
1081: * free font
1082: * 'h' 1
1083: * id 2
1084: */
1085: if(m < 3)
1086: error(Ebadblt);
1087: v = BGSHORT(p+1);
1088: if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
1089: error(Ebadfont);
1090: fontfree(ff);
1091: bit.font[v] = 0;
1092: m -= 3;
1093: p += 3;
1094: break;
1095:
1096: case 'i':
1097: /*
1098: * init
1099: *
1100: * 'i' 1
1101: */
1102: bit.init = 1;
1103: m -= 1;
1104: p += 1;
1105: break;
1106:
1107: case 'j':
1108: /*
1109: * subfont cache check
1110: *
1111: * 'j' 1
1112: * qid 8
1113: */
1114: if(m < 9)
1115: error(Ebadblt);
1116: q0 = BGLONG(p+1);
1117: q1 = BGLONG(p+5);
1118: i = 0;
1119: if(q0 != ~0)
1120: for(; i<bit.nsubfont; i++){
1121: f = bit.subfont[i];
1122: if(f && f->qid[0]==q0 && f->qid[1]==q1)
1123: goto sfcachefound;
1124: }
1125: error(Esfnotcached);
1126:
1127: sfcachefound:
1128: f->ref++;
1129: bit.cacheid = i;
1130: m -= 9;
1131: p += 9;
1132: break;
1133:
1134: case 'k':
1135: /*
1136: * allocate subfont
1137: * 'k' 1
1138: * n 2
1139: * height 1
1140: * ascent 1
1141: * bitmap id 2
1142: * qid 8
1143: * fontchars 6*(n+1)
1144: * next read returns allocated font id
1145: */
1146: if(m < 15)
1147: error(Ebadblt);
1148: v = BGSHORT(p+1);
1149: if(v<0 || v>NINFO || m<15+6*(v+1))
1150: error(Ebadblt);
1151: for(i=1; i<bit.nsubfont; i++)
1152: if(bit.subfont[i] == 0)
1153: goto subfontfound;
1154: fp = bitmalloc((bit.nsubfont+DMAP)*sizeof(BSubfont*));
1155: if(fp == 0)
1156: error(Enomem);
1157: memmove(fp, bit.subfont, bit.nsubfont*sizeof(BSubfont*));
1158: free(bit.subfont);
1159: bit.subfont = fp;
1160: bit.nsubfont += DMAP;
1161: subfontfound:
1162: f = bitmalloc(sizeof(BSubfont));
1163: if(f == 0)
1164: error(Enomem);
1165: f->info = bitmalloc((v+1)*sizeof(Fontchar));
1166: if(f->info == 0){
1167: free(f);
1168: error(Enomem);
1169: }
1170: bit.subfont[i] = f;
1171: f->n = v;
1172: f->height = p[3];
1173: f->ascent = p[4];
1174: f->qid[0] = BGLONG(p+7);
1175: f->qid[1] = BGLONG(p+11);
1176: /* check to see if already there, uncache if so */
1177: for(j=0; j<bit.nsubfont; j++){
1178: if(j == i)
1179: continue;
1180: tf = bit.subfont[j];
1181: if(tf && tf->qid[0]==f->qid[0] && tf->qid[1]==f->qid[1]){
1182: f->qid[0] = ~0; /* uncached */
1183: break;
1184: }
1185: }
1186: f->ref = 1;
1187: v = BGSHORT(p+5);
1188: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1189: error(Ebadbitmap);
1190: f->bits = dst;
1191: bit.map[v] = 0; /* subfont now owns bitmap */
1192: m -= 15;
1193: p += 15;
1194: fcp = f->info;
1195: for(j=0; j<=f->n; j++,fcp++){
1196: fcp->x = BGSHORT(p);
1197: fcp->top = p[2];
1198: fcp->bottom = p[3];
1199: fcp->left = p[4];
1200: fcp->width = p[5];
1201: fcp->top = p[2];
1202: p += 6;
1203: m -= 6;
1204: }
1205: bit.subfid = i;
1206: break;
1207:
1208: case 'l':
1209: /*
1210: * line segment
1211: *
1212: * 'l' 1
1213: * id 2
1214: * pt1 8
1215: * pt2 8
1216: * value 1
1217: * code 2
1218: */
1219: if(m < 22)
1220: error(Ebadblt);
1221: v = BGSHORT(p+1);
1222: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1223: error(Ebadbitmap);
1224: off = 0;
1225: fc = BGSHORT(p+20) & 0xF;
1226: if(v == 0){
1227: if(flipping)
1228: fc = flipD[fc];
1229: off = 1;
1230: }
1231: pt1.x = BGLONG(p+3);
1232: pt1.y = BGLONG(p+7);
1233: pt2.x = BGLONG(p+11);
1234: pt2.y = BGLONG(p+15);
1235: t = p[19];
1236: if(off && !isoff){
1237: cursoroff(1);
1238: isoff = 1;
1239: }
1240: gsegment(dst, pt1, pt2, t, fc);
1241: if(dst->base < endscreen){
1242: mbbpt(pt1);
1243: mbbpt(pt2);
1244: }
1245: m -= 22;
1246: p += 22;
1247: break;
1248:
1249: case 'm':
1250: /*
1251: * read colormap
1252: *
1253: * 'm' 1
1254: * id 2
1255: */
1256: if(m < 3)
1257: error(Ebadblt);
1258: v = BGSHORT(p+1);
1259: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1260: error(Ebadbitmap);
1261: bit.mid = v;
1262: m -= 3;
1263: p += 3;
1264: break;
1265:
1266: case 'n':
1267: /*
1268: * allocate font
1269: * 'n' 1
1270: * height 1
1271: * ascent 1
1272: * ldepth 2
1273: * ncache 2
1274: * next read returns allocated font id
1275: */
1276: if(m < 7)
1277: error(Ebadblt);
1278: v = BGSHORT(p+3);
1279: t = BGSHORT(p+5);
1280: if(v<0 || t<0)
1281: error(Ebadblt);
1282: for(i=0; i<bit.nfont; i++)
1283: if(bit.font[i] == 0)
1284: goto fontfound;
1285: ffp = bitmalloc((bit.nfont+DMAP)*sizeof(GFont*));
1286: if(ffp == 0)
1287: error(Enomem);
1288: memmove(ffp, bit.font, bit.nfont*sizeof(GFont*));
1289: free(bit.font);
1290: bit.font = ffp;
1291: bit.nfont += DMAP;
1292: fontfound:
1293: ff = bitmalloc(sizeof(GFont));
1294: if(ff == 0)
1295: error(Enomem);
1296: ff->ncache = t;
1297: ff->cache = bitmalloc(t*sizeof(GCacheinfo));
1298: if(ff->cache == 0){
1299: free(ff);
1300: error(Enomem);
1301: }
1302: bit.font[i] = ff;
1303: ff = bit.font[i];
1304: ff->height = p[1];
1305: ff->ascent = p[2];
1306: ff->ldepth = v;
1307: ff->width = 0;
1308: ff->b = 0;
1309: m -= 7;
1310: p += 7;
1311: bit.fid = i;
1312: break;
1313:
1314: case 'p':
1315: /*
1316: * point
1317: *
1318: * 'p' 1
1319: * id 2
1320: * pt 8
1321: * value 1
1322: * code 2
1323: */
1324: if(m < 14)
1325: error(Ebadblt);
1326: v = BGSHORT(p+1);
1327: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1328: error(Ebadbitmap);
1329: off = 0;
1330: fc = BGSHORT(p+12) & 0xF;
1331: if(v == 0){
1332: if(flipping)
1333: fc = flipD[fc];
1334: off = 1;
1335: }
1336: pt1.x = BGLONG(p+3);
1337: pt1.y = BGLONG(p+7);
1338: t = p[11];
1339: if(off && !isoff){
1340: cursoroff(1);
1341: isoff = 1;
1342: }
1343: gpoint(dst, pt1, t, fc);
1344: if(dst->base < endscreen)
1345: mbbpt(pt1);
1346: m -= 14;
1347: p += 14;
1348: break;
1349:
1350: case 'q':
1351: /*
1352: * clip rectangle
1353: * 'q' 1
1354: * id 2
1355: * rect 16
1356: */
1357: if(m < 19)
1358: error(Ebadblt);
1359: v = BGSHORT(p+1);
1360: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1361: error(Ebadbitmap);
1362: rect.min.x = BGLONG(p+3);
1363: rect.min.y = BGLONG(p+7);
1364: rect.max.x = BGLONG(p+11);
1365: rect.max.y = BGLONG(p+15);
1366: if(rectclip(&rect, dst->r))
1367: dst->clipr = rect;
1368: m -= 19;
1369: p += 19;
1370: break;
1371:
1372: case 'r':
1373: /*
1374: * read
1375: * 'r' 1
1376: * src id 2
1377: * miny 4
1378: * maxy 4
1379: */
1380: if(m < 11)
1381: error(Ebadblt);
1382: v = BGSHORT(p+1);
1383: if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
1384: error(Ebadbitmap);
1385: miny = BGLONG(p+3);
1386: maxy = BGLONG(p+7);
1387: if(miny>maxy || miny<src->r.min.y || maxy>src->r.max.y)
1388: error(Ebadblt);
1389: bit.rid = v;
1390: bit.rminy = miny;
1391: bit.rmaxy = maxy;
1392: p += 11;
1393: m -= 11;
1394: break;
1395:
1396: case 's':
1397: /*
1398: * string
1399: * 's' 1
1400: * id 2
1401: * pt 8
1402: * font id 2
1403: * code 2
1404: * n 2
1405: * cache indices 2*n (not null terminated)
1406: */
1407: if(m < 17)
1408: error(Ebadblt);
1409: v = BGSHORT(p+1);
1410: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1411: error(Ebadbitmap);
1412: off = 0;
1413: fc = BGSHORT(p+13) & 0xF;
1414: if(v == 0){
1415: if(flipping)
1416: fc = flipD[fc];
1417: off = 1;
1418: }
1419: pt.x = BGLONG(p+3);
1420: pt.y = BGLONG(p+7);
1421: v = BGSHORT(p+11);
1422: if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
1423: error(Ebadfont);
1424: l = BGSHORT(p+15)*2;
1425: p += 17;
1426: m -= 17;
1427: if(l > m)
1428: error(Ebadblt);
1429: if(off && !isoff){
1430: cursoroff(1);
1431: isoff = 1;
1432: }
1433: bitstring(dst, pt, ff, p, l, fc);
1434: if(dst->base < endscreen)
1435: mbbrect(Rpt(pt, add(pt, bitstrsize(ff, p, l))));
1436: m -= l;
1437: p += l;
1438: break;
1439:
1440: case 't':
1441: /*
1442: * texture
1443: * 't' 1
1444: * dst id 2
1445: * rect 16
1446: * src id 2
1447: * fcode 2
1448: */
1449: if(m < 23)
1450: error(Ebadblt);
1451: v = BGSHORT(p+1);
1452: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1453: error(Ebadbitmap);
1454: off = 0;
1455: fc = BGSHORT(p+21) & 0xF;
1456: if(v == 0){
1457: if(flipping)
1458: fc = flipD[fc];
1459: off = 1;
1460: }
1461: rect.min.x = BGLONG(p+3);
1462: rect.min.y = BGLONG(p+7);
1463: rect.max.x = BGLONG(p+11);
1464: rect.max.y = BGLONG(p+15);
1465: v = BGSHORT(p+19);
1466: if(v<0 || v>=bit.nmap || (src=bit.map[v])==0)
1467: error(Ebadbitmap);
1468: if(off && !isoff){
1469: cursoroff(1);
1470: isoff = 1;
1471: }
1472: gtexture(dst, rect, src, fc);
1473: if(dst->base < endscreen)
1474: mbbrect(rect);
1475: m -= 23;
1476: p += 23;
1477: break;
1478:
1479: case 'v':
1480: /*
1481: * clear font cache and bitmap.
1482: * if error, font is unchanged.
1483: * 'v' 1
1484: * id 2
1485: * ncache 2
1486: * width 2
1487: */
1488: if(m < 7)
1489: error(Ebadblt);
1490: v = BGSHORT(p+1);
1491: t = BGSHORT(p+3);
1492: if(t<0 || v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
1493: error(Ebadblt);
1494: x = BGSHORT(p+5);
1495: i = bitalloc(Rect(0, 0, t*x, ff->height), ff->ldepth);
1496: if(t != ff->ncache){
1497: gc = bitmalloc(t*sizeof(ff->cache[0]));
1498: if(gc == 0){
1499: bitfree(bit.map[i]);
1500: bit.map[i] = 0;
1501: error(Enomem);
1502: }
1503: free(ff->cache);
1504: ff->cache = gc;
1505: ff->ncache = t;
1506: }else{
1507: /*
1508: * memset not necessary but helps avoid
1509: * confusion if the cache is mishandled by the
1510: * user.
1511: */
1512: memset(ff->cache, 0, t*sizeof(ff->cache[0]));
1513: }
1514: if(ff->b)
1515: bitfree(ff->b);
1516: ff->b = bit.map[i];
1517: bit.map[i] = 0; /* disconnect it from GBitmap space */
1518: ff->width = x;
1519: p += 7;
1520: m -= 7;
1521: break;
1522:
1523: case 'w':
1524: /*
1525: * write
1526: * 'w' 1
1527: * dst id 2
1528: * miny 4
1529: * maxy 4
1530: * data bytewidth*(maxy-miny)
1531: */
1532: if(m < 11)
1533: error(Ebadblt);
1534: v = BGSHORT(p+1);
1535: if(v<0 || v>=bit.nmap || (dst=bit.map[v])==0)
1536: error(Ebadbitmap);
1537: off = 0;
1538: if(v == 0)
1539: off = 1;
1540: miny = BGLONG(p+3);
1541: maxy = BGLONG(p+7);
1542: if(miny>maxy || miny<dst->r.min.y || maxy>dst->r.max.y)
1543: error(Ebadblt);
1544: ws = 1<<(3-dst->ldepth); /* pixels per byte */
1545: /* set l to number of bytes of incoming data per scan line */
1546: if(dst->r.min.x >= 0)
1547: l = (dst->r.max.x+ws-1)/ws - dst->r.min.x/ws;
1548: else{ /* make positive before divide */
1549: t = (-dst->r.min.x)+ws-1;
1550: t = (t/ws)*ws;
1551: l = (t+dst->r.max.x+ws-1)/ws;
1552: }
1553: if(dst->base < endscreen)
1554: mbbrect(Rect(dst->r.min.x, miny, dst->r.max.x, maxy));
1555: p += 11;
1556: m -= 11;
1557: if(m < l*(maxy-miny))
1558: error(Ebadblt);
1559: if(off && !isoff){
1560: cursoroff(1);
1561: isoff = 1;
1562: }
1563: for(y=miny; y<maxy; y++){
1564: oq = (uchar*)gaddr(dst, Pt(dst->r.min.x, y));
1565: q = oq + (dst->r.min.x&((sizeof(ulong))*ws-1))/ws;
1566: memmove(q, p, l);
1567: if(islittle)
1568: pixreverse(q, l, dst->ldepth);
1569: if(v==0 && flipping){ /* flip bits */
1570: /* we know it's all word aligned */
1571: lp = (ulong*)oq;
1572: for(x=0; x<l; x+=sizeof(ulong))
1573: *lp++ ^= ~0;
1574: }
1575: p += l;
1576: m -= l;
1577: }
1578: if(v == 0)
1579: hwscreenwrite(miny, maxy);
1580: break;
1581:
1582: case 'x':
1583: /*
1584: * cursorset
1585: *
1586: * 'x' 1
1587: * pt 8
1588: */
1589: if(m < 9)
1590: error(Ebadblt);
1591: pt1.x = BGLONG(p+1);
1592: pt1.y = BGLONG(p+5);
1593: if(ptinrect(pt1, gscreen.r)){
1594: mouse.xy = pt1;
1595: mouse.redraw = 1;
1596: mouse.track = 1;
1597: mouseclock();
1598: }
1599: m -= 9;
1600: p += 9;
1601: break;
1602:
1603: case 'y':
1604: /*
1605: * load font from subfont
1606: * 'y' 1
1607: * id 2
1608: * cache index 2
1609: * subfont id 2
1610: * subfont index 2
1611: */
1612: if(m < 9)
1613: error(Ebadblt);
1614: v = BGSHORT(p+1);
1615: if(v<0 || v>=bit.nfont || (ff=bit.font[v])==0)
1616: error(Ebadblt);
1617: if(ff->b == 0)
1618: error(Ebadbitmap);
1619: l = BGSHORT(p+3);
1620: if(l >= ff->ncache)
1621: error(Ebadblt);
1622: v = BGSHORT(p+5);
1623: if(v<0 || v>=bit.nsubfont || (f=bit.subfont[v])==0 || f->ref==0)
1624: error(Ebadfont);
1625: nw = BGSHORT(p+7);
1626: if(nw >= f->n)
1627: error(Ebadblt);
1628: bitloadchar(ff, l, f, nw);
1629: p += 9;
1630: m -= 9;
1631: break;
1632:
1633: case 'z':
1634: /*
1635: * write the colormap
1636: *
1637: * 'z' 1
1638: * id 2
1639: * map 12*(2**bitmapdepth)
1640: */
1641: if(m < 3)
1642: error(Ebadblt);
1643: v = BGSHORT(p+1);
1644: if(v != 0)
1645: error(Ebadbitmap);
1646: m -= 3;
1647: p += 3;
1648: nw = 1 << (1 << gscreen.ldepth);
1649: if(m < 12*nw)
1650: error(Ebadblt);
1651: ok = 1;
1652: for(i = 0; i < nw; i++){
1653: ok &= setcolor(flipping ? ~i : i, BGLONG(p), BGLONG(p+4), BGLONG(p+8));
1654: p += 12;
1655: m -= 12;
1656: }
1657: if(!ok){
1658: /* assume monochrome: possibly change flipping */
1659: l = BGLONG(p-12);
1660: getcolor(nw-1, &rv, &rv, &rv);
1661: flipping = (l != rv);
1662: }
1663: break;
1664: }
1665:
1666: poperror();
1667: if(isoff)
1668: cursoron(1);
1669: screenupdate();
1670: qunlock(&bit);
1671: return n;
1672: }
1673:
1674: int
1675: bitalloc(Rectangle rect, int ld)
1676: {
1677: Arena *a, *ea, *aa;
1678: GBitmap *b, **bp, **ep;
1679: ulong l, ws, nw;
1680: long t;
1681:
1682: ws = BI2WD>>ld; /* pixels per word */
1683: if(rect.min.x >= 0){
1684: l = (rect.max.x+ws-1)/ws;
1685: l -= rect.min.x/ws;
1686: }else{ /* make positive before divide */
1687: t = (-rect.min.x)+ws-1;
1688: t = (t/ws)*ws;
1689: l = (t+rect.max.x+ws-1)/ws;
1690: }
1691: nw = l*Dy(rect);
1692: ea = &bit.arena[bit.narena];
1693:
1694: /* first try easy fit */
1695: for(a=bit.arena; a<ea; a++){
1696: if(a->words == 0)
1697: continue;
1698: if(a->wfree+HDR+nw <= a->words+a->nwords)
1699: goto found;
1700: }
1701:
1702: /* compact and try again */
1703: bitcompact();
1704: aa = 0;
1705: for(a=bit.arena; a<ea; a++){
1706: if(a->words == 0){
1707: if(aa == 0)
1708: aa = a;
1709: continue;
1710: }
1711: if(a->wfree+HDR+nw <= a->words+a->nwords)
1712: goto found;
1713: }
1714:
1715: /* need new arena */
1716: if(aa){
1717: a = aa;
1718: a->nwords = HDR + (gscreen.r.max.y*gscreen.r.max.x)/ws;
1719: if(a->nwords < HDR+nw)
1720: a->nwords = HDR+nw;
1721: a->words = xalloc(a->nwords*sizeof(ulong));
1722: if(a->words){
1723: a->wfree = a->words;
1724: a->nbusy = 0;
1725: goto found;
1726: }
1727: }
1728: /* else can't grow list: bitmaps have backpointers */
1729:
1730: bitfreeup();
1731:
1732: for(a=bit.arena; a<ea; a++){
1733: if(a->words == 0)
1734: continue;
1735: if(a->wfree+HDR+nw <= a->words+a->nwords)
1736: goto found;
1737: }
1738: if(a == ea)
1739: error(Enobitstore);
1740:
1741: found:
1742: b = bitmalloc(sizeof(GBitmap));
1743: if(b == 0)
1744: error(Enomem);
1745: *a->wfree++ = nw;
1746: *a->wfree++ = (ulong)a;
1747: *a->wfree++ = (ulong)b;
1748: memset(a->wfree, 0, nw*sizeof(ulong));
1749: b->base = a->wfree;
1750: a->wfree += nw;
1751: a->nbusy++;
1752: b->zero = l*rect.min.y;
1753: if(rect.min.x >= 0)
1754: b->zero += rect.min.x/ws;
1755: else
1756: b->zero -= (-rect.min.x+ws-1)/ws;
1757: b->zero = -b->zero;
1758: b->width = l;
1759: b->ldepth = ld;
1760: b->r = rect;
1761: b->clipr = rect;
1762: b->cache = 0;
1763: /* worth doing better than linear lookup? */
1764: ep = bit.map+bit.nmap;
1765: for(bp=bit.map; bp<ep; bp++)
1766: if(*bp == 0)
1767: break;
1768: if(bp == ep){
1769: bp = bitmalloc((bit.nmap+DMAP)*sizeof(GBitmap*));
1770: if(bp == 0){
1771: bitfree(b);
1772: error(Enomem);
1773: }
1774: memmove(bp, bit.map, bit.nmap*sizeof(GBitmap*));
1775: free(bit.map);
1776: bit.map = bp;
1777: bp += bit.nmap;
1778: bit.nmap += DMAP;
1779: }
1780: *bp = b;
1781: return bp-bit.map;
1782: }
1783:
1784: void
1785: bitfree(GBitmap *b)
1786: {
1787: Arena *a;
1788:
1789: if(b->base != gscreen.base){ /* can't free screen memory */
1790: a = (Arena*)(b->base[-2]);
1791: a->nbusy--;
1792: if(a->nbusy == 0)
1793: arenafree(a);
1794: b->base[-1] = 0;
1795: }
1796: free(b);
1797: }
1798:
1799: void
1800: fontfree(GFont *f)
1801: {
1802: if(f->b)
1803: bitfree(f->b);
1804: free(f->cache);
1805: free(f);
1806: }
1807:
1808: void
1809: subfontfree(BSubfont *s, int i)
1810: {
1811: if(s!=bdefont && s->ref>0){ /* don't free subfont 0, bdefont */
1812: s->ref--;
1813: if(s->ref==0 && s->qid[0]==~0){ /* uncached */
1814: bitfree(s->bits);
1815: free(s->info);
1816: free(s);
1817: bit.subfont[i] = 0;
1818: }
1819: }
1820: return;
1821: }
1822:
1823: void
1824: arenafree(Arena *a)
1825: {
1826: xfree(a->words);
1827: a->words = 0;
1828: }
1829:
1830: void
1831: bitstring(GBitmap *bp, Point pt, GFont *f, uchar *p, long l, Fcode fc)
1832: {
1833: int full;
1834: Rectangle rect;
1835: ushort r;
1836: GCacheinfo *c;
1837: int x;
1838: Fcode clr;
1839:
1840: clr = 0;
1841: full = (fc&~S)^(D&~S); /* result involves source */
1842: if(full){
1843: rect.min.y = 0;
1844: rect.max.y = f->height;
1845: /* set clr to result under fc if source pixel is zero */
1846: /* hard to do without knowing layout of bits, so we cheat */
1847: clr = (fc&3); /* fc&3 is result if source is zero */
1848: clr |= clr<<2; /* fc&(3<<2) is result if source is one */
1849: }
1850:
1851: while(l > 0){
1852: r = BGSHORT(p);
1853: p += 2;
1854: l -= 2;
1855: if(r >= f->ncache)
1856: continue;
1857: c = &f->cache[r];
1858: if(!full){
1859: rect.min.y = c->top;
1860: rect.max.y = c->bottom;
1861: }else{
1862: if(c->left > 0)
1863: gbitblt(bp, pt, bp,
1864: Rect(pt.x, pt.y, pt.x+c->left, pt.y+f->height),
1865: clr);
1866: x = c->left+(c->xright-c->x);
1867: if(x < c->width)
1868: gbitblt(bp, Pt(pt.x+x, pt.y), bp,
1869: Rect(pt.x+x, pt.y, pt.x+c->width, pt.y+f->height),
1870: clr);
1871: }
1872: rect.min.x = c->x;
1873: rect.max.x = c->xright;
1874: gbitblt(bp, Pt(pt.x+c->left, pt.y+rect.min.y), f->b, rect, fc);
1875: pt.x += c->width;
1876: }
1877: }
1878:
1879: void
1880: bitloadchar(GFont *f, int ci, GSubfont *subf, int si)
1881: {
1882: GCacheinfo *c;
1883: Rectangle rect;
1884: Fontchar *fi;
1885: int y;
1886:
1887: c = &f->cache[ci];
1888: fi = &subf->info[si];
1889: /* careful about sign extension: top and bottom are uchars */
1890: y = fi->top + (f->ascent-subf->ascent);
1891: if(y < 0)
1892: y = 0;
1893: c->top = y;
1894: y = fi->bottom + (f->ascent-subf->ascent);
1895: if(y < 0)
1896: y = 0;
1897: c->bottom = y;
1898: c->width = fi->width;
1899: c->left = fi->left;
1900: c->x = ci*f->width;
1901: c->xright = c->x + ((fi+1)->x - fi->x);
1902: rect.min.y = 0;
1903: rect.max.y = f->height;
1904: rect.min.x = c->x;
1905: rect.max.x = c->x+f->width;
1906: gbitblt(f->b, rect.min, f->b, rect, 0);
1907: rect.min.x = fi->x;
1908: rect.max.x = (fi+1)->x;
1909: rect.max.y = subf->height;
1910: gbitblt(f->b, Pt(c->x, f->ascent-subf->ascent), subf->bits, rect, S);
1911: }
1912:
1913: QLock bitlock;
1914:
1915: GBitmap*
1916: id2bit(int v)
1917: {
1918: GBitmap *bp=0;
1919:
1920: if(v<0 || v>=bit.nmap || (bp=bit.map[v])==0)
1921: error(Ebadbitmap);
1922: return bp;
1923: }
1924:
1925: void
1926: bitcompact(void)
1927: {
1928: Arena *a, *ea, *na;
1929: ulong *p1, *p2, n;
1930:
1931: qlock(&bitlock);
1932: ea = &bit.arena[bit.narena];
1933: for(a=bit.arena; a<ea; a++){
1934: if(a->words == 0)
1935: continue;
1936: /* first compact what's here */
1937: p1 = p2 = a->words;
1938: while(p2 < a->wfree){
1939: n = HDR+p2[0];
1940: if(p2[2] == 0){
1941: p2 += n;
1942: continue;
1943: }
1944: if(p1 != p2){
1945: memmove(p1, p2, n*sizeof(ulong));
1946: ((GBitmap*)p1[2])->base = p1+HDR;
1947: }
1948: p2 += n;
1949: p1 += n;
1950: }
1951: /* now pull stuff from later arena to fill this one */
1952: na = a+1;
1953: while(na<ea && p1<a->words+a->nwords){
1954: p2 = na->words;
1955: if(p2 == 0){
1956: na++;
1957: continue;
1958: }
1959: while(p2 < na->wfree){
1960: n = HDR+p2[0];
1961: if(p2[2] == 0){
1962: p2 += n;
1963: continue;
1964: }
1965: if(p1+n < a->words+a->nwords){
1966: memmove(p1, p2, n*sizeof(ulong));
1967: ((GBitmap*)p1[2])->base = p1+HDR;
1968: /* block now in new arena... */
1969: p1[1] = (ulong)a;
1970: a->nbusy++;
1971: /* ... not in old arena */
1972: na->nbusy--;
1973: p2[2] = 0;
1974: p1 += n;
1975: }
1976: p2 += n;
1977: }
1978: na++;
1979: }
1980: a->wfree = p1;
1981: }
1982: for(a=bit.arena; a<ea; a++)
1983: if(a->words && a->nbusy==0)
1984: arenafree(a);
1985: qunlock(&bitlock);
1986: }
1987:
1988: void
1989: Cursortocursor(Cursor *c)
1990: {
1991: lock(&cursor);
1992: memmove(&cursor, c, sizeof(Cursor));
1993: setcursor(c);
1994: unlock(&cursor);
1995: }
1996:
1997: int
1998: cursoron(int dolock)
1999: {
2000: int ret;
2001:
2002: if(dolock)
2003: lock(&cursor);
2004: ret = 0;
2005: if(hwcurs)
2006: ret = hwgcmove(mouse.xy);
2007: else if(cursor.visible++ == 0){
2008: cursor.r.min = mouse.xy;
2009: cursor.r.max = add(mouse.xy, Pt(16, 16));
2010: cursor.r = raddp(cursor.r, cursor.offset);
2011: gbitblt(&cursorback, Pt(0, 0), &gscreen, cursor.r, S);
2012: gbitblt(&gscreen, cursor.r.min,
2013: &clr, Rect(0, 0, 16, 16), flipping? flipD[D&~S] : D&~S);
2014: gbitblt(&gscreen, cursor.r.min,
2015: &set, Rect(0, 0, 16, 16), flipping? flipD[S|D] : S|D);
2016: mbbrect(cursor.r);
2017: }
2018: if(dolock)
2019: unlock(&cursor);
2020:
2021: return ret;
2022: }
2023:
2024: void
2025: cursoroff(int dolock)
2026: {
2027: if(hwcurs)
2028: return;
2029: if(dolock)
2030: lock(&cursor);
2031: if(--cursor.visible == 0) {
2032: gbitblt(&gscreen, cursor.r.min, &cursorback, Rect(0, 0, 16, 16), S);
2033: mbbrect(cursor.r);
2034: mousescreenupdate();
2035: }
2036: if(dolock)
2037: unlock(&cursor);
2038: }
2039:
2040: /*
2041: * called by the clock routine to redraw the cursor
2042: */
2043: void
2044: mouseclock(void)
2045: {
2046: if(mouse.track){
2047: mousetrack(mouse.buttons, mouse.dx, mouse.dy);
2048: mouse.track = 0;
2049: mouse.dx = 0;
2050: mouse.dy = 0;
2051: }
2052: if(mouse.redraw && canlock(&cursor)){
2053: mouse.redraw = 0;
2054: cursoroff(0);
2055: mouse.redraw = cursoron(0);
2056: mousescreenupdate();
2057: unlock(&cursor);
2058: }
2059: }
2060:
2061: /*
2062: * called at interrupt level to update the structure and
2063: * awaken any waiting procs.
2064: */
2065: void
2066: mousetrack(int b, int dx, int dy)
2067: {
2068: int x, y;
2069:
2070: x = mouse.xy.x + dx;
2071: if(x < gscreen.r.min.x)
2072: x = gscreen.r.min.x;
2073: if(x >= gscreen.r.max.x)
2074: x = gscreen.r.max.x;
2075: y = mouse.xy.y + dy;
2076: if(y < gscreen.r.min.y)
2077: y = gscreen.r.min.y;
2078: if(y >= gscreen.r.max.y)
2079: y = gscreen.r.max.y;
2080: mouse.counter++;
2081: mouse.xy = Pt(x, y);
2082: mouse.buttons = b;
2083: mouse.redraw = 1;
2084: wakeup(&mouse.r);
2085: }
2086:
2087: /*
2088: * microsoft 3 button, 7 bit bytes
2089: *
2090: * byte 0 - 1 L R Y7 Y6 X7 X6
2091: * byte 1 - 0 X5 X4 X3 X2 X1 X0
2092: * byte 2 - 0 Y5 Y4 Y3 Y2 Y1 Y0
2093: * byte 3 - 0 M x x x x x (optional)
2094: *
2095: * shift & right button is the same as middle button (for 2 button mice)
2096: */
2097: int
2098: m3mouseputc(IOQ *q, int c)
2099: {
2100: static uchar msg[3];
2101: static int nb;
2102: static int middle;
2103: static uchar b[] = { 0, 4, 1, 5, 0, 2, 1, 5 };
2104: short x;
2105: int dx, dy, newbuttons;
2106:
2107: USED(q);
2108: /*
2109: * check bit 6 for consistency
2110: */
2111: if(nb==0){
2112: if((c&0x40) == 0){
2113: /* an extra byte gets sent for the middle button */
2114: middle = (c&0x20) ? 2 : 0;
2115: newbuttons = (mouse.buttons & ~2) | middle;
2116: mousetrack(newbuttons, 0, 0);
2117: return 0;
2118: }
2119: }
2120: msg[nb] = c;
2121: if(++nb == 3){
2122: nb = 0;
2123: newbuttons = middle | b[(msg[0]>>4)&3 | (mouseshifted ? 4 : 0)];
2124: x = (msg[0]&0x3)<<14;
2125: dx = (x>>8) | msg[1];
2126: x = (msg[0]&0xc)<<12;
2127: dy = (x>>8) | msg[2];
2128: mousetrack(newbuttons, dx, dy);
2129: }
2130: return 0;
2131: }
2132:
2133: /*
2134: * Logitech 5 byte packed binary mouse format, 8 bit bytes
2135: *
2136: * shift & right button is the same as middle button (for 2 button mice)
2137: */
2138: int
2139: mouseputc(IOQ *q, int c)
2140: {
2141: static short msg[5];
2142: static int nb;
2143: static uchar b[] = {0, 4, 2, 6, 1, 5, 3, 7, 0, 2, 2, 6, 1, 5, 3, 7};
2144: int dx, dy, newbuttons;
2145:
2146: USED(q);
2147: if((c&0xF0) == 0x80)
2148: nb=0;
2149: msg[nb] = c;
2150: if(c & 0x80)
2151: msg[nb] |= ~0xFF; /* sign extend */
2152: if(++nb == 5){
2153: newbuttons = b[((msg[0]&7)^7) | (mouseshifted ? 8 : 0)];
2154: dx = msg[1]+msg[3];
2155: dy = -(msg[2]+msg[4]);
2156: mousetrack(newbuttons, dx, dy);
2157: nb = 0;
2158: }
2159: return 0;
2160: }
2161:
2162: int
2163: mousechanged(void *m)
2164: {
2165: USED(m);
2166: return mouse.lastcounter != mouse.counter;
2167: }
2168:
2169: /*
2170: * reverse pixels into little endian order
2171: */
2172: uchar revtab0[] = {
2173: 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
2174: 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
2175: 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
2176: 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
2177: 0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
2178: 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
2179: 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
2180: 0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
2181: 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
2182: 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
2183: 0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
2184: 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
2185: 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
2186: 0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
2187: 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
2188: 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
2189: 0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
2190: 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
2191: 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
2192: 0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
2193: 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
2194: 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
2195: 0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
2196: 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
2197: 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
2198: 0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
2199: 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
2200: 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
2201: 0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
2202: 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
2203: 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
2204: 0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
2205: };
2206: uchar revtab1[] = {
2207: 0x00, 0x40, 0x80, 0xc0, 0x10, 0x50, 0x90, 0xd0,
2208: 0x20, 0x60, 0xa0, 0xe0, 0x30, 0x70, 0xb0, 0xf0,
2209: 0x04, 0x44, 0x84, 0xc4, 0x14, 0x54, 0x94, 0xd4,
2210: 0x24, 0x64, 0xa4, 0xe4, 0x34, 0x74, 0xb4, 0xf4,
2211: 0x08, 0x48, 0x88, 0xc8, 0x18, 0x58, 0x98, 0xd8,
2212: 0x28, 0x68, 0xa8, 0xe8, 0x38, 0x78, 0xb8, 0xf8,
2213: 0x0c, 0x4c, 0x8c, 0xcc, 0x1c, 0x5c, 0x9c, 0xdc,
2214: 0x2c, 0x6c, 0xac, 0xec, 0x3c, 0x7c, 0xbc, 0xfc,
2215: 0x01, 0x41, 0x81, 0xc1, 0x11, 0x51, 0x91, 0xd1,
2216: 0x21, 0x61, 0xa1, 0xe1, 0x31, 0x71, 0xb1, 0xf1,
2217: 0x05, 0x45, 0x85, 0xc5, 0x15, 0x55, 0x95, 0xd5,
2218: 0x25, 0x65, 0xa5, 0xe5, 0x35, 0x75, 0xb5, 0xf5,
2219: 0x09, 0x49, 0x89, 0xc9, 0x19, 0x59, 0x99, 0xd9,
2220: 0x29, 0x69, 0xa9, 0xe9, 0x39, 0x79, 0xb9, 0xf9,
2221: 0x0d, 0x4d, 0x8d, 0xcd, 0x1d, 0x5d, 0x9d, 0xdd,
2222: 0x2d, 0x6d, 0xad, 0xed, 0x3d, 0x7d, 0xbd, 0xfd,
2223: 0x02, 0x42, 0x82, 0xc2, 0x12, 0x52, 0x92, 0xd2,
2224: 0x22, 0x62, 0xa2, 0xe2, 0x32, 0x72, 0xb2, 0xf2,
2225: 0x06, 0x46, 0x86, 0xc6, 0x16, 0x56, 0x96, 0xd6,
2226: 0x26, 0x66, 0xa6, 0xe6, 0x36, 0x76, 0xb6, 0xf6,
2227: 0x0a, 0x4a, 0x8a, 0xca, 0x1a, 0x5a, 0x9a, 0xda,
2228: 0x2a, 0x6a, 0xaa, 0xea, 0x3a, 0x7a, 0xba, 0xfa,
2229: 0x0e, 0x4e, 0x8e, 0xce, 0x1e, 0x5e, 0x9e, 0xde,
2230: 0x2e, 0x6e, 0xae, 0xee, 0x3e, 0x7e, 0xbe, 0xfe,
2231: 0x03, 0x43, 0x83, 0xc3, 0x13, 0x53, 0x93, 0xd3,
2232: 0x23, 0x63, 0xa3, 0xe3, 0x33, 0x73, 0xb3, 0xf3,
2233: 0x07, 0x47, 0x87, 0xc7, 0x17, 0x57, 0x97, 0xd7,
2234: 0x27, 0x67, 0xa7, 0xe7, 0x37, 0x77, 0xb7, 0xf7,
2235: 0x0b, 0x4b, 0x8b, 0xcb, 0x1b, 0x5b, 0x9b, 0xdb,
2236: 0x2b, 0x6b, 0xab, 0xeb, 0x3b, 0x7b, 0xbb, 0xfb,
2237: 0x0f, 0x4f, 0x8f, 0xcf, 0x1f, 0x5f, 0x9f, 0xdf,
2238: 0x2f, 0x6f, 0xaf, 0xef, 0x3f, 0x7f, 0xbf, 0xff,
2239: };
2240: uchar revtab2[] = {
2241: 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70,
2242: 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
2243: 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71,
2244: 0x81, 0x91, 0xa1, 0xb1, 0xc1, 0xd1, 0xe1, 0xf1,
2245: 0x02, 0x12, 0x22, 0x32, 0x42, 0x52, 0x62, 0x72,
2246: 0x82, 0x92, 0xa2, 0xb2, 0xc2, 0xd2, 0xe2, 0xf2,
2247: 0x03, 0x13, 0x23, 0x33, 0x43, 0x53, 0x63, 0x73,
2248: 0x83, 0x93, 0xa3, 0xb3, 0xc3, 0xd3, 0xe3, 0xf3,
2249: 0x04, 0x14, 0x24, 0x34, 0x44, 0x54, 0x64, 0x74,
2250: 0x84, 0x94, 0xa4, 0xb4, 0xc4, 0xd4, 0xe4, 0xf4,
2251: 0x05, 0x15, 0x25, 0x35, 0x45, 0x55, 0x65, 0x75,
2252: 0x85, 0x95, 0xa5, 0xb5, 0xc5, 0xd5, 0xe5, 0xf5,
2253: 0x06, 0x16, 0x26, 0x36, 0x46, 0x56, 0x66, 0x76,
2254: 0x86, 0x96, 0xa6, 0xb6, 0xc6, 0xd6, 0xe6, 0xf6,
2255: 0x07, 0x17, 0x27, 0x37, 0x47, 0x57, 0x67, 0x77,
2256: 0x87, 0x97, 0xa7, 0xb7, 0xc7, 0xd7, 0xe7, 0xf7,
2257: 0x08, 0x18, 0x28, 0x38, 0x48, 0x58, 0x68, 0x78,
2258: 0x88, 0x98, 0xa8, 0xb8, 0xc8, 0xd8, 0xe8, 0xf8,
2259: 0x09, 0x19, 0x29, 0x39, 0x49, 0x59, 0x69, 0x79,
2260: 0x89, 0x99, 0xa9, 0xb9, 0xc9, 0xd9, 0xe9, 0xf9,
2261: 0x0a, 0x1a, 0x2a, 0x3a, 0x4a, 0x5a, 0x6a, 0x7a,
2262: 0x8a, 0x9a, 0xaa, 0xba, 0xca, 0xda, 0xea, 0xfa,
2263: 0x0b, 0x1b, 0x2b, 0x3b, 0x4b, 0x5b, 0x6b, 0x7b,
2264: 0x8b, 0x9b, 0xab, 0xbb, 0xcb, 0xdb, 0xeb, 0xfb,
2265: 0x0c, 0x1c, 0x2c, 0x3c, 0x4c, 0x5c, 0x6c, 0x7c,
2266: 0x8c, 0x9c, 0xac, 0xbc, 0xcc, 0xdc, 0xec, 0xfc,
2267: 0x0d, 0x1d, 0x2d, 0x3d, 0x4d, 0x5d, 0x6d, 0x7d,
2268: 0x8d, 0x9d, 0xad, 0xbd, 0xcd, 0xdd, 0xed, 0xfd,
2269: 0x0e, 0x1e, 0x2e, 0x3e, 0x4e, 0x5e, 0x6e, 0x7e,
2270: 0x8e, 0x9e, 0xae, 0xbe, 0xce, 0xde, 0xee, 0xfe,
2271: 0x0f, 0x1f, 0x2f, 0x3f, 0x4f, 0x5f, 0x6f, 0x7f,
2272: 0x8f, 0x9f, 0xaf, 0xbf, 0xcf, 0xdf, 0xef, 0xff,
2273: };
2274:
2275: void
2276: pixreverse(uchar *p, int len, int ldepth)
2277: {
2278: uchar *e;
2279: uchar *tab;
2280:
2281: switch(ldepth){
2282: case 0:
2283: tab = revtab0;
2284: break;
2285: case 1:
2286: tab = revtab1;
2287: break;
2288: case 2:
2289: tab = revtab2;
2290: break;
2291: default:
2292: return;
2293: }
2294:
2295: for(e = p + len; p < e; p++)
2296: *p = tab[*p];
2297: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.