#ifndef lint static char sccsid[] = "@(#)clip.c 9.6 88/02/10 Copyright 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- Cscript clipping primitives clip.c, Wed Nov 13 09:29:20 1985 */ #ifdef REF #include #include #endif #include "shape.h" #include "qalloc.h" #include "canvas.h" #include "cursor.h" #include sh_clip(gc, mask) register struct graphics_context *gc; { extern struct shape_trapezon *looptotrap(); register struct shape *outline, *newclip; outline = cv_pathtoshape(gc, mask); newclip = sh_intersect(gc->clip, outline); if (outline) sh_decref(outline); trim_traps(newclip); if (newclip == 0) { qtalloc(newclip, (struct shape *)); newclip->refcnt = 1; newclip->pos.x = newclip->pos.y = 0; newclip->size.x = newclip->size.y = 0; newclip->is_rect = 1; newclip->trapset = 0; } sh_decref(gc->clip); gc->clip = newclip; /*- cv_invalidate_clip((struct canvas *) gc->canvas); */ cs_newpath(gc); } sh_clipcanvas(gc, mask) register struct graphics_context *gc; { register struct shape *outline, *newclip; register struct canvas *cv = (struct canvas *) gc->canvas; register struct canvas *tcv; register dx = 0, dy = 0; for (tcv = cv; tcv && tcv != cv->opaqparent; tcv = tcv->parent) { dx += tcv->pos.x; dy += tcv->pos.y; } cv = cv->opaqparent; outline = cv_pathtoshape(gc, mask); trim_traps(outline); if (cv->globalclip) sh_decref(cv->globalclip); if (outline) cv->globalclip = sh_translate(outline, dx, dy); else cv->globalclip = 0; cv_invalidate_clip(cv, 0); cs_newpath(gc); } cs_clipcanvaspath(gc) register struct graphics_context *gc; { register struct canvas *cv = (struct canvas *) gc->canvas; cs_setpath(gc, (cv && cv_is_canvas(cv) ? (cv->globalclip ? cv->globalclip : cv->outerclip) : gc->clip)); } extern cv_save_fragment(), cv_restore_fragment(); extern struct shape *cv_apply_to_intersecting_fragments(); static struct spoint zero = {0, 0}; cs_masksetcanvasshape(gc, cv, mask) register struct graphics_context *gc; register struct canvas *cv; { extern struct shape *cv_compute_visible_part(); extern struct shape_trapezon *looptotrap(); extern sh_only_apply_below; /* magic global parameter to cv_apply_to_intersecting_fragments */ register struct shape *outline; register struct pixrect *newret = 0; struct shape *restore_shape = 0; struct shape *old_visible; struct spoint cvpos, gccpos; struct spoint npos; cs_checkcursordims(cv,0,0,cv->pixrect.pr_width,cv->pixrect.pr_height); if (cv->hasopaque) { register struct canvas *p; for (p = cv->topchild; p; p = p->prev) cv_unmap(p, 1); } cvpos = cs_abscanvaslocation(cv); gccpos = cs_abscanvaslocation(gc->canvas); outline = cv_pathtoshape(gc, mask); old_visible = cv_compute_visible_part(cv, 1); trim_traps(outline); if (outline == 0) { /* Reshaping to empty path */ qtalloc(outline, (struct shape *)); outline->refcnt = 1; outline->pos.x = outline->pos.y = 0; outline->size.x = outline->size.y = 0; outline->is_rect = 1; outline->trapset = 0; } cs_checkcursordims(gc->canvas,outline->pos.x, outline->pos.y, outline->size.x, outline->size.y); #ifndef PREVIEW /* * Figure out the new per-canvas transformation matrix based on the * current process transformation matrix */ cv->invgeneration = 0; cv->opaqparent->invgeneration = 0; /* * If there is no parent then don't adjust offset because have nothing to * be relative to. */ if (!cv->parent) goto Damage_Propagate; cs_currentmatrix(gc, cv->matrix); cv->matrix[2][0] -= fracti(outline->pos.x); cv->matrix[2][1] -= fracti(gc->canvas->pr_height - outline->size.y - outline->pos.y); #endif /* npos is where the canvas is moving to */ npos.x = outline->pos.x + gccpos.x - cvpos.x + cv->pos.x; npos.y = outline->pos.y + gccpos.y - cvpos.y + cv->pos.y; /* pixrect -ve origin bug write-around */ if (npos.x < 0) npos.x = 0; if (npos.y < 0) npos.y = 0; if (cv->retained && !cv->transparent) { register struct shape *save = old_visible; if (save) sh_incref(save); save = cv_apply_to_intersecting_fragments(save, cv, 0, cv_save_fragment); if (save) sh_decref(save); if (npos.x != 0 || npos.y != 0 || outline->size.x != cv->pixrect.pr_size.x || outline->size.y != cv->pixrect.pr_size.y) { /* * create a new retained pixrect for the canvas and save it's old * bits there */ newret = mem_create(outline->size.x, outline->size.y, cv->pixrect.pr_depth); if (newret) pr_rop(newret, 0, 0, outline->size.x, outline->size.y, PIX_SRC, cv->retained_part.pixrect, 0, 0); else newret = (struct pixrect *)-1; } } if (cv->mapped && !cv->transparent) { /* * save the pieces that need saving, and figure out what needs to be * restored */ register struct shape *sh, *tro, *tempsh, *parentsh; outline = sh_translate(outline, npos.x - outline->pos.x, npos.y - outline->pos.y); tro = old_visible; if (tro) sh_incref(tro); parentsh = cv_compute_visible_part(cv->parent, 0); tro = sh_translate(tro, cv->pos.x, cv->pos.y); tempsh = sh_difference(outline, tro); sh = sh_intersect(tempsh, parentsh); if (parentsh) sh_decref(parentsh); if (tempsh) sh_decref(tempsh); { register struct canvas *p; p = cv; while (p != cv->parent->topchild && sh) { p = p->next; if (p->mapped && !p->transparent) { register struct shape *temp1, *temp2; temp1 = p->outerclip; sh_incref(temp1); temp1 = sh_translate(temp1, p->pos.x, p->pos.y); temp2 = sh_difference (sh, temp1); sh_decref(temp1); sh_decref (sh); sh = temp2; } } } if (sh) { /* Save the pieces that get covered */ sh_only_apply_below = 1; cv_apply_to_intersecting_fragments_of_parent( zero, sh, cv->parent, cv, cv_save_fragment); sh_decref(sh); } restore_shape = sh_difference(tro, outline); if (tro) sh_decref(tro); } outline = sh_translate(outline, -outline->pos.x, -outline->pos.y); cv->pos.x = npos.x; cv->pos.y = npos.y; cv->pixrect.pr_size.x = outline->size.x; cv->pixrect.pr_size.y = outline->size.y; Damage_Propagate: sh_decref(cv->outerclip); cv->outerclip = outline; cv_invalidate_pixrects(cv); if (newret) { if (newret == (struct pixrect *)-1) /* Handle out of space via making unretained */ cs_make_nonretained(cv); else { /* restore retained bits to the screen */ if (cv->retained_part.pixrect) pr_destroy(cv->retained_part.pixrect); cv->retained_part.pixrect = newret; } } if (restore_shape) { /* And restore the pieces that are uncovered */ sh_only_apply_below = 1; cv_apply_to_intersecting_fragments_of_parent( zero, restore_shape, cv->parent, cv, cv_restore_fragment); sh_decref(restore_shape); } sh_only_apply_below = 0; if ((struct canvas *) gc->canvas == cv) { sh_decref(gc->clip); gc->clip = outline; sh_incref(outline); cs_initmatrix(gc); } cv_invalidate_clip(cv, 1); /* Propagate damage to all children */ if (!cv->transparent) { extern cv_extend_damage(); register struct shape *damaged = cv->outerclip; sh_incref(damaged); damaged = cv_apply_to_intersecting_fragments(damaged, cv, 0, cv_extend_damage); if (damaged) sh_decref(damaged); } /*- cv_extend_damage(cv, cv->outerclip); */ cs_newpath(gc); if (cv->hasopaque) { register struct canvas *p; for (p = cv->topchild; p; p = p->prev) cv_map(p, 1); } if (old_visible) sh_decref(old_visible); } cs_clippath(gc) register struct graphics_context *gc; { register struct canvas *cv = (struct canvas *) gc->canvas; register struct shape *sh; cs_newpath(gc); if (!cv_is_canvas(cv)) { qtalloc(sh, (struct shape *)); sh->pos.x = 0; sh->pos.y = 0; sh->size.x = cv->pixrect.pr_width; sh->size.y = cv->pixrect.pr_height; sh->is_rect = 1; sh->refcnt = 0; sh->trapset = 0; } else sh = gc->clip; sh_incref(sh); gc->shape = sh; } cs_pathbbox(gc, fminx, fminy, fmaxx, fmaxy) register struct graphics_context *gc; fract *fminx, *fminy, *fmaxx, *fmaxy; { struct fcorner_bbox dbb, /* device coord bbox */ ubb; /* user coord bbox */ struct fpoint lmin, lmax, rmin, rmax; register struct shape *sh; if (sh = gc->shape) { if (gc->shape && gc->path.used == gc->path.startpos) dbb.ll.x = fracti(sh->pos.x); dbb.ur.x = fracti(sh->pos.x + sh->size.x); dbb.ll.y = fracti(sh->pos.y); dbb.ur.y = fracti(sh->pos.y + sh->size.y); } else { register struct path_element *p, *limit; p = &gc->path.element[gc->path.startpos]; limit = &gc->path.element[gc->path.used - 1]; if (gc->path.size == 0 || p >= limit) { *fminx = 0; *fminy = 0; *fmaxx = 0; *fmaxy = 0; return; } dbb.ll.x = dbb.ur.x = p->pos.x; dbb.ll.y = dbb.ur.y = p->pos.y; do { p++; if (p->variation != CLOSEPATH_FLAG) { if (dbb.ll.x > p->pos.x) dbb.ll.x = p->pos.x; if (dbb.ur.x < p->pos.x) dbb.ur.x = p->pos.x; if (dbb.ll.y > p->pos.y) dbb.ll.y = p->pos.y; if (dbb.ur.y < p->pos.y) dbb.ur.y = p->pos.y; } } while (p < limit); } cs_bbitransform(gc, &dbb, &ubb); *fminx = ubb.ll.x; *fminy = ubb.ll.y; *fmaxx = ubb.ur.x; *fmaxy = ubb.ur.y; return; } cs_initclip(gc) register struct graphics_context *gc; { register struct canvas *cv; if ((cv = (struct canvas *) gc->canvas) != 0 && cv_is_canvas(cv) && gc->clip != cv->outerclip) { if (gc->clip->refcnt != STATIC_OBJ) sh_decref(gc->clip); gc->clip = cv->outerclip; sh_incref(gc->clip); /*- cv_invalidate_clip(cv); */ } }