#ifndef lint static char sccsid[] = "@(#)overlay.c 9.3 88/01/19 Copyright 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- Screen overlays. For the moment, only one overlay is up at a time. overlay.c, Tue Jul 22 12:59:07 1986 */ #include #ifdef REF #include #include #endif #include "shape.h" #include "canvas.h" #include "qalloc.h" #include "font.h" #include "cursor.h" #include "cscript.h" #include #include int ovl_state; /* -1=>overlay exists, but down; 0=>no overlay 1=>overlay exists and is up */ static ovl_rop(); static ovl_stencil(); static ovl_batchrop(); static ovl_nop(); int ovl_destroy(); static ovl_get(); static ovl_put(); static ovl_vector(); static struct pixrect *ovl_region(); static ovl_putcolormap(); static ovl_getcolormap(); static ovl_putattributes(); static ovl_getattributes(); static ovl_shapetext(); static ovl_shaperop(); static ovl_shapecurve(); static ovl_shapevector(); static ovl_replrop(); #define is_rop 0 #define is_vector 1 #define is_shapetext 2 #define is_shaperop 3 #define is_shapecurve 4 #define is_shapevector 5 #define is_replrop 6 struct overlay_record { struct overlay_record *next; char kind; union { struct { struct spoint p1, p2; } vector; struct { struct spoint pos, size; } rop; struct { struct rendering_info *ri; struct font *font; short len; } text; struct shape_dcurve *curve; struct shape *shape; } u; }; /* * NOTE: This macro assumes that p is a pointer to struct overlay_record * because currently every invocation of EXTEND works that way. If * this ever changes, the struct type must be passed as an extra * argument to EXTEND so that it can be passed on to qtalloc(). */ #define EXTEND(pr, p, fkind) \ qtalloc(p, (struct overlay_record *)); \ (p)->kind = fkind; \ ovl_state = -1; \ ovl_root = pr; \ (p)->next = (struct overlay_record *) pr->pixrect.pr_data; \ pr->pixrect.pr_data = (char *) (p); static struct canvas *ovl_root; static struct pixrect * ovl_prnop() { return 0; } struct pixrectops ovl_ops = {ovl_rop, ovl_nop, ovl_nop, ovl_nop, ovl_destroy, ovl_nop, ovl_nop, ovl_vector, ovl_prnop, ovl_nop, ovl_nop, ovl_nop, ovl_nop, ovl_shapetext, ovl_shaperop, ovl_shapecurve, ovl_shapevector, ovl_replrop, }; static ovl_nop() { return 0; } static ovl_vector(pr, x1, y1, x2, y2, op, color) register struct canvas *pr; { register struct overlay_record *p; cs_cursordown(); /* Will pull down the overlay too */ EXTEND(pr, p, is_vector); p->u.vector.p1.x = x1; p->u.vector.p1.y = y1; p->u.vector.p2.x = x2; p->u.vector.p2.y = y2; return 0; } static ovl_rop(dpr, dx, dy, w, h, op, spr, sx, sy) register struct canvas *dpr; struct canvas *spr; { register struct overlay_record *p; if (spr != 0) return 0; cs_cursordown(); /* Will pull down the overlay too */ if (op == 0 && w > 2000) { /* Hack! */ ovl_freeoverlay(dpr); ovl_state = 0; return 0; } EXTEND(dpr, p, is_rop); p->u.rop.pos.x = dx; p->u.rop.pos.y = dy; p->u.rop.size.x = w; p->u.rop.size.y = h; return 0; } static ovl_shapetext(pr, op, font, shape, ri, n) struct canvas *pr; short op; struct font *font; struct shape *shape; register struct rendering_info *ri; register short n; { register struct overlay_record *p; register size = n * sizeof(struct rendering_info); cs_cursordown(); /* Will pull down the overlay too */ EXTEND(pr, p, is_shapetext); p->u.text.font = font; p->u.text.len = n; QALLOC(p->u.text.ri, size, (struct rendering_info *)); bcopy(ri, p->u.text.ri, size); return 0; } static ovl_shaperop(dpr, shape, OP, spr, sx, sy) struct canvas *dpr, *spr; register struct shape *shape; { register struct overlay_record *p; cs_cursordown(); /* Will pull down the overlay too */ EXTEND(dpr, p, is_shaperop); sh_incref(shape); p->u.shape = shape; return 0; } static ovl_shapevector() { return 0; } static ovl_replrop() { return 0; } static ovl_shapecurve(dpr, shape, dcurve, op, texture, phase) register struct canvas *dpr; struct shape *shape; register struct shape_dcurve *dcurve; short *texture; { register struct overlay_record *p; cs_cursordown(); /* Will pull down the overlay too */ EXTEND(dpr, p, is_shapecurve); p->u.curve = dcurve; dcurve->refcnt++; } struct canvas * ovl_create(parent) register struct canvas *parent; { register struct canvas *cv; if (parent == 0 || parent->overlay) return 0; qtalloc(cv, (struct canvas *)); if (cv == 0) return 0; bzero(cv, sizeof *cv); cv->pixrect.pr_ops = &ovl_ops; cv->pixrect.pr_depth = 1; cv->pixrect.pr_canvas = 1; cv->pixrect.pr_size = parent->pixrect.pr_size; cv->parent = parent; cv->outerclip = parent->outerclip; cv->scr_pos = parent->scr_pos; sh_incref(cv->outerclip); cv_incref(parent); cv->refcnt = 1; cv->overlay = 1; cv->opaqparent = cv; return cv; } ovl_destroy(cv) register struct canvas *cv; { if (cv_canvasdestructionhook) (*cv_canvasdestructionhook) (cv); if (cv->refcnt > 0) return; if (ovl_root == cv) { cs_cursordown(); /* Will pull down the overlay too */ ovl_root = 0; ovl_state = 0; } ovl_freeoverlay(cv); if (cv->mapped) cv_unmap(cv, 0); cv->signature = 0; assert(cv->parent); cs_remove(cv, 0); if (cv->outerclip) sh_decref(cv->outerclip); if (cv->globalclip) sh_decref(cv->globalclip); if (cv->lastclip && cv->lastclip != &InvalidShape) sh_decref(cv->lastclip); if (cv->screen_part.pixrect) pr_destroy(cv->screen_part.pixrect); if (cv->screen_part.clip) sh_decref(cv->screen_part.clip); if (cv->retained_part.pixrect) pr_destroy(cv->retained_part.pixrect); if (cv->retained_part.clip) sh_decref(cv->retained_part.clip); if (cv->cdata.psfont) psf_decref(cv->cdata.psfont); qtfree(cv); } static ovl_freeoverlay(cv) register struct canvas *cv; { register struct overlay_record *p; p = (struct overlay_record *) cv->pixrect.pr_data; while (p) { register struct overlay_record *n; switch (p->kind) { case is_shapecurve: if (--p->u.curve->refcnt <= 0) shape_freecurve(p->u.curve); break; case is_shapetext: QFREE(p->u.text.ri); break; case is_shaperop: sh_decref(p->u.shape); break; } n = p->next; qtfree(p); p = n; } cv->pixrect.pr_data = 0; } ovl_overlaydown() { if (ovl_root == 0) { ovl_state = 0; return; } if (ovl_state <= 0) return; ovl_draw(ovl_root, 0); ovl_state = -1; } ovl_overlayup() { if (ovl_root == 0) { ovl_state = 0; return; } if (ovl_state >= 0) return; ovl_draw(ovl_root, 1); ovl_state = 1; } static ovl_draw(cv, up) register struct canvas *cv; { register struct overlay_record *p; register struct pixrect *fb; struct canvas cv_parent_cache; int is_cached = 0; #define cvfb ((struct canvas *) fb) p = (struct overlay_record *) cv->pixrect.pr_data; cvfb = cv->parent; if (!cvfb->mapped) { ovl_root = 0; ovl_state = 0; return; } if (cvfb->parent == 0) { register struct shape *shape = cvfb->outerclip; /* root canvas case */ if (shape->is_rect && shape->size.x == cvfb->pixrect.pr_size.x && shape->size.y == cvfb->pixrect.pr_size.y && shape->pos.x == cvfb->pos.x && shape->pos.y == cvfb->pos.y) { /* Rectangular root canvas that covers the entire screen (fast) */ fb = cvfb->screen_part.pixrect; } else { /* "Funny" shaped root canvas (slow) */ /* Remember root canvas state by copying canvas & adjusting refs */ cv_parent_cache = *cvfb; sh_incref(cv_parent_cache.outerclip); if (cv_parent_cache.lastclip != &InvalidShape) sh_incref(cv_parent_cache.lastclip); if (cv_parent_cache.screen_part.clip) sh_incref(cv_parent_cache.screen_part.clip); if (cv_parent_cache.retained_part.clip) sh_incref(cv_parent_cache.retained_part.clip); /* Fool root into thinking that it doesn't have any children */ cvfb->topchild = cvfb->next = cvfb->prev = (struct canvas *)0; /* Don't let any additional clipping (damage), change clipping */ cvfb->globalclip = (struct shape *)0; /* Figure clipping while in new "fooled" state */ cv_invalidate_clip(cvfb, 1); cv_validate_clip(cvfb, cvfb->outerclip); cv->pixrect.pr_size = cvfb->pixrect.pr_size; is_cached = 1; } } else if (cvfb->lastclip != cvfb->outerclip) { /* Non-root canvas case */ cv_validate_clip(cvfb, cvfb->outerclip); cv->pixrect.pr_size = cvfb->pixrect.pr_size; } while (p) { switch (p->kind) { case is_vector: pr_vector(fb, p->u.vector.p1.x, p->u.vector.p1.y, p->u.vector.p2.x, p->u.vector.p2.y, PIX_NOT(PIX_DST), 0); break; case is_rop: pr_rop(fb, p->u.rop.pos.x, p->u.rop.pos.y, p->u.rop.size.x, p->u.rop.size.y, PIX_NOT(PIX_DST), 0, 0, 0); break; case is_shapecurve: pr_shapecurve(fb, &InfiniteShape, p->u.curve, PIX_NOT(PIX_DST), 0, 0); break; case is_shapetext: pr_shapetext(fb, PIX_NOT(PIX_DST), p->u.text.font, &InfiniteShape, p->u.text.ri, p->u.text.len); break; case is_shaperop: pr_shaperop(fb, p->u.shape, PIX_NOT(PIX_DST), 0, 0, 0); break; default: break; } p = p->next; } if (is_cached) { /* Restore root canvas to original state */ sh_decref(cvfb->outerclip); if (cvfb->lastclip != &InvalidShape) sh_decref(cvfb->lastclip); if (cvfb->screen_part.clip) sh_decref(cvfb->screen_part.clip); if (cvfb->retained_part.clip) sh_decref(cvfb->retained_part.clip); *cvfb = cv_parent_cache; } }