/* * [MS-RDPEGDI]: Graphics Device Interface (GDI) Acceleration Extensions * http://msdn.microsoft.com/en-us/library/cc241537.aspx */ #include #include #include /* for geometry */ #include "dat.h" #include "fns.h" enum { Bits2= 3, Bits3= 7, Bits6= 63, Bits7= 127, Bits8= 255, }; enum /* 2.2.2.2.1 Drawing Order (DRAWING_ORDER) */ { Standard= 1<<0, Secondary= 1<<1, }; enum /* 2.2.2.2.1.1.2 Primary Drawing Order (PRIMARY_DRAWING_ORDER) */ { Clip= 1<<2, NewOrder= 1<<3, Diff= 1<<4, Lastclipr= 1<<5, ZeroFieldBit0= 1<<6, ZeroFieldBit1= 1<<7, }; enum { Scopy = 0xcc, }; enum { /* orderSupport indices for capability negotiation */ CanDstBlt = 0, CanPatBlt, /* also OpaqueRect */ CanScrBlt, CanMemBlt = 3, CanMem3Blt, CanDrawNineGrid = 7, CanLineTo, CanMultiDrawNineGrid, CanSaveBitmap = 0x0B, CanMultiDstBlt = 0x0F, CanMultiPatBlt = 0x10, CanMultiScrBlt, CanMultiOpaqueRect, CanFastIndex, CanPolygonSC, /* also PolygonCB */ CanPolygonCB, /* also PolygonCB */ CanPolyline, CanFastGlyph = 0x18, CanEllipseSC, /* also EllipseCB */ CanEllipseCB, /* also EllipseSC */ CanGlyphIndex, }; enum { /* 2.2.2.2.1.1.2 Primary Drawing Order (PRIMARY_DRAWING_ORDER) */ PatBlt=1, ScrBlt=2, OpaqueRect=10, MemBlt=13, MultiOpaqueRect=18, }; enum { /* 2.2.2.2.1.2.1.1 Secondary Drawing Order Header */ CacheImage = 0, CacheCmap, CacheCompressed, CacheGlyph, CacheImage2, CacheCompressed2, CacheBrush = 7, CacheCompressed3, }; static int getscrblt(Imgupd*, uchar*, uint, int, int); static int getmemblt(Imgupd*, uchar*, uint, int, int); static int getimgcache2(Imgupd*, uchar*, uint, int, int); static int getcmapcache(Imgupd*, uchar*, uint, int, int); typedef struct Order Order; struct Order { int fsize; int (*get)(Imgupd*,uchar*,uint,int,int); }; Order ordtab[NumOrders] = { [ScrBlt]= { 1, getscrblt }, [MemBlt]= { 2, getmemblt }, }; Order auxtab[8] = { [CacheImage2]= { 0, getimgcache2 }, [CacheCompressed2]= { 0, getimgcache2 }, [CacheCmap]= { 0, getcmapcache }, }; uchar orderSupport[NumOrders] = { [CanScrBlt]= 1, [CanMemBlt]= 1, }; static struct GdiContext { int order; Rectangle clipr; } gc = {PatBlt}; static int loadclipr(Rectangle*,uchar*,int); static int loadpt(Point*,uchar*,int,int,int); int getfupd(Imgupd* up, uchar* a, uint nb) { uchar *p, *ep; int ctl, fset, fsize; int n, size, opt, xorder; p = a; ep = a+nb; fset = 0; ctl = *p; if(!(ctl&Standard)) goto ErrNstd; if(ctl&Secondary){ if(p+6>ep) sysfatal("draworders: %s", Eshort); size = ((short)igets(p+1))+13; if(size < 0 || p+size > ep) sysfatal("draworders: size: %s", Eshort); opt = igets(p+3); xorder = p[5]; if(xorder >= nelem(auxtab) || auxtab[xorder].get == nil){ fprint(2, "egdi: unsupported secondary order %d\n", xorder); p += size; return p-a; } auxtab[xorder].get(up, p, size, xorder, opt); p += size; return p-a; } p++; if(ctl&NewOrder){ gc.order = *p++; if(gc.order >= NumOrders) // paranoia gc.order = PatBlt; } fsize = ordtab[gc.order].fsize - ((ctl>>6)&Bits2); switch(fsize){ default: goto ErrFsize; case 3: fset = p[0]|(p[1]<<8)|(p[2]<<16); break; case 2: fset = igets(p); break; case 1: fset = p[0]; case 0: break; } p += fsize; if(ctl&Clip && !(ctl&Lastclipr)) p += loadclipr(&gc.clipr, p, ep-p); if(ordtab[gc.order].get == nil) goto ErrNotsup; n = ordtab[gc.order].get(up, p, ep-p, ctl, fset); p += n; return p-a; ErrNstd: fprint(2, "egdi: non-standard order (GDI+ or out of sync)\n"); return p-a; ErrFsize: fprint(2, "egdi: bad field encoding bytes count for order %d\n", gc.order); return p-a; ErrNotsup: fprint(2, "egdi: unsupported order %d\n", gc.order); return p-a; } static int loadpt(Point* p, uchar* a, int nb, int isdelta, int fset) { int n; n = 0; if(isdelta){ if(fset&1<<0) n++; if(fset&1<<1) n++; }else{ if(fset&1<<0) n += 2; if(fset&1<<1) n += 2; } if(n>nb) sysfatal("loadpt: %s", Eshort); if(isdelta){ if(fset&1<<0) p->x += (signed char)*a++; if(fset&1<<1) p->y += (signed char)*a; }else{ if(fset&1<<0){ p->x = igets(a); a += 2; }; if(fset&1<<1) p->y = igets(a); } return n; } static int loadrect(Rectangle* pr, uchar* p, int nb, int isdelta, int fset){ int n, m; pr->max = subpt(pr->max, pr->min); n = loadpt(&pr->min, p, nb, isdelta, fset); m = loadpt(&pr->max, p+n, nb-n, isdelta, fset>>2); pr->max = addpt(pr->max, pr->min); return n+m; } static int loadclipr(Rectangle* pr, uchar* a, int nb) { int bctl; uchar *p, *ep; p = a; ep = a+nb; bctl = *p++; if(bctl&1<<4) pr->min.x += (char)*p++; else if(bctl&1<<0){ pr->min.x = igets(p); p += 2; } if(bctl&1<<5) pr->min.y += (char)*p++; else if(bctl&1<<1){ pr->min.y = igets(p); p += 2; } if(bctl&1<<6) pr->max.x += (char)*p++; else if(bctl&1<<2){ pr->max.x = igets(p)+1; p += 2; } if(bctl&1<<7) pr->max.y += (char)*p++; else if(bctl&1<<3){ pr->max.y = igets(p)+1; p += 2; } if(p>ep) sysfatal("loadclipr: %s", Eshort); return p-a; } /* 2.2.2.2.1.1.2.7 ScrBlt (SCRBLT_ORDER) */ static int getscrblt(Imgupd* up, uchar* a, uint nb, int ctl, int fset) { int n; uchar *p, *ep; Rectangle r; static Rectangle wr; static Point wp; static int rop3; p = a; ep = a+nb; n = loadrect(&wr, p, ep-p, ctl&Diff, fset); p += n; if(fset&1<<4){ if(ep-p<1) sysfatal(Eshort); rop3 = *p++; } n = loadpt(&wp, p, ep-p, ctl&Diff, fset>>5); p += n; r = wr; if(ctl&Clip) rectclip(&r, gc.clipr); if(rop3 != Scopy) fprint(2, "scrblt: rop3 %#hhux is not supported\n", rop3); up->type = Uscrblt; up->x = r.min.x; up->y = r.min.y; up->xsz = Dx(r); up->ysz = Dy(r); up->sx = wp.x; up->sy = wp.y; return p-a; } static int getmemblt(Imgupd* up, uchar* a, uint nb, int ctl, int fset) { static int cid; /* cacheId */ static int coff; /* cacheIndex */ static int rop3; static Rectangle r; static Point pt; int n; uchar *p, *ep; p = a; ep = a+nb; if(fset&1<<0){ cid = igets(p); p += 2; } n = loadrect(&r, p, ep-p, ctl&Diff, fset>>1); p += n; if(fset&1<<5) rop3 = *p++; n = loadpt(&pt, p, ep-p, ctl&Diff, fset>>6); p += n; if(fset&1<<8){ coff = igets(p); p += 2; } if(p>ep) sysfatal("getmemblt: %s", Eshort); cid &= Bits8; up->type = Umemblt; up->cid = cid; up->coff = coff; up->x = r.min.x; up->y = r.min.y; up->xm = r.max.x-1; up->ym = r.max.y-1; up->xsz = Dx(r); up->ysz = Dy(r); up->sx = pt.x; up->sy = pt.y; up->clip = 0; if(ctl&Clip){ up->clip = 1; up->cx = gc.clipr.min.x; up->cy = gc.clipr.min.y; up->cxsz = Dx(gc.clipr); up->cysz = Dy(gc.clipr); } return p-a; } /* 2.2.2.2.1.2.3 Cache Bitmap - Revision 2 (CACHE_BITMAP_REV2_ORDER) */ static int getimgcache2(Imgupd* up, uchar* a, uint nb, int xorder, int opt) { uchar *p, *ep; int cid; /* cacheId */ int coff; /* cacheIndex */ int n, g; int size; p = a; ep = a+nb; up->compressed = (xorder==CacheCompressed2); cid = opt&Bits3; opt >>= 7; if(p+9 >= ep) sysfatal("cacheimage2: %s", Eshort); p += 6; if(opt&1<<1) p += 8; // persistent cache key g = *p++; if(g&1<<7) g = ((g&Bits7)<<8) | *p++; up->xsz = g; if(opt&1) up->ysz = g; else{ g = *p++; if(g&1<<7) g = ((g&Bits7)<<8) | *p++; up->ysz = g; } g = *p++; n = g>>6; g &= Bits6; switch(n){ default: sysfatal("cacheimage2: integer too big"); case 3: g = (g<<8) | *p++; case 2: g = (g<<8) | *p++; case 1: g = (g<<8) | *p++; } size = g; g = *p++; if(g&1<<7) g = ((g&Bits7)<<8) | *p++; coff = g; if(up->compressed && !(opt&1<<3)){ p += 8; // bitmapComprHdr size -= 8; } if(p+size > ep) sysfatal("cacheimage2: size: %s", Eshort); up->type = Ucacheimg; up->cid = cid; up->coff = coff; up->nbytes = size; up->bytes = p; return size; } /* 2.2.2.2.1.2.4 Cache Color Table (CACHE_COLOR_TABLE_ORDER) */ static int getcmapcache(Imgupd* up, uchar* a, uint nb, int xorder, int opt) { int cid, n; USED(xorder); USED(opt); cid = a[6]; n = igets(a+7); if(n != 256) sysfatal("cachecmap: %d != 256", n); if(9+4*256 > nb) sysfatal(Eshort); up->type = Umcache; up->cid = cid; up->bytes = a+9; up->nbytes = 4*256; return 9+4*256; }