#ifndef lint static char sccsid[] = "@(#)canvas.c 9.6 88/01/19 Copyright 1985 Sun Micro"; #endif /*- Routines for dealing with canvases canvas.c, Mon Sep 30 11:54:25 1985 */ #include #ifdef REF #include #include #endif #include "shape.h" #include "canvas.h" #include "fontcache.h" #include "qalloc.h" #include #include int cv_seq; static cv_rop(); static cv_stencil(); static cv_batchrop(); static cv_nop(); int cv_destroy(); static cv_get(); static cv_put(); static cv_vector(); static struct pixrect *cv_region(); static cv_putcolormap(); static cv_getcolormap(); static cv_putattributes(); static cv_getattributes(); static cv_shapetext(); static cv_shaperop(); static cv_shapecurve(); static cv_shapevector(); struct color black_color, white_color; struct canvas *cv_damage_list; /* The list of damaged canvases */ struct pixrectops cv_ops = {cv_rop, cv_stencil, cv_batchrop, cv_nop, cv_destroy, cv_get, cv_put, cv_vector, cv_region, cv_putcolormap, cv_getcolormap, cv_putattributes, cv_getattributes, cv_shapetext, cv_shaperop, cv_shapecurve, cv_shapevector, generic_replrop, }; static cv_rop(dpr, dx, dy, w, h, op, spr, sx, sy) register struct canvas *spr; register struct canvas *dpr; { struct shape shape; shape.pos.x = dx; shape.pos.y = dy; shape.size.x = w; shape.size.y = h; shape.is_rect = 1; if (cv_is_canvas(dpr)) if (spr == dpr) { /* spr == dpr */ register struct shape *vp; extern struct shape *cv_compute_visible_part(); register struct canvas *parent = dpr->opaqparent; vp = cv_compute_visible_part(parent, 1); if (parent->damage) { register struct shape *t1, *t2; sh_incref(parent->damage); t1 = sh_translate(parent->damage, dx - sx, dy - sy); t2 = sh_intersect(t1, &shape); if (t2) { cv_extend_damage(parent, t2); sh_decref(t2); } sh_decref(t1); } if (spr->retained_part.clip == 0 /* Screen part only */ && spr->screen_part.clip != 0 /* * && (spr->screen_part.clip->is_rect || * spr->screen_part.clip->trapset->next == 0) */ ) { register struct shape *dst = sh_intersect(&shape, spr->screen_part.clip); if (dst) { pr_shaperop(spr->screen_part.pixrect, dst, op, spr->screen_part.pixrect, dx - sx, dy - sy); sh_decref(dst); } if (!spr->retained && vp != spr->outerclip) { shape.pos.x = sx; shape.pos.y = sy; dst = sh_difference(&shape, spr->screen_part.clip); if (dst) { trim_traps(dst); dst = sh_translate(dst, dx - sx, dy - sy); pr_shaperop(&spr->pixrect, dst, 0, 0, 0, 0); /* zap behind */ cv_extend_damage(spr, dst); sh_decref(dst); } } } else if (spr->retained) { /* * This code is really stupid -- it badly needs to be fixed */ if (!parent->complete && vp) /* copy to retained */ pr_shaperop(parent->retained_part.pixrect, vp, PIX_SRC, parent->screen_part.pixrect, 0, 0); pr_rop(parent->retained_part.pixrect, dx, dy, w, h, op, parent->retained_part.pixrect, sx, sy); pr_shaperop(parent->screen_part.pixrect, vp, PIX_SRC, parent->retained_part.pixrect, 0, 0); /*XXX parent->complete = 1; */ } else { register struct shape *dst = sh_intersect(&shape, spr->screen_part.clip); if (dst) { register struct pixrect *temp = mem_create(w, h, dpr->pixrect.pr_depth); pr_rop(temp, 0, 0, w, h, PIX_SRC, dpr->screen_part.pixrect, sx, sy); pr_shaperop(dpr->screen_part.pixrect, dst, op, temp, dx, dy); sh_decref(dst); pr_destroy(temp); } if (!spr->retained && vp != spr->outerclip) { shape.pos.x = sx; shape.pos.y = sy; dst = sh_difference(&shape, spr->screen_part.clip); if (dst) { trim_traps(dst); dst = sh_translate(dst, dx - sx, dy - sy); pr_shaperop(&spr->pixrect, dst, 0, 0, 0, 0); /* zap behind */ cv_extend_damage(spr->opaqparent, dst); sh_decref(dst); } } } } else { register struct canvas_part *cp = dpr->parts; register n = 2; while (--n >= 0) { if (cp->clip) { register struct shape *dst = sh_intersect(cp->clip, &shape); if (dst) { pr_shaperop(cp->pixrect, dst, op, spr, dx - sx, dy - sy); sh_decref(dst); } } cp++; } dpr->opaqparent->complete = 0; } else { register struct canvas_part *cp = spr->parts; register n = 2; assert(cv_is_canvas(spr)); while (--n >= 0) { if (cp->clip) { register struct shape *dst = sh_intersect(cp->clip, &shape); if (dst) { pr_shaperop((struct pixrect *) dpr, dst, op, cp->pixrect, dx - sx, dy - sy); sh_decref(dst); } } cp++; } } return 0; } static cv_stencil(dpr, dx, dy, w, h, op, stpr, stx, sty, spr, sx, sy) register struct canvas *spr, *stpr, *dpr; { panic("cv_stencil"); } static cv_batchrop(dpr, x, y, op, sbp, n) register struct canvas *dpr; { panic("cv_batchrop"); } static cv_nop() { panic("cv_nop"); } int (*cv_canvasdestructionhook) (); cv_destroy(pr) register struct canvas *pr; { if (pr) { if (pr->overlay) { ovl_destroy(pr); return; } if (cv_canvasdestructionhook) (*cv_canvasdestructionhook) (pr); if (pr->refcnt > 0) return; if (pr->indamqueue) { register struct canvas **prev; for (prev = &cv_damage_list; *prev; prev = &(*prev)->damnext) if (*prev == pr) { *prev = pr->damnext; /* printf("eliminated a cv from the damage list\n"); */ #ifdef DEBUG prev = 0; #endif break; } assert(prev == 0); } pr->signature = 0; cs_remove(pr, 0); if (pr->outerclip) sh_decref(pr->outerclip); if (pr->globalclip) sh_decref(pr->globalclip); if (pr->lastclip && pr->lastclip != &InvalidShape) sh_decref(pr->lastclip); if (pr->screen_part.pixrect) pr_destroy(pr->screen_part.pixrect); if (pr->screen_part.clip) sh_decref(pr->screen_part.clip); if (pr->retained_part.pixrect) pr_destroy(pr->retained_part.pixrect); if (pr->retained_part.clip) sh_decref(pr->retained_part.clip); if (pr->cdata.psfont) psf_decref(pr->cdata.psfont); qtfree(pr); } } static cv_get(pr, x, y) register struct canvas *pr; { panic("cv_get"); } static cv_put(pr, x, y, val) register struct canvas *pr; { panic("cv_put"); } static cv_vector(pr, x0, y0, x1, y1, op, color) register struct canvas *pr; { register struct canvas_part *cp = pr->parts; register n; n = 2; pr->opaqparent->complete = 0; while (--n >= 0) { if (cp->clip) pr_shapevector(cp->pixrect, cp->clip, x0, y0, x1, y1, op, color); cp++; } } static struct pixrect * cv_region(pr, x, y, w, h) register struct canvas *pr; { panic("cv_region"); } static cv_putcolormap(pr, ind, cnt, red, grn, blu) register struct canvas *pr; { if (pr->screen_part.pixrect) pr_putcolormap(pr->screen_part.pixrect, ind, cnt, red, grn, blu); } static cv_getcolormap(pr, ind, cnt, red, grn, blu) register struct canvas *pr; { if (pr->screen_part.pixrect) pr_getcolormap(pr->screen_part.pixrect, ind, cnt, red, grn, blu); } static cv_putattributes(pr, planes) register struct canvas *pr; { panic("cv_putattributes"); } static cv_getattributes(pr, planes) register struct canvas *pr; { panic("cv_getattributes"); } static cv_shapetext(dpr, op, font, shape, ri, ril) register struct canvas *dpr; register struct font *font; register struct shape *shape; { register struct canvas_part *cp = dpr->parts; register n; if (shape == 0) return 0; n = 2; dpr->opaqparent->complete = 0; while (--n >= 0) { if (cp->clip) if (shape == &InfiniteShape) pr_shapetext(cp->pixrect, op, font, cp->clip, ri, ril); else { register struct shape *dst = sh_intersect(cp->clip, shape); if (dst) { pr_shapetext(cp->pixrect, op, font, dst, ri, ril); sh_decref(dst); } } cp++; } return 0; } static cv_shaperop(dpr, shape, op, spr, x, y) register struct canvas *spr, *dpr; register struct shape *shape; { if (shape == 0) return 0; dpr->opaqparent->complete = 0; if (cv_is_canvas((struct pixrect *) dpr)) if (spr != dpr || dpr->retained_part.clip == 0 && dpr->retained || dpr->screen_part.clip == 0) { register struct canvas_part *cp = dpr->parts; register n = 2; while (--n >= 0) { if (cp->clip) { register struct shape *dst = sh_intersect(cp->clip, shape); if (dst) { pr_shaperop(cp->pixrect, dst, op, spr, x, y); sh_decref(dst); } } cp++; } } else { /* spr == dpr */ register struct canvas *parent = dpr->opaqparent; if (parent->damage) { register struct shape *t1, *t2; sh_incref(parent->damage); t1 = sh_translate(parent->damage, x, y); t2 = sh_intersect(t1, shape); if (t2) { cv_extend_damage(parent, t2); sh_decref(t2); } sh_decref(t1); } if (spr->retained_part.clip == 0 && spr->screen_part.clip != 0 /* && (spr->screen_part.clip->is_rect || spr->screen_part.clip->trapset->next == 0) */) { register struct shape *dst = sh_intersect(shape, spr->screen_part.clip); if (dst) { pr_shaperop(spr->screen_part.pixrect, dst, op, spr->screen_part.pixrect, x, y); sh_decref(dst); } if (!spr->retained && spr->screen_part.clip != spr->outerclip) { register struct shape *tsh = shape; sh_incref(tsh); tsh = sh_translate(tsh, -x, -y); dst = sh_difference(tsh, spr->screen_part.clip); sh_decref(tsh); if (dst) { trim_traps(dst); dst = sh_translate(dst, x, y); pr_shaperop(&spr->pixrect, dst, 0, 0, 0, 0); /* zap behind */ cv_extend_damage(spr, dst); sh_decref(dst); } } } else if (spr->retained) { register struct shape *rsrc; register struct shape *rdst = sh_intersect(shape, spr->screen_part.clip); rsrc = shape; sh_incref(rsrc); rsrc = sh_intersect(sh_translate(rsrc, -x, -y), spr->screen_part.clip); trim_traps(rsrc); trim_traps(rdst); if (!parent->complete && rsrc) /* copy to retained */ pr_shaperop(spr->retained_part.pixrect, rsrc, PIX_SRC, spr->screen_part.pixrect, 0, 0); pr_shaperop(spr->retained_part.pixrect, shape, PIX_SRC, spr->retained_part.pixrect, x, y); pr_shaperop(spr->screen_part.pixrect, rdst, PIX_SRC, spr->retained_part.pixrect, 0, 0); if (rsrc) sh_decref(rsrc); if (rdst) sh_decref(rdst); } else { register struct shape *dst = sh_intersect(shape, spr->screen_part.clip); register struct pixrect *temp; if (dst) { temp = mem_create(dst->size.x, dst->size.y, dpr->pixrect.pr_depth); pr_rop(temp, 0, 0, dst->size.x, dst->size.y, PIX_SRC, dpr->screen_part.pixrect, shape->pos.x, shape->pos.y); pr_shaperop(dpr->screen_part.pixrect, dst, op, temp, shape->pos.x + x, shape->pos.y + y); sh_decref(dst); pr_destroy(temp); } if (!spr->retained && spr->screen_part.clip != spr->outerclip) { register struct shape *tsh = shape; sh_incref(tsh); tsh = sh_translate(tsh, -x, -y); dst = sh_difference(tsh, spr->screen_part.clip); sh_decref(tsh); if (dst) { trim_traps(dst); dst = sh_translate(dst, x, y); pr_shaperop(&spr->pixrect, dst, 0, 0, 0, 0); /* zap behind */ cv_extend_damage(spr, dst); sh_decref(dst); } } } } else if (spr == 0 || !cv_is_canvas((struct pixrect *) spr)) panic("cv_shaperop"); else { /* * Work Needed: offset shape; deal with matching source & dest * pixrects(move to retained) */ register struct canvas_part *cp = spr->parts; register n = 2; while (--n >= 0) { if (cp->clip) { register struct shape *dst, *ssh; ssh = shape; sh_incref(ssh); ssh = sh_translate(ssh, x, y); dst = sh_intersect(ssh, shape); sh_decref(ssh); if (dst) { pr_shaperop(cp->pixrect, dst, op, spr, x, y); sh_decref(dst); } } cp++; } } return 0; } static cv_shapecurve(dpr, shape, dcurve, op, texture, phase) register struct canvas *dpr; register struct shape *shape; { register struct canvas_part *cp = dpr->parts; register n; if (shape == 0) return 0; n = 2; dpr->opaqparent->complete = 0; while (--n >= 0) { if (cp->clip) if (shape == &InfiniteShape) pr_shapecurve(cp->pixrect, cp->clip, dcurve, op, texture, phase); else { register struct shape *dst = sh_intersect(cp->clip, shape); if (dst) { pr_shapecurve(cp->pixrect, dst, dcurve, op, texture, phase); sh_decref(dst); } } cp++; } return 0; } static cv_shapevector(pr, shape, x0, y0, x1, y1, op, color) register struct canvas *pr; register struct shape *shape; { register struct canvas_part *cp = pr->parts; register n; if (shape == 0) return 0; n = 2; pr->opaqparent->complete = 0; while (--n >= 0) { if (cp->clip) if (shape == &InfiniteShape) pr_shapevector(cp->pixrect, cp->clip, x0, y0, x1, y1, op, color); else { register struct shape *dst = sh_intersect(cp->clip, shape); if (dst) { pr_shapevector(cp->pixrect, dst, x0, y0, x1, y1, op, color); sh_decref(dst); } } cp++; } return 0; } /* * Here I descend to the use of obscenities: these should all be flushed * when the problem with win_screennew is eliminated and it no longer * trashes color maps */ static struct pixrect *ScrewedUpPR; int (*RepairColorMap) (); FixScrewup() { if (ScrewedUpPR) cs_initialize_colormaps(ScrewedUpPR); } struct canvas * cv_create_screen_canvas(fn) char *fn; { register struct canvas *cv; register struct scene *sc; register struct pixrect *pr; extern struct canvas *cv_create_canvas(); extern struct pixrect *osi_create_screen_device(); #ifdef PREVIEW pr = (struct pixrect *) preview_getpr(); #else if ((pr = osi_create_screen_device(fn)) == 0) return 0; #endif white_color.red = 0xff; white_color.green = 0xff; white_color.blue = 0xff; white_color.hint = grey_inverse[0xFF]; black_color.hint = grey_inverse[0]; cv = cv_create_canvas(0, pr->pr_size.x, pr->pr_size.y); cv->pixrect.pr_depth = pr->pr_depth; cs_initialize_colormaps(pr); if (pr->pr_depth > 1) { RepairColorMap = FixScrewup; ScrewedUpPR = pr; } cv->screen_part.pixrect = pr; #ifdef undef if (0) { char bkg[400]; register FILE *f = 0; register struct pixrect *pr; struct pixrect *cs_readimage(); sprintf(bkg, "%s/.background", getenv("HOME")); if ((f = fopen(bkg, "r")) && (pr = cs_readimage(f))) if (pr->pr_width < 100) cv->retained_part.pixrect = tile_create(pr); else cv->retained_part.pixrect = pr; else cv->retained_part.pixrect = tile_create(&background); if (f) fclose(f); pr_rop(pr, 0, 0, pr->pr_width, pr->pr_height, PIX_SRC, cv->retained_part.pixrect, 0, 0); cv->retained = 1; } #endif cv->screen_part.clip = cv->outerclip; cv->mapped = 1; cv->map_req = 1; cv->validpix = 1; cv->refcnt = 99; sh_incref(cv->screen_part.clip); qtalloc(sc, (struct scene *)); sc->canvases = cv; cv->scene = sc; sc->display = pr; /* * This should really be dependent on the characteristics of the * display, but right now there is no way of finding that out */ sc->matrix[0][0] = fracti(1); sc->matrix[0][1] = fracti(0); sc->matrix[1][0] = fracti(0); sc->matrix[1][1] = fracti(1); sc->matrix[2][0] = fracti(0); sc->matrix[2][1] = fracti(0); bcopy(sc->matrix, cv->matrix, sizeof (FMATRIX)); scene_initialize (); return cv; } struct canvas * cv_create_canvas(parent, width, height) struct canvas *parent; { register struct canvas *cv; register struct shape *cl; qtalloc(cv, (struct canvas *)); bzero(cv, sizeof *cv); cv->pixrect.pr_size.x = width; cv->pixrect.pr_size.y = height; cv->pixrect.pr_ops = &cv_ops; cv->pixrect.pr_canvas = 1; cv->hasopaque = 0; cv->signature = CANVASSIGNATURE; if (parent) { cv->pixrect.pr_depth = parent->pixrect.pr_depth; if (parent->parent) cv->transparent = 1; else parent->hasopaque = 1; cv_incref(parent); /* Inherit cursor */ if (parent->cdata.psfont) { cv->cdata = parent->cdata; psf_incref(cv->cdata.psfont); } } else { cv->pixrect.pr_depth = 1; } if (cv->transparent) { cv->opaqparent = parent->opaqparent; cv->events_consumed = MatchedEvents; } else { cv->opaqparent = cv; cv->events_consumed = AllEvents; } cv->parent = parent; cv->refcnt = 1; qtalloc(cl, (struct shape *)); cl->refcnt = 1; cl->pos.x = 0; cl->pos.y = 0; cl->size.x = width; cl->size.y = height; cl->is_rect = 1; cv->lastclip = &InvalidShape; cv->outerclip = cl; if (parent) { if (cv->transparent) cv->retained = parent->retained; cv->scene = parent->scene; if (cv->prev = parent->topchild) cv->prev->next = cv; parent->topchild = cv; } else { cv->scene = 0; } cv->matrix[0][0] = fracti(1); cv->matrix[0][1] = fracti(0); cv->matrix[1][0] = fracti(0); cv->matrix[1][1] = fracti(1); cv->matrix[2][0] = fracti(0); cv->matrix[2][1] = fracti(0); return cv; } cv_alloc_retained(cv, w, h, d) register struct canvas *cv; { if (cv->retained_part.pixrect) pr_destroy(cv->retained_part.pixrect); cv->retained_part.pixrect = mem_create(w, h, d); /* Handle out of space via refusing being set retained */ if (!cv->retained_part.pixrect) { soft_malloc_failure("cv_alloc_retained"); cv_mark_retained(cv, 0); } } static cv_mark_retained(cv, value) register struct canvas *cv; { if (cv->retained == value) return; cv_invalidate_clip(cv, 0); cv_invalidate_pixrects(cv); cv->retained = value; cv->saveback = 0; for (cv = cv->topchild; cv; cv = cv->prev) if (cv->transparent) cv_mark_retained(cv, value); } cs_make_retained(cv) register struct canvas *cv; { while (cv->transparent) cv = cv->parent; if (cv->retained) return; cv_mark_retained(cv, 1); cv_alloc_retained(cv, cv->pixrect.pr_size.x, cv->pixrect.pr_size.y, cv->pixrect.pr_depth); cv_extend_damage(cv, cv->outerclip); } cs_make_nonretained(cv) register struct canvas *cv; { if (!cv->retained || cv->transparent) return; cv_mark_retained(cv, 0); } cs_make_transparent(cv) register struct canvas *cv; { if (cv==0 || cv->transparent) return 0; if (cv->parent == 0) return -1; if (cv->parent->retained && cv->mapped) pr_rop((struct pixrect *)cv, 0, 0, cv->pixrect.pr_size.x, cv->pixrect.pr_size.y, PIX_SRC, cv->parent, cv->pos.x, cv->pos.y); cv->transparent = 1; cv_invalidate_pixrects(cv); cv_invalidate_clip(cv, 1); cv_propogate_transparency(cv); return 0; } static cv_propogate_transparency(cv) register struct canvas *cv; { cv->retained = cv->parent->retained; cv->opaqparent = cv->parent->opaqparent; for (cv = cv->topchild; cv; cv = cv->prev) if (cv->transparent) cv_propogate_transparency(cv); } cs_make_opaque(cv) register struct canvas *cv; { register struct pixrect *temp = 0; if (cv == 0 || !cv->transparent) return 0; if (cv->parent == 0) return -1; if (cv->retained && cv->validpix) { temp = mem_create(cv->pixrect.pr_size.x, cv->pixrect.pr_size.y, cv->pixrect.pr_depth); pr_rop(temp, 0, 0, cv->pixrect.pr_size.x, cv->pixrect.pr_size.y, PIX_SRC, cv, 0, 0); } cv_invalidate_pixrects(cv); cv_invalidate_clip(cv, 1); cv->transparent = 0; if (temp) cv->retained_part.pixrect = temp; cv_propogate_opacity(cv); if (!cv->mapped || cv->parent->opaqparent->damage) cv_extend_damage(cv, cv->outerclip); while (cv = cv->parent) cv->hasopaque = 1; } static cv_propogate_opacity(cv) register struct canvas *cv; { if (cv->transparent) cv->opaqparent = cv->parent->opaqparent; else cv->opaqparent = cv; for (cv = cv->topchild; cv; cv = cv->prev) if (cv->transparent) cv_propogate_opacity(cv); } void cv_setcursor(gc, canvas, psfont, image_index, mask_index) struct graphics_context *gc; struct canvas *canvas; struct psfont *psfont; unsigned char image_index, mask_index; { struct psfont *psfont_tmp; char str[3]; struct cursor_shape cursor; /* Handle font reference counting */ if (psfont) psf_incref(psfont); if (canvas->cdata.psfont) psf_decref(canvas->cdata.psfont); canvas->cdata.psfont = psfont; /* Set font in gcontext for duration of cursor image setting */ psfont_tmp = gc->font; gc->font = psfont; /* Update canvas cursor */ str[CURSOR_SHAPE] = image_index; str[CURSOR_MASK] = mask_index; str[2] = 0; cs_initcursor(gc, str, 2, &cursor); /* Reset gcontext font */ gc->font = psfont_tmp; /* Change canvas' cursor */ cs_setcursor(canvas, &cursor); } panic(s) char *s; { fprintf(stderr, "PANIC: %s\n", s); fprintf(fopen("/dev/console", "w"), "PANIC: %s\n", s); abort(0); } sh_equal(sh1, sh2) register struct shape *sh1, *sh2; { if (sh1 == sh2) return 1; if (sh1 == 0 || sh2 == 0 || sh1->pos.x != sh2->pos.x || sh1->pos.y != sh2->pos.y || sh1->size.x != sh2->size.x || sh1->size.y != sh2->size.y || sh1->is_rect != sh2->is_rect) return 0; if (sh1->is_rect) return 1; #define tr1 ((struct shape_trapezon *) sh1) #define tr2 ((struct shape_trapezon *) sh2) tr1 = sh1->trapset; tr2 = sh2->trapset; while (1) { register struct shape_trapseg *sg1, *sg2; register n; if (tr1 == tr2) return 1; if (tr1 == 0 || tr2 == 0) return 0; if ((n = tr1->used) != tr2->used || tr1->top != tr2->top || tr1->bottom != tr2->bottom) return 0; sg1 = tr1->segs; sg2 = tr2->segs; while (--n >= 0) { if (sg1->y != sg2->y || sg1->x1 != sg2->x1 || sg1->x2 != sg2->x2) return 0; sg1++; sg2++; } tr1 = tr1->next; tr2 = tr2->next; } }