#ifndef lint static char sccsid[] = "@(#) canvas.c 9.8 88/02/23"; #endif /* * Copyright (c) 1987 by Sun Microsystems, Inc. */ /* * operations on canvas objects */ #ifdef REF #include #include #endif #include "PostScript.h" #include "input.h" static struct body *all_events_keyword, *matched_events_keyword, *no_events_keyword; static retainthreshold; /* By default, canvases which are deeper than retainthreshold will not be retained */ static setretainthreshold(ee) register struct execution_environment *ee; { if (ee->optop[-1].type != fixed_type) { ee->error_code = typecheck_error_code; return; } retainthreshold = roundfr(ee->optop[-1].value.fixed); ee->optop--; } static currentcanvas(ee) register struct execution_environment *ee; { register struct object *o = ee->optop++; register struct body *body; set_typed_object(o, canvas_type); (struct canvas *) o->value.canvas = cs_currentcanvas(&ee->gontext); if (cv_is_canvas(o->value.canvas)) { body = (struct body *) cs_currentcanvasspare((struct canvas *) o->value.canvas); set_body_of(o, body); if (body->refcnt==0) /* Welcome back from the dead... */ cv_incref(cs_currentcanvas(&ee->gontext)); incref(body); } } /* x y movecanvas - */ static movecanvas(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; struct fpoint pos; register struct canvas *cv = cs_currentcanvas(&ee->gontext); if (optop[-2].type != fixed_type || optop[-1].type != fixed_type) { ee->error_code = typecheck_error_code; return; } if (!cv_is_canvas(cv) || cv->scene == 0 || cv->parent == 0) { ee->error_code = invalidaccess_error_code; return; } cs_frdtransform(&ee->gontext, optop[-2].value.fixed, optop[-1].value.fixed, &pos.x, &pos.y); ee->optop -= 2; if (cv_is_canvas(cv)) { cs_insertcanvasabove(cv, cv, (roundfr(pos.x) + cfloorfr(cv->parent->matrix[2][0]) - cfloorfr(cv->matrix[2][0])), (roundfr(pos.y) + cfloorfr(cv->parent->matrix[2][1]) + cv->parent->pixrect.pr_height - cfloorfr(cv->matrix[2][1]) - cv->pixrect.pr_height)); /*- cs_insertcanvasabove(cv, cv, roundfr(pos.x), roundfr(pos.y) + cv->parent->pixrect.pr_height - cv->pixrect.pr_height); */ } CheckCrossings(last_event_time); } /* parent x y newcanvas newcanvas */ static newcanvas(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; register struct canvas *cv; register struct body *b; register struct canvas *parent; extern struct canvas *cv_create_canvas(); if (optop[-1].type != canvas_type) { ee->error_code = typecheck_error_code; return; } parent = (struct canvas *) optop[-1].value.canvas; if ((cv = cv_create_canvas(parent, 1, 1)) == 0 || (b = new_body(canvas)) == 0) { ee->error_code = VMerror_error_code; return; } if (!cv->transparent && cv->pixrect.pr_depth <= retainthreshold) cs_make_retained(cv); /* Fill out body fields */ b->type = canvas_type; b->body.canvas.canvas = (struct pixrect *) cv; cs_setcanvasspare(cv, b); b->body.canvas.interest = 0; object_decref(optop - 1); set_typed_bodied_object(optop - 1, canvas_type, b); optop[-1].value.canvas = b->body.canvas.canvas; } static createdevice(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; char buf[300]; register struct canvas *scp; register struct body *b; extern struct scene *CurrentInputScene; extern struct canvas *cv_create_screen_canvas(); if (optop[-1].type != string_type) { ee->error_code = typecheck_error_code; return; } if (optop[-1].value.substring.length >= sizeof buf) { ee->error_code = rangecheck_error_code; return; } sprintf(buf, "%.*s", optop[-1].value.substring.length, body_of(optop - 1)->body.string.chars + optop[-1].value.substring.start); if ((scp = cv_create_screen_canvas(buf)) == 0 || (b = new_body(canvas)) == 0) { ee->error_code = VMerror_error_code; return; } b->type = canvas_type; b->body.canvas.canvas = (struct pixrect *) scp; cs_setcanvasspare(scp, b); b->body.canvas.interest = 0; object_decref(optop - 1); set_typed_bodied_object(optop - 1, canvas_type, b); optop[-1].value.canvas = b->body.canvas.canvas; if (CurrentInputScene == 0) { CurrentInputScene = scp->scene; cs_setcursorcanvas(scp); } } static reshapecanvas(ee) register struct execution_environment *ee; { if (ee->optop[-1].type != canvas_type) { ee->error_code = typecheck_error_code; return; } cs_masksetcanvasshape(&ee->gontext, (struct canvas *) ee->optop[-1].value.canvas, ee->execee.value.def->index ? 1 : ~0); CheckCrossings(last_event_time); object_decref(ee->optop-1); ee->optop--; } /* othercanvas x y insertcanvasabove - */ static insertcanvasabove(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; struct fpoint pos; register struct canvas *cv = cs_currentcanvas(&ee->gontext); register struct canvas *ocv; if (optop[-3].type != canvas_type || optop[-2].type != fixed_type || optop[-1].type != fixed_type) { ee->error_code = typecheck_error_code; return; } cs_frdtransform(&ee->gontext, optop[-2].value.fixed, optop[-1].value.fixed, &pos.x, &pos.y); ocv = (struct canvas *) optop[-3].value.canvas; if (cv_is_canvas(cv) && ocv->scene && cv_is_canvas(ocv)) { register int x = roundfr(pos.x); register int y = roundfr(pos.y); register struct canvas *tcv = ((ocv == cv->parent) ? cv : ocv)->parent; if (tcv) y += tcv->pixrect.pr_height; if (ee->execee.value.def->index == 0) cs_insertcanvasabove(cv, ocv, x, y); else cs_insertcanvasbelow(cv, ocv, x, y); } object_decref(optop - 3); ee->optop -= 3; CheckCrossings(last_event_time); } static canvastotop(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; register struct canvas *val, *cv; register struct body *body; if (optop[-1].type != canvas_type) { ee->error_code = typecheck_error_code; return; } cv = (struct canvas *) optop[-1].value.canvas; val = cs_parent(cv); if (val == 0) { ee->error_code = invalidaccess_error_code; return; } if (ee->execee.value.def->index == 0) val = cs_topchild(val); cs_insertcanvasabove(cv, val, cv->pos.x, cv->pos.y); object_decref(optop - 1); ee->optop--; CheckCrossings(last_event_time); } static clipcanvas(ee) register struct execution_environment *ee; { switch (ee->execee.value.def->index) { case 0: cs_clipcanvas(&ee->gontext); break; case 1: cs_eoclipcanvas(&ee->gontext); break; case 2: cs_clipcanvaspath(&ee->gontext); break; } } static getcanvaslocation(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; register struct canvas *cv, *rcv; register struct spoint cpos, rpos; extern struct spoint cs_abscanvaslocation(); if (optop[-1].type != canvas_type) { ee->error_code = typecheck_error_code; return; } cv = (struct canvas *) optop[-1].value.canvas; rcv = cs_currentcanvas(&ee->gontext); rpos = cs_abscanvaslocation(rcv); cpos = cs_abscanvaslocation(cv); cpos.x -= rpos.x; cpos.y = (cpos.y - rpos.y) - cs_currentcanvas(&ee->gontext)->pixrect.pr_height + cv->pixrect.pr_height; cpos.x += roundfr(cv->matrix[2][0] - rcv->matrix[2][0]); cpos.y += roundfr(cv->matrix[2][1] - rcv->matrix[2][1]); object_decref(optop - 1); set_typed_object(optop - 1, fixed_type); set_typed_object(optop, fixed_type); cs_fridtransform(&ee->gontext, fracti(cpos.x), fracti(cpos.y), &optop[-1].value.fixed, &optop[0].value.fixed); ee->optop++; } /* base mask SETCANVASCURSOR */ static setcanvascursor(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; struct canvas *cur_canvas = cs_currentcanvas(&ee->gontext); struct body *b; void cv_setcursor(); if (!cv_is_canvas(cur_canvas)) { ee->error_code = undefined_error_code; return; } if (optop[-3].type != font_id_type || optop[-2].type != fixed_type || optop[-1].type != fixed_type) { ee->error_code = typecheck_error_code; return; } ee->optop -= 3; b = body_of(optop - 3); cv_setcursor(&ee->gontext, cur_canvas, b->body.font, (unsigned char)cfloorfr(optop[-2].value.fixed), (unsigned char)cfloorfr(optop[-1].value.fixed)); decref(b); } static getcanvascursor(ee) register struct execution_environment *ee; { register struct object *optop = ee->optop; struct canvas *cur_canvas = cs_currentcanvas(&ee->gontext); register struct body *b; fract shape_index; fract mask_index; /* Do some consistency checking */ if (!cv_is_canvas(cur_canvas) || cur_canvas->cdata.psfont == 0) { ee->error_code = undefined_error_code; return; } /* Put font on the stack */ b = new_body(font); set_typed_bodied_object(optop, font_id_type, b); b->type = font_id_type; b->body.font = cur_canvas->cdata.psfont; psf_incref(b->body.font); /* Put indices on the stack */ shape_index = fracti(cur_canvas->cdata.cursor.index[CURSOR_SHAPE]); mask_index = fracti(cur_canvas->cdata.cursor.index[CURSOR_MASK]); set_fixed_object(optop+1, shape_index); set_fixed_object(optop+2, mask_index); ee->optop += 3; } /* Now implement the magic dict operators */ #ifdef notdef static canvascursor(c, set, value) register struct body *c; int set; register struct object value; { register struct execution_environment *ee = current_process; register struct object *optop = ee->optop; struct canvas *cur_canvas = cs_currentcanvas(&ee->gontext); struct body *b; void cv_setcursor(); if (!cv_is_canvas(cur_canvas)) { ee->error_code = undefined_error_code; return; } if (set { switch (ee->execee.value.def->index) { case 0: /* CursorFont */ if (value.type != font_id_type) { cursor_error: ee->error_code = typecheck_error_code; return; } break; case 1: /* CursorImage */ if (value.type != fixed_type) goto cursor_error; break; case 2: /* CursorMask */ if (value.type != fixed_type) goto cursor_error; break; default: ee->error_code = undefined_error_code; return; } } ee->optop -= 3; b = body_of(optop - 3); cv_setcursor(&ee->gontext, cur_canvas, b->body.font, (unsigned char)cfloorfr(optop[-2].value.fixed), (unsigned char)cfloorfr(optop[-1].value.fixed)); decref(b); } } else { /* Do some consistency checking */ if (!cv_is_canvas(cur_canvas) || cur_canvas->cdata.psfont == 0) { ee->error_code = undefined_error_code; return; } /* Put font on the stack */ b = new_body(font); set_typed_bodied_object(optop, font_id_type, b); b->type = font_id_type; b->body.font = cur_canvas->cdata.psfont; psf_incref(b->body.font); /* Put indices on the stack */ shape_index = fracti(cur_canvas->cdata.cursor.index[CURSOR_SHAPE]); mask_index = fracti(cur_canvas->cdata.cursor.index[CURSOR_MASK]); set_fixed_object(optop+1, shape_index); set_fixed_object(optop+2, mask_index); ee->optop += 3; } } #endif static events_consumed(c, set, value) register struct body *c; int set; struct object value; { register struct execution_environment *ee = current_process; register struct canvas *cv; register struct body *b; assert(c != 0); if (c->type != canvas_type) { ee->error_code = unregistered_error_code; return; } cv = (struct canvas *) (c->body.canvas.canvas); switch (set) { case SET_MAGIC(0): if (value.type != keyword_type) { ee->error_code = typecheck_error_code; return; } b = body_of(&value); if (b == all_events_keyword) cv->events_consumed = AllEvents; else if (b == matched_events_keyword) cv->events_consumed = MatchedEvents; else if (b == no_events_keyword) cv->events_consumed = NoEvents; else { ee->error_code = rangecheck_error_code; return; } break; case GET_MAGIC(0): { register struct object *optop = ee->optop; switch (cv->events_consumed) { case AllEvents: b = all_events_keyword; break; case MatchedEvents: b = matched_events_keyword; break; case NoEvents: b = no_events_keyword; break; } set_typed_bodied_object(optop, keyword_type, b); ee->optop++; } break; default: ee->error_code = invalidaccess_error_code; /* Never happens */ break; } } static canvas_interests(c, set, value) register struct body *c; int set; struct object value; { struct execution_environment *ee = current_process; assert(c != 0); if (c->type != canvas_type) { ee->error_code = unregistered_error_code; return; } if (IS_SET_MAGIC(set)) { ee->error_code = invalidaccess_error_code; return; } return_interests(c->body.canvas.interest, ee); } static testcanvas(c, set, value) register struct body *c; int set; register struct object value; { register struct execution_environment *ee = current_process; register struct canvas *cv; register result = fracti(1); register struct object *optop = ee->optop; assert(c != 0); if (c->type != canvas_type) { ee->error_code = unregistered_error_code; return; } cv = (struct canvas *) (c->body.canvas.canvas); if (IS_SET_MAGIC(set) && value.type != boolean_type) { ee->error_code = typecheck_error_code; return; } switch (set) { case SET_MAGIC(0): /* Transparent */ if (value.value.fixed) { cs_make_transparent(cv); } else { cs_make_opaque(cv); } break; case GET_MAGIC(0): /* Transparent */ if (!cs_transparent(cv)) result = 0; goto bool_result; case SET_MAGIC(1): /* Mapped */ if (value.value.fixed) { if (!cv_is_canvas(cv) || cv->scene == 0 || cv->parent == 0) { ee->error_code = invalidaccess_error_code; return; } cs_map(cv, 1); } else { cs_unmap(cv, 1); } CheckCrossings(last_event_time); break; case GET_MAGIC(1): /* Mapped */ if (!cs_mapped(cv)) result = 0; goto bool_result; case SET_MAGIC(2): /* retained */ if (value.value.fixed) { cs_make_retained(cv); } else { cs_make_nonretained(cv); } break; case GET_MAGIC(2): /* retained */ if (!cs_retained(cv)) result = 0; goto bool_result; case GET_MAGIC(3): /* XLocation */ case SET_MAGIC(3): /* XLocation */ case SET_MAGIC(4): /* YLocation */ case GET_MAGIC(4): /* YLocation */ case SET_MAGIC(6): /* Color */ default: ee->error_code = invalidaccess_error_code; return; case SET_MAGIC(5): /* SaveBehind */ cs_setsaveback(cv, value.value.fixed); break; case GET_MAGIC(5): /* SaveBehind */ #ifdef notdef if (!cs_savedback(cv)) result = 0; goto bool_result; #endif case GET_MAGIC(6): /* Color */ /* XXX - this test isn't the real thing */ if (((struct pixrect *) cv)->pr_depth == 1) result = 0; bool_result: set_typed_object(optop, boolean_type); optop->value.fixed = result; ee->optop++; break; } } static relatedcanvas(c, set, value) register struct body *c; int set; register struct object value; { register struct execution_environment *ee = current_process; register struct object *optop = ee->optop; register struct canvas *val, *cv; assert(c != 0); if (c->type != canvas_type || !cv_is_canvas(cv = (struct canvas *) (c->body.canvas.canvas))) { ee->error_code = unregistered_error_code; return; } switch (set) { default: /* for now you can't set these fields */ ee->error_code = invalidaccess_error_code; break; case GET_MAGIC(0): val = cs_topcanvas(cv); goto make_result; case GET_MAGIC(1): val = cs_bottomcanvas(cv); goto make_result; case GET_MAGIC(2): val = cs_canvasabove(cv); goto make_result; case GET_MAGIC(3): val = cs_canvasbelow(cv); goto make_result; case GET_MAGIC(4): val = cs_topchild(cv); goto make_result; case SET_MAGIC(5): /* Setting Parent */ if (value.type == null_type) { cs_remove(cv, 1); } if (value.type == canvas_type) { if (cs_setparent(cv, value.value.canvas) < 0) ee->error_code = invalidaccess_error_code; } else ee->error_code = typecheck_error_code; break; case GET_MAGIC(5): val = cs_parent(cv); make_result: if (val == 0) clear_object(optop); else { register struct body *body; body = (struct body *) cs_currentcanvasspare(val); if (body->refcnt == 0) /* Welcome back from the dead... */ cv_incref(val); incref(body); set_typed_bodied_object(optop, canvas_type, body); (struct canvas *) optop->value.canvas = val; } ee->optop++; } } initialize_canvas() { retainthreshold = 1; all_events_keyword = get_name("AllEvents", -1); matched_events_keyword = get_name("MatchedEvents", -1); no_events_keyword = get_name("NoEvents", -1); define_operator("setretainthreshold", setretainthreshold, 0, 1, 0); define_operator("currentcanvas", currentcanvas, 0, 0, 1); define_operator("movecanvas", movecanvas, 0, 2, 0); define_operator("canvastotop", canvastotop, 0, 1, 0); define_operator("canvastobottom", canvastotop, 1, 1, 0); define_operator("createdevice", createdevice, 0, 1, 1); define_operator("newcanvas", newcanvas, 0, 1, 1); define_operator("reshapecanvas", reshapecanvas, 0, 1, 0); define_operator("eoreshapecanvas", reshapecanvas, 1, 1, 0); define_operator("insertcanvasabove", insertcanvasabove, 0, 3, 0); define_operator("insertcanvasbelow", insertcanvasabove, 1, 3, 0); define_operator("getcanvaslocation", getcanvaslocation, 0, 1, 2); define_operator("clipcanvas", clipcanvas, 0, 0, 0); define_operator("eoclipcanvas", clipcanvas, 1, 0, 0); define_operator("clipcanvaspath", clipcanvas, 2, 0, 0); define_operator("setcanvascursor", setcanvascursor, 0, 3, 0); define_operator("getcanvascursor", getcanvascursor, 0, 0, 3); /* Now set up the canvas magic dict */ { register struct body *cd = new_dict(30); struct object o; dict_table[(int) canvas_type] = cd; cd->refcnt = maximum_refcnt; set_typed_bodied_object(&o, dictionary_type, cd); define_object(system_dictionary, "magic:canvasdict", o); define_magic("TopCanvas", cd, relatedcanvas, 0, 0, 1); define_magic("BottomCanvas", cd, relatedcanvas, 1, 0, 1); define_magic("CanvasAbove", cd, relatedcanvas, 2, 0, 1); define_magic("CanvasBelow", cd, relatedcanvas, 3, 0, 1); define_magic("TopChild", cd, relatedcanvas, 4, 0, 1); define_magic("Parent", cd, relatedcanvas, 5, 0, 1); define_magic("Transparent", cd, testcanvas, 0, 0, 1); define_magic("Mapped", cd, testcanvas, 1, 0, 1); define_magic("Retained", cd, testcanvas, 2, 0, 1); #ifdef notdef define_magic("XLocation", cd, testcanvas, 3, 0, 1); define_magic("YLocation", cd, testcanvas, 4, 0, 1); #endif define_magic("SaveBehind", cd, testcanvas, 5, 0, 1); define_magic("Color", cd, testcanvas, 6, 0, 1); #ifdef notdef define_magic("CursorImage", cd, CursorImage, 0, 0, 1); /* XXX */ define_magic("CursorMask", cd, CursorMask, 0, 0, 1); /* XXX */ define_magic("CursorFont", cd, CursorFont, 0, 0, 1); /* XXX */ #endif define_magic("EventsConsumed", cd, events_consumed, 0, 0, 1); define_magic("Interests", cd, canvas_interests, 0, 0, 1); } }