ref: 3a9bd2b51c2c1627c4dabac83f83af3a5c0b86be
dir: /egdi.c/
/* * [MS-RDPEGDI]: Graphics Device Interface (GDI) Acceleration Extensions * http://msdn.microsoft.com/en-us/library/cc241537.aspx */ #include <u.h> #include <libc.h> #include <draw.h> #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) */ { Clipped= 1<<2, NewOrder= 1<<3, Diff= 1<<4, SameClipping= 1<<5, ZeroFieldBit0= 1<<6, ZeroFieldBit1= 1<<7, }; enum { ROP2_COPY = 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, }; typedef struct Order Order; struct Order { int fsize; uchar* (*fn)(Rdp*, uchar*,uchar*,int,int); }; static uchar* scrblt(Rdp*, uchar*,uchar*,int,int); static uchar* memblt(Rdp*, uchar*,uchar*,int,int); static uchar* cacheimage2(Rdp*, uchar*,uchar*,int,int); static uchar* cachecmap(Rdp*, uchar*,uchar*,int,int); Order ordtab[NumOrders] = { [ScrBlt]= { 1, scrblt }, [MemBlt]= { 2, memblt }, }; Order auxtab[8] = { [CacheImage2]= { 0, cacheimage2 }, [CacheCompressed2]= { 0, cacheimage2 }, [CacheCmap]= { 0, cachecmap }, }; uchar orderSupport[NumOrders] = { [CanScrBlt] 1, [CanMemBlt] 1, }; static struct GdiContext { int order; Rectangle clipr; } gc = {PatBlt}; static uchar* getclipr(Rectangle*,uchar*,uchar*); static uchar* getpt(Point*,uchar*,uchar*,int,int); /* 2.2.2.2 Fast-Path Orders Update (TS_FP_UPDATE_ORDERS) */ void scanorders(Rdp* c, Share* as) { int count; uchar *p, *ep; int ctl, fset, fsize; int size, opt, xorder; count = as->nord; p = as->data; ep = as->data + as->ndata; while(count-- > 0 && p<ep){ fset = 0; ctl = *p; if(!(ctl&Standard)) goto ErrNstd; // GDI+ or out of sync if(ctl&Secondary){ if(p+6>ep) sysfatal("scanorders: %s", Eshort); size = ((short)GSHORT(p+1))+13; if(size < 0 || p+size > ep) sysfatal("scanorders: size: %s", Eshort); opt = GSHORT(p+3); xorder = p[5]; if(xorder >= nelem(auxtab) || auxtab[xorder].fn == nil){ fprint(2, "egdi: unsupported secondary order %d\n", xorder); p += size; continue; } auxtab[xorder].fn(c, p, p+size, xorder, opt); p += size; continue; } 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 = GSHORT(p); break; case 1: fset = p[0]; case 0: break; } p += fsize; if(ctl&Clipped && !(ctl&SameClipping)) p = getclipr(&gc.clipr, p, ep); if(ordtab[gc.order].fn == nil) goto ErrNotsup; p = ordtab[gc.order].fn(c, p, ep, ctl, fset); if(p == nil) break; } if(display->locking) lockdisplay(display); flushimage(display, 1); if(display->locking) unlockdisplay(display); return; ErrNstd: fprint(2, "egdi: non-standard order\n"); return; ErrFsize: fprint(2, "egdi: bad field encoding bytes count for order %d\n", gc.order); return; ErrNotsup: fprint(2, "egdi: unsupported order %d\n", gc.order); return; } static uchar* getclipr(Rectangle* pr, uchar* p, uchar* ep) { int bctl; bctl = *p++; if(bctl&1<<4) pr->min.x += (char)*p++; else if(bctl&1<<0){ pr->min.x = GSHORT(p); p += 2; } if(bctl&1<<5) pr->min.y += (char)*p++; else if(bctl&1<<1){ pr->min.y = GSHORT(p); p += 2; } if(bctl&1<<6) pr->max.x += (char)*p++; else if(bctl&1<<2){ pr->max.x = GSHORT(p)+1; p += 2; } if(bctl&1<<7) pr->max.y += (char)*p++; else if(bctl&1<<3){ pr->max.y = GSHORT(p)+1; p += 2; } if(p>ep) sysfatal("getclipr: %s", Eshort); return p; } static uchar* getpt(Point* pp, uchar* s, uchar *es, int ctl, int fset) { Point p; p = *pp; if(ctl&Diff){ if(fset&1<<0) p.x += (char)*s++; if(fset&1<<1) p.y += (char)*s++; }else{ if(fset&1<<0){ p.x = GSHORT(s); s += 2; }; if(fset&1<<1){ p.y = GSHORT(s); s += 2; }; } if(s > es) sysfatal("getpt: %s", Eshort); *pp = p; return s; } static uchar* getoffrect(Rectangle* pr, uchar* p, uchar* ep, int ctl, int fset){ Rectangle r; r = *pr; r.max = subpt(r.max, r.min); p = getpt(&r.min, p, ep, ctl, fset); p = getpt(&r.max, p, ep, ctl, fset>>2); r.max = addpt(r.max, r.min); *pr = r; return p; } /* 2.2.2.2.1.1.2.7 ScrBlt (SCRBLT_ORDER) */ static uchar* scrblt(Rdp*, uchar* p, uchar* ep, int ctl, int fset) { static Rectangle wr; static Point wp; static int rop3; Rectangle r, sr; p = getoffrect(&wr, p, ep, ctl, fset); if(fset&1<<4) rop3 = *p++; p = getpt(&wp, p, ep, ctl, fset>>5); if(ctl&Clipped) rectclip(&wr, gc.clipr); if(rop3 != ROP2_COPY){ fprint(2, "scrblt: rop3 %#hhux is not supported\n", rop3); return p; } r = rectaddpt(wr, screen->r.min); sr = rectaddpt(Rpt(wp, Pt(Dx(r), Dy(r))), screen->r.min); scroll(display, r, sr); return p; } uchar* getmemblt(Imgupd* iu, uchar* p, uchar* ep, int ctl, int fset) { static int cid; /* cacheId */ static int coff; /* cacheIndex */ static int rop3; static Rectangle r; static Point pt; if(fset&1<<0){ cid = GSHORT(p); p += 2; } p = getoffrect(&r, p, ep, ctl, fset>>1); if(fset&1<<5) rop3 = *p++; p = getpt(&pt, p, ep, ctl, fset>>6); if(fset&1<<8){ coff = GSHORT(p); p += 2; } if(p>ep) sysfatal("getmemblt: %s", Eshort); cid &= Bits8; iu->cid = cid; iu->coff = coff; iu->x = r.min.x; iu->y = r.min.y; iu->xm = r.max.x-1; iu->ym = r.max.y-1; iu->xsz = Dx(r); iu->ysz = Dy(r); iu->sx = pt.x; iu->sy = pt.y; return p; } /* 2.2.2.2.1.1.2.9 MemBlt (MEMBLT_ORDER) */ static uchar* memblt(Rdp* c, uchar* p, uchar* ep, int ctl, int fset) { Imgupd u; p = getmemblt(&u, p, ep, ctl, fset); if(display->locking) lockdisplay(display); if(ctl&Clipped) replclipr(screen, screen->repl, rectaddpt(gc.clipr, screen->r.min)); drawmemimg(c, &u); if(ctl&Clipped) replclipr(screen, screen->repl, screen->r); if(display->locking) unlockdisplay(display); return p; } int getimgcache2(Imgupd* iu, 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; iu->iscompr = (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++; iu->xsz = g; if(opt&1) iu->ysz = g; else{ g = *p++; if(g&1<<7) g = ((g&Bits7)<<8) | *p++; iu->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(iu->iscompr && !(opt&1<<3)){ p += 8; // bitmapComprHdr size -= 8; } if(p+size > ep) sysfatal("cacheimage2: size: %s", Eshort); iu->cid = cid; iu->coff = coff; iu->nbytes = size; iu->bytes = p; return size; } /* 2.2.2.2.1.2.3 Cache Bitmap - Revision 2 (CACHE_BITMAP_REV2_ORDER) */ static uchar* cacheimage2(Rdp* c, uchar* p, uchar* ep, int xorder, int opt) { int size; Imgupd iupd, *iu; iu = &iupd; size = getimgcache2(iu, p, ep-p, xorder, opt); loadmemimg(c, iu); return p+size; } /* 2.2.2.2.1.2.4 Cache Color Table (CACHE_COLOR_TABLE_ORDER) */ static uchar* cachecmap(Rdp*, uchar* p,uchar* ep, int, int) { int cid, n; cid = p[6]; n = GSHORT(p+7); if(n != 256){ fprint(2, "cachecmap: %d != 256\n", n); return nil; } if(p+9+4*256>ep){ werrstr(Eshort); return nil; } /* fixed cmap here */ USED(cid); return p+9+4*256; }