/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include <pool.h> extern Pool* imagmem;int drawdebug;static int tablesbuilt; /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) /* * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation. * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation. * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole. *//* #define DIV255(x) (((x)*257+256)>>16) */#define DIV255(x) ((((x)+1)*257)>>16)/* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */ #define MUL(x, y, t) (t = (x)*(y)+128, (t+(t>>8))>>8)#define MASK13 0xFF00FF00#define MASK02 0x00FF00FF#define MUL13(a, x, t) (t = (a)*(((x)&MASK13)>>8)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)#define MUL02(a, x, t) (t = (a)*(((x)&MASK02)>>0)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)#define MUL0123(a, x, s, t) ((MUL13(a, x, s)<<8)|MUL02(a, x, t)) #define MUL2(u, v, x, y) (t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8) static void mktables(void);typedef int Subdraw(Memdrawparam*);static Subdraw chardraw, alphadraw, memoptdraw; static Memimage* memones;static Memimage* memzeros;Memimage *memwhite;Memimage *memblack;Memimage *memtransparent;Memimage *memopaque; int _ifmt(Fmt*); voidmemimageinit(void){ static int didinit = 0; if(didinit) return; didinit = 1; if(strcmp(imagmem->name, "Image") == 0 || strcmp(imagmem->name, "image") == 0) imagmem->move = memimagemove; mktables(); _memmkcmap(); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); fmtinstall('b', _ifmt); memones = allocmemimage(Rect(0,0,1,1), GREY1); memones->flags |= Frepl; memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memones, ZP) = ~0; memzeros = allocmemimage(Rect(0,0,1,1), GREY1); memzeros->flags |= Frepl; memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memzeros, ZP) = 0; if(memones == nil || memzeros == nil) assert(0 /*cannot initialize memimage library */); /* RSC BUG */ memwhite = memones; memblack = memzeros; memopaque = memones; memtransparent = memzeros;} static ulong imgtorgba(Memimage*, ulong);static ulong rgbatoimg(Memimage*, ulong);static ulong pixelbits(Memimage*, Point); #define DBG if(0)voidmemimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op){ static int n = 0; Memdrawparam par; if(mask == nil) mask = memopaque; DBG print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1); if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){// if(drawdebug)// iprint("empty clipped rectangle\n"); return; } if(op < Clear || op > SoverD){// if(drawdebug)// iprint("op out of range: %d\n", op); return; } par.op = op; par.dst = dst; par.r = r; par.src = src; /* par.sr set by drawclip */ par.mask = mask; /* par.mr set by drawclip */ par.state = 0; if(src->flags&Frepl){ par.state |= Replsrc; if(Dx(src->r)==1 && Dy(src->r)==1){ par.sval = pixelbits(src, src->r.min); par.state |= Simplesrc; par.srgba = imgtorgba(src, par.sval); par.sdval = rgbatoimg(dst, par.srgba); if((par.srgba&0xFF) == 0 && (op&DoutS)){// if (drawdebug) iprint("fill with transparent source\n"); return; /* no-op successfully handled */ } } } if(mask->flags & Frepl){ par.state |= Replmask; if(Dx(mask->r)==1 && Dy(mask->r)==1){ par.mval = pixelbits(mask, mask->r.min); if(par.mval == 0 && (op&DoutS)){// if(drawdebug) iprint("fill with zero mask\n"); return; /* no-op successfully handled */ } par.state |= Simplemask; if(par.mval == ~0) par.state |= Fullmask; par.mrgba = imgtorgba(mask, par.mval); } } // if(drawdebug)// iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state); /* * Now that we've clipped the parameters down to be consistent, we * simply try sub-drawing routines in order until we find one that was able * to handle us. If the sub-drawing routine returns zero, it means it was * unable to satisfy the request, so we do not return. */ /* * Hardware support. Each video driver provides this function, * which checks to see if there is anything it can help with. * There could be an if around this checking to see if dst is in video memory. */DBG print("test hwdraw\n"); if(hwdraw(&par)){//if(drawdebug) iprint("hw handled\n");DBG print("hwdraw handled\n"); return; } /* * Optimizations using memmove and memset. */DBG print("test memoptdraw\n"); if(memoptdraw(&par)){//if(drawdebug) iprint("memopt handled\n");DBG print("memopt handled\n"); return; } /* * Character drawing. * Solid source color being painted through a boolean mask onto a high res image. */DBG print("test chardraw\n"); if(chardraw(&par)){//if(drawdebug) iprint("chardraw handled\n");DBG print("chardraw handled\n"); return; } /* * General calculation-laden case that does alpha for each pixel. */DBG print("do alphadraw\n"); alphadraw(&par);//if(drawdebug) iprint("alphadraw handled\n");DBG print("alphadraw handled\n");}#undef DBG /* * Clip the destination rectangle further based on the properties of the * source and mask rectangles. Once the destination rectangle is properly * clipped, adjust the source and mask rectangles to be the same size. * Then if source or mask is replicated, move its clipped rectangle * so that its minimum point falls within the repl rectangle. * * Return zero if the final rectangle is null. */intdrawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr){ Point rmin, delta; int splitcoords; Rectangle omr; if(r->min.x>=r->max.x || r->min.y>=r->max.y) return 0; splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); /* clip to destination */ rmin = r->min; if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) return 0; /* move mask point */ p1->x += r->min.x-rmin.x; p1->y += r->min.y-rmin.y; /* move source point */ p0->x += r->min.x-rmin.x; p0->y += r->min.y-rmin.y; /* map destination rectangle into source */ sr->min = *p0; sr->max.x = p0->x+Dx(*r); sr->max.y = p0->y+Dy(*r); /* sr is r in source coordinates; clip to source */ if(!(src->flags&Frepl) && !rectclip(sr, src->r)) return 0; if(!rectclip(sr, src->clipr)) return 0; /* compute and clip rectangle in mask */ if(splitcoords){ /* move mask point with source */ p1->x += sr->min.x-p0->x; p1->y += sr->min.y-p0->y; mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); omr = *mr; /* mr is now rectangle in mask; clip it */ if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) return 0; if(!rectclip(mr, mask->clipr)) return 0; /* reflect any clips back to source */ sr->min.x += mr->min.x-omr.min.x; sr->min.y += mr->min.y-omr.min.y; sr->max.x += mr->max.x-omr.max.x; sr->max.y += mr->max.y-omr.max.y; *p1 = mr->min; }else{ if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) return 0; if(!rectclip(sr, mask->clipr)) return 0; *p1 = sr->min; } /* move source clipping back to destination */ delta.x = r->min.x - p0->x; delta.y = r->min.y - p0->y; r->min.x = sr->min.x + delta.x; r->min.y = sr->min.y + delta.y; r->max.x = sr->max.x + delta.x; r->max.y = sr->max.y + delta.y; /* move source rectangle so sr->min is in src->r */ if(src->flags&Frepl) { delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; sr->min.x += delta.x; sr->min.y += delta.y; sr->max.x += delta.x; sr->max.y += delta.y; } *p0 = sr->min; /* move mask point so it is in mask->r */ *p1 = drawrepl(mask->r, *p1); mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); assert(ptinrect(*p0, src->r)); assert(ptinrect(*p1, mask->r)); assert(ptinrect(r->min, dst->r)); return 1;} /* * Conversion tables. */static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */static uchar conv28[256][4]; /* ... */static uchar conv48[256][2]; /* * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. * the X's are where to put the bottom (ones) bit of the n-bit pattern. * only the top 8 bits of the result are actually used. * (the lower 8 bits are needed to get bits in the right place * when n is not a divisor of 8.) * * Should check to see if its easier to just refer to replmul than * use the precomputed values in replbit. On PCs it may well * be; on machines with slow multiply instructions it probably isn't. */#define a ((((((((((((((((0#define X *2+1)#define _ *2)static int replmul[1+8] = { 0, a X X X X X X X X X X X X X X X X, a _ X _ X _ X _ X _ X _ X _ X _ X, a _ _ X _ _ X _ _ X _ _ X _ _ X _, a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,};#undef a#undef X#undef _ static voidmktables(void){ int i, j, mask, sh, small; if(tablesbuilt) return; fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); tablesbuilt = 1; /* bit replication up to 8 bits */ for(i=0; i<256; i++){ for(j=0; j<=8; j++){ /* j <= 8 [sic] */ small = i & ((1<<j)-1); replbit[j][i] = (small*replmul[j])>>8; } } /* bit unpacking up to 8 bits, only powers of 2 */ for(i=0; i<256; i++){ for(j=0, sh=7, mask=1; j<8; j++, sh--) conv18[i][j] = replbit[1][(i>>sh)&mask]; for(j=0, sh=6, mask=3; j<4; j++, sh-=2) conv28[i][j] = replbit[2][(i>>sh)&mask]; for(j=0, sh=4, mask=15; j<2; j++, sh-=4) conv48[i][j] = replbit[4][(i>>sh)&mask]; }} static uchar ones = 0xff; /* * General alpha drawing case. Can handle anything. */typedef struct Buffer Buffer;struct Buffer { /* used by most routines */ uchar *red; uchar *grn; uchar *blu; uchar *alpha; uchar *grey; ulong *rgba; int delta; /* number of bytes to add to pointer to get next pixel to the right */ /* used by boolcalc* for mask data */ uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ int mskip; /* no. of left bits to skip in *m */ uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ int bmskip; /* no. of left bits to skip in *bm */ uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ int emskip; /* no. of right bits to skip in *em */}; typedef struct Param Param;typedef Buffer Readfn(Param*, uchar*, int);typedef void Writefn(Param*, uchar*, Buffer);typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int); enum { MAXBCACHE = 16}; /* giant rathole to customize functions with */struct Param { Readfn *replcall; Readfn *greymaskcall; Readfn *convreadcall; Writefn *convwritecall; Memimage *img; Rectangle r; int dx; /* of r */ int needbuf; int convgrey; int alphaonly; uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ int bwidth; int replcache; /* if set, cache buffers */ Buffer bcache[MAXBCACHE]; ulong bfilled; uchar *bufbase; int bufoff; int bufdelta; int dir; int convbufoff; uchar *convbuf; Param *convdpar; int convdx;}; static uchar *drawbuf;static int ndrawbuf;static int mdrawbuf;static Readfn greymaskread, replread, readptr;static Writefn nullwrite;static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;static Calcfn boolcalc14, boolcalc236789, boolcalc1011; static Readfn* readfn(Memimage*);static Readfn* readalphafn(Memimage*);static Writefn* writefn(Memimage*); static Calcfn* boolcopyfn(Memimage*, Memimage*);static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*);static Readfn* ptrfn(Memimage*); static Calcfn *alphacalc[Ncomp] = { alphacalc0, /* Clear */ alphacalc14, /* DoutS */ alphacalc2810, /* SoutD */ alphacalc3679, /* DxorS */ alphacalc14, /* DinS */ alphacalc5, /* D */ alphacalc3679, /* DatopS */ alphacalc3679, /* DoverS */ alphacalc2810, /* SinD */ alphacalc3679, /* SatopD */ alphacalc2810, /* S */ alphacalc11, /* SoverD */}; static Calcfn *boolcalc[Ncomp] ={ alphacalc0, /* Clear */ boolcalc14, /* DoutS */ boolcalc236789, /* SoutD */ boolcalc236789, /* DxorS */ boolcalc14, /* DinS */ alphacalc5, /* D */ boolcalc236789, /* DatopS */ boolcalc236789, /* DoverS */ boolcalc236789, /* SinD */ boolcalc236789, /* SatopD */ boolcalc1011, /* S */ boolcalc1011, /* SoverD */}; /* * Avoid standard Lock, QLock so that can be used in kernel. */Lines 1–500 of 2525. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> #include <pool.h> extern Pool* imagmem; int drawdebug; static int tablesbuilt; /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) /* * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation. * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation. * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole. */ /* #define DIV255(x) (((x)*257+256)>>16) */ #define DIV255(x) ((((x)+1)*257)>>16) /* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */ #define MUL(x, y, t) (t = (x)*(y)+128, (t+(t>>8))>>8) #define MASK13 0xFF00FF00 #define MASK02 0x00FF00FF #define MUL13(a, x, t) (t = (a)*(((x)&MASK13)>>8)+128, ((t+((t>>8)&MASK02))>>8)&MASK02) #define MUL02(a, x, t) (t = (a)*(((x)&MASK02)>>0)+128, ((t+((t>>8)&MASK02))>>8)&MASK02) #define MUL0123(a, x, s, t) ((MUL13(a, x, s)<<8)|MUL02(a, x, t)) #define MUL2(u, v, x, y) (t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8) static void mktables(void); typedef int Subdraw(Memdrawparam*); static Subdraw chardraw, alphadraw, memoptdraw; static Memimage* memones; static Memimage* memzeros; Memimage *memwhite; Memimage *memblack; Memimage *memtransparent; Memimage *memopaque; int _ifmt(Fmt*); void memimageinit(void) { static int didinit = 0; if(didinit) return; didinit = 1; if(strcmp(imagmem->name, "Image") == 0 || strcmp(imagmem->name, "image") == 0) imagmem->move = memimagemove; mktables(); _memmkcmap(); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); fmtinstall('b', _ifmt); memones = allocmemimage(Rect(0,0,1,1), GREY1); memones->flags |= Frepl; memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memones, ZP) = ~0; memzeros = allocmemimage(Rect(0,0,1,1), GREY1); memzeros->flags |= Frepl; memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memzeros, ZP) = 0; if(memones == nil || memzeros == nil) assert(0 /*cannot initialize memimage library */); /* RSC BUG */ memwhite = memones; memblack = memzeros; memopaque = memones; memtransparent = memzeros; } static ulong imgtorgba(Memimage*, ulong); static ulong rgbatoimg(Memimage*, ulong); static ulong pixelbits(Memimage*, Point); #define DBG if(0) void memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) { static int n = 0; Memdrawparam par; if(mask == nil) mask = memopaque; DBG print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1); if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){ // if(drawdebug) // iprint("empty clipped rectangle\n"); return; } if(op < Clear || op > SoverD){ // if(drawdebug) // iprint("op out of range: %d\n", op); return; } par.op = op; par.dst = dst; par.r = r; par.src = src; /* par.sr set by drawclip */ par.mask = mask; /* par.mr set by drawclip */ par.state = 0; if(src->flags&Frepl){ par.state |= Replsrc; if(Dx(src->r)==1 && Dy(src->r)==1){ par.sval = pixelbits(src, src->r.min); par.state |= Simplesrc; par.srgba = imgtorgba(src, par.sval); par.sdval = rgbatoimg(dst, par.srgba); if((par.srgba&0xFF) == 0 && (op&DoutS)){ // if (drawdebug) iprint("fill with transparent source\n"); return; /* no-op successfully handled */ } } } if(mask->flags & Frepl){ par.state |= Replmask; if(Dx(mask->r)==1 && Dy(mask->r)==1){ par.mval = pixelbits(mask, mask->r.min); if(par.mval == 0 && (op&DoutS)){ // if(drawdebug) iprint("fill with zero mask\n"); return; /* no-op successfully handled */ } par.state |= Simplemask; if(par.mval == ~0) par.state |= Fullmask; par.mrgba = imgtorgba(mask, par.mval); } } // if(drawdebug) // iprint("dr %R sr %R mr %R...", r, par.sr, par.mr); DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state); /* * Now that we've clipped the parameters down to be consistent, we * simply try sub-drawing routines in order until we find one that was able * to handle us. If the sub-drawing routine returns zero, it means it was * unable to satisfy the request, so we do not return. */ /* * Hardware support. Each video driver provides this function, * which checks to see if there is anything it can help with. * There could be an if around this checking to see if dst is in video memory. */ DBG print("test hwdraw\n"); if(hwdraw(&par)){ //if(drawdebug) iprint("hw handled\n"); DBG print("hwdraw handled\n"); return; } /* * Optimizations using memmove and memset. */ DBG print("test memoptdraw\n"); if(memoptdraw(&par)){ //if(drawdebug) iprint("memopt handled\n"); DBG print("memopt handled\n"); return; } /* * Character drawing. * Solid source color being painted through a boolean mask onto a high res image. */ DBG print("test chardraw\n"); if(chardraw(&par)){ //if(drawdebug) iprint("chardraw handled\n"); DBG print("chardraw handled\n"); return; } /* * General calculation-laden case that does alpha for each pixel. */ DBG print("do alphadraw\n"); alphadraw(&par); //if(drawdebug) iprint("alphadraw handled\n"); DBG print("alphadraw handled\n"); } #undef DBG /* * Clip the destination rectangle further based on the properties of the * source and mask rectangles. Once the destination rectangle is properly * clipped, adjust the source and mask rectangles to be the same size. * Then if source or mask is replicated, move its clipped rectangle * so that its minimum point falls within the repl rectangle. * * Return zero if the final rectangle is null. */ int drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr) { Point rmin, delta; int splitcoords; Rectangle omr; if(r->min.x>=r->max.x || r->min.y>=r->max.y) return 0; splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); /* clip to destination */ rmin = r->min; if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) return 0; /* move mask point */ p1->x += r->min.x-rmin.x; p1->y += r->min.y-rmin.y; /* move source point */ p0->x += r->min.x-rmin.x; p0->y += r->min.y-rmin.y; /* map destination rectangle into source */ sr->min = *p0; sr->max.x = p0->x+Dx(*r); sr->max.y = p0->y+Dy(*r); /* sr is r in source coordinates; clip to source */ if(!(src->flags&Frepl) && !rectclip(sr, src->r)) return 0; if(!rectclip(sr, src->clipr)) return 0; /* compute and clip rectangle in mask */ if(splitcoords){ /* move mask point with source */ p1->x += sr->min.x-p0->x; p1->y += sr->min.y-p0->y; mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); omr = *mr; /* mr is now rectangle in mask; clip it */ if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) return 0; if(!rectclip(mr, mask->clipr)) return 0; /* reflect any clips back to source */ sr->min.x += mr->min.x-omr.min.x; sr->min.y += mr->min.y-omr.min.y; sr->max.x += mr->max.x-omr.max.x; sr->max.y += mr->max.y-omr.max.y; *p1 = mr->min; }else{ if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) return 0; if(!rectclip(sr, mask->clipr)) return 0; *p1 = sr->min; } /* move source clipping back to destination */ delta.x = r->min.x - p0->x; delta.y = r->min.y - p0->y; r->min.x = sr->min.x + delta.x; r->min.y = sr->min.y + delta.y; r->max.x = sr->max.x + delta.x; r->max.y = sr->max.y + delta.y; /* move source rectangle so sr->min is in src->r */ if(src->flags&Frepl) { delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; sr->min.x += delta.x; sr->min.y += delta.y; sr->max.x += delta.x; sr->max.y += delta.y; } *p0 = sr->min; /* move mask point so it is in mask->r */ *p1 = drawrepl(mask->r, *p1); mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); assert(ptinrect(*p0, src->r)); assert(ptinrect(*p1, mask->r)); assert(ptinrect(r->min, dst->r)); return 1; } /* * Conversion tables. */ static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */ static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */ static uchar conv28[256][4]; /* ... */ static uchar conv48[256][2]; /* * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. * the X's are where to put the bottom (ones) bit of the n-bit pattern. * only the top 8 bits of the result are actually used. * (the lower 8 bits are needed to get bits in the right place * when n is not a divisor of 8.) * * Should check to see if its easier to just refer to replmul than * use the precomputed values in replbit. On PCs it may well * be; on machines with slow multiply instructions it probably isn't. */ #define a ((((((((((((((((0 #define X *2+1) #define _ *2) static int replmul[1+8] = { 0, a X X X X X X X X X X X X X X X X, a _ X _ X _ X _ X _ X _ X _ X _ X, a _ _ X _ _ X _ _ X _ _ X _ _ X _, a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X, }; #undef a #undef X #undef _ static void mktables(void) { int i, j, mask, sh, small; if(tablesbuilt) return; fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); tablesbuilt = 1; /* bit replication up to 8 bits */ for(i=0; i<256; i++){ for(j=0; j<=8; j++){ /* j <= 8 [sic] */ small = i & ((1<<j)-1); replbit[j][i] = (small*replmul[j])>>8; } } /* bit unpacking up to 8 bits, only powers of 2 */ for(i=0; i<256; i++){ for(j=0, sh=7, mask=1; j<8; j++, sh--) conv18[i][j] = replbit[1][(i>>sh)&mask]; for(j=0, sh=6, mask=3; j<4; j++, sh-=2) conv28[i][j] = replbit[2][(i>>sh)&mask]; for(j=0, sh=4, mask=15; j<2; j++, sh-=4) conv48[i][j] = replbit[4][(i>>sh)&mask]; } } static uchar ones = 0xff; /* * General alpha drawing case. Can handle anything. */ typedef struct Buffer Buffer; struct Buffer { /* used by most routines */ uchar *red; uchar *grn; uchar *blu; uchar *alpha; uchar *grey; ulong *rgba; int delta; /* number of bytes to add to pointer to get next pixel to the right */ /* used by boolcalc* for mask data */ uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ int mskip; /* no. of left bits to skip in *m */ uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ int bmskip; /* no. of left bits to skip in *bm */ uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ int emskip; /* no. of right bits to skip in *em */ }; typedef struct Param Param; typedef Buffer Readfn(Param*, uchar*, int); typedef void Writefn(Param*, uchar*, Buffer); typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int); enum { MAXBCACHE = 16 }; /* giant rathole to customize functions with */ struct Param { Readfn *replcall; Readfn *greymaskcall; Readfn *convreadcall; Writefn *convwritecall; Memimage *img; Rectangle r; int dx; /* of r */ int needbuf; int convgrey; int alphaonly; uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ int bwidth; int replcache; /* if set, cache buffers */ Buffer bcache[MAXBCACHE]; ulong bfilled; uchar *bufbase; int bufoff; int bufdelta; int dir; int convbufoff; uchar *convbuf; Param *convdpar; int convdx; }; static uchar *drawbuf; static int ndrawbuf; static int mdrawbuf; static Readfn greymaskread, replread, readptr; static Writefn nullwrite; static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS; static Calcfn boolcalc14, boolcalc236789, boolcalc1011; static Readfn* readfn(Memimage*); static Readfn* readalphafn(Memimage*); static Writefn* writefn(Memimage*); static Calcfn* boolcopyfn(Memimage*, Memimage*); static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*); static Readfn* ptrfn(Memimage*); static Calcfn *alphacalc[Ncomp] = { alphacalc0, /* Clear */ alphacalc14, /* DoutS */ alphacalc2810, /* SoutD */ alphacalc3679, /* DxorS */ alphacalc14, /* DinS */ alphacalc5, /* D */ alphacalc3679, /* DatopS */ alphacalc3679, /* DoverS */ alphacalc2810, /* SinD */ alphacalc3679, /* SatopD */ alphacalc2810, /* S */ alphacalc11, /* SoverD */ }; static Calcfn *boolcalc[Ncomp] = { alphacalc0, /* Clear */ boolcalc14, /* DoutS */ boolcalc236789, /* SoutD */ boolcalc236789, /* DxorS */ boolcalc14, /* DinS */ alphacalc5, /* D */ boolcalc236789, /* DatopS */ boolcalc236789, /* DoverS */ boolcalc236789, /* SinD */ boolcalc236789, /* SatopD */ boolcalc1011, /* S */ boolcalc1011, /* SoverD */ }; /* * Avoid standard Lock, QLock so that can be used in kernel. */