#ifndef lint static char sccsid[] = "@(#)flattenpath.c 9.2 88/01/19 Copyright 1985 Sun Micro"; #endif /* * Copyright (c) 1985 by Sun Microsystems, Inc. */ /*- Flatten a PostScript path [change all the curve segments to straight lines] flattenpath.c, Sun Feb 15 14:00:34 1987 James Gosling, Sun Microsystems */ #include #ifdef REF #include #include #endif #include "shape.h" #include "qalloc.h" cs_flattenpath(gc) register struct graphics_context *gc; { register struct shape_arc *next; register struct shape_arc *arcs; register struct shape_arc *p; if (gc->path.straight) return; arcs = path_to_arc(&gc->path, 0); if (arcs == 0) return 0; p = arcs; do { while (p->sh) { register fract dx, dy; dx = p->C.x - p->A.x; dy = p->C.y - p->A.y; if (abs(dx) <= abs(dy)) if (dy == 0) { p->sh = 0; break; } else dx = frmul(frdiv(dx, dy), p->B.y - p->A.y) + p->A.x - p->B.x; else dx = frmul(frdiv(dy, dx), p->B.x - p->A.x) + p->A.y - p->B.y; if (floorfr(abs(dx)) > gc->flatness) { struct shape_arc A; qtalloc(next, (struct shape_arc *)); if (p->A.y > p->C.y) { /* * halfdivide only handles arcs ordered top to bottom */ struct fpoint t; t = p->A; p->A = p->C; p->C = t; halfdivide(p, next, &A); t = next->A; next->A = next->C; next->C = t; t = A.A; A.A = A.C; A.C = t; } else halfdivide(p, &A, next); next->next = p->next; A.next = next; *p = A; } else p->sh = 0; } } while ((p = p->next) != arcs); { register i = gc->path.startpos; register lmv = -1; int first = 1; p = arcs; do { register struct path_element *pe; next = p->next; while (i + 3 >= gc->path.size) { assert(gc->path.size > 0); gc->path.element = (struct path_element *) realloc (gc->path.element, (gc->path.size = gc->path.size * 3 / 2) * sizeof gc->path.element[0]); } pe = gc->path.element + i; if (first || p->A.x != pe[-1].pos.x || p->A.y != pe[-1].pos.y) { pe->variation = MOVE_TO_FLAG; pe->pos = p->A; pe++; lmv = i; i++; } first = 0; pe->pos = p->C; pe->variation = 0; if (lmv >= 0 && p->C.x == gc->path.element[lmv].pos.x && p->C.y == gc->path.element[lmv].pos.y) { pe->variation = CLOSEPATH_FLAG; first = 1; } i++; qtfree(p); } while ((p = next) != arcs); gc->path.used = i; gc->path.straight = 1; } } static enlarge_path(gc) register struct graphics_context *gc; { gc->path.element = (struct path_element *) realloc(gc->path.element, (gc->path.size = (gc->path.size + 2) * 3 / 2) * sizeof(struct path_element)); } #define real_close(a,b) ((unsigned)(a-b+fraction(1,2)) < fracti(1)) cs_dashpath(gc) register struct graphics_context *gc; { register src, dst; register fract offset, offi; int limit; int on; struct path_element closepos, startpos; closepos.variation = 0; if (gc->texture[0] <= 0 || gc->path.startpos >= gc->path.used) return; if (!gc->path.straight) cs_flattenpath(gc); if (gc->textrevision != gc->transform.revision) { register fract scale = (frhypotenuse(gc->transform.matrix[0][0], gc->transform.matrix[0][1]) + frhypotenuse(gc->transform.matrix[1][0], gc->transform.matrix[1][1])) >> 1; /* this works in rotated and uniformly scaled coordinate systems */ for (src = 0; gc->texture[src] > 0; src++) gc->ttexture[src] = frmul(scale, gc->texture[src]); gc->ttexture[src] = 0; gc->toffset = frmul(scale, gc->offset); gc->textrevision = gc->transform.revision; } src = gc->path.startpos; dst = gc->path.used; limit = dst; offi = 0; offset = gc->toffset; on = 1; while (offset > gc->ttexture[offi]) { offset -= gc->ttexture[offi]; on = 1 - on; if (gc->ttexture[++offi] == 0) offi = 0; } gc->path.startpos = dst; while (src < limit) { struct path_element pe; pe = gc->path.element[src]; if (pe.variation == CLOSEPATH_FLAG) if (closepos.variation) { pe = closepos; pe.variation = 0; } else { src++; continue; } else if (pe.variation == MOVE_TO_FLAG || src == gc->path.startpos) { startpos = pe; closepos = pe; src++; continue; } startpos.variation = MOVE_TO_FLAG; assert(pe.variation == 0); if (real_close(startpos.pos.x, pe.pos.x)) { /* vertical */ if (startpos.pos.y <= pe.pos.y) { pe.pos.x = startpos.pos.x; while (startpos.pos.y < pe.pos.y) { register fract len = gc->ttexture[offi] - offset; if (startpos.pos.y + len > pe.pos.y) len = pe.pos.y - startpos.pos.y; if (on) { register struct path_element *dstp; if (dst + 2 >= gc->path.size) enlarge_path(gc); dstp = &gc->path.element[dst]; *dstp++ = startpos; *dstp = pe; dstp->pos.y = startpos.pos.y + len; dst += 2; } startpos.pos.y += len; if ((offset += len) >= gc->ttexture[offi]) { offset -= gc->ttexture[offi]; if (gc->ttexture[++offi] <= 0) offi = 0; on = 1 - on; } else break; } } else { pe.pos.x = startpos.pos.x; while (startpos.pos.y > pe.pos.y) { register fract len = gc->ttexture[offi] - offset; if (startpos.pos.y - len < pe.pos.y) len = startpos.pos.y - pe.pos.y; if (on) { register struct path_element *dstp; if (dst + 2 >= gc->path.size) enlarge_path(gc); dstp = &gc->path.element[dst]; *dstp++ = startpos; *dstp = pe; dstp->pos.y = startpos.pos.y - len; dst += 2; } startpos.pos.y -= len; if ((offset += len) >= gc->ttexture[offi]) { offset -= gc->ttexture[offi]; if (gc->ttexture[++offi] <= 0) offi = 0; on = 1 - on; } else break; } } } else if (real_close(startpos.pos.y, pe.pos.y)) { /* horizontal */ if (startpos.pos.x < pe.pos.x) { pe.pos.y = startpos.pos.y; while (startpos.pos.x < pe.pos.x) { register fract len = gc->ttexture[offi] - offset; if (startpos.pos.x + len > pe.pos.x) len = pe.pos.x - startpos.pos.x; if (on) { register struct path_element *dstp; if (dst + 2 >= gc->path.size) enlarge_path(gc); dstp = &gc->path.element[dst]; *dstp++ = startpos; *dstp = pe; dstp->pos.x = startpos.pos.x + len; dst += 2; } startpos.pos.x += len; if ((offset += len) >= gc->ttexture[offi]) { offset -= gc->ttexture[offi]; if (gc->ttexture[++offi] <= 0) offi = 0; on = 1 - on; } else break; } } else { pe.pos.y = startpos.pos.y; while (startpos.pos.x > pe.pos.x) { register fract len = gc->ttexture[offi] - offset; if (startpos.pos.x - len < pe.pos.x) len = startpos.pos.x - pe.pos.x; if (on) { register struct path_element *dstp; if (dst + 2 >= gc->path.size) enlarge_path(gc); dstp = &gc->path.element[dst]; *dstp++ = startpos; *dstp = pe; dstp->pos.x = startpos.pos.x - len; dst += 2; } startpos.pos.x -= len; if ((offset += len) >= gc->ttexture[offi]) { offset -= gc->ttexture[offi]; if (gc->ttexture[++offi] <= 0) offi = 0; on = 1 - on; } else break; } } } else { fract xf, yf, hypot; hypot = frhypotenuse(startpos.pos.x - pe.pos.x, startpos.pos.y - pe.pos.y); xf = frdiv(pe.pos.x - startpos.pos.x, hypot); yf = frdiv(pe.pos.y - startpos.pos.y, hypot); if (startpos.pos.x <= pe.pos.x) { while (startpos.pos.x < pe.pos.x) { register fract len = gc->ttexture[offi] - offset; register fract xl, yl; struct fpoint endc; xl = frmul(len, xf); yl = frmul(len, yf); if (startpos.pos.x + xl > pe.pos.x) { endc = pe.pos; len = frdiv(pe.pos.x - startpos.pos.x, xf); } else { endc.x = startpos.pos.x + xl; endc.y = startpos.pos.y + yl; } if (on) { register struct path_element *dstp; if (dst + 2 >= gc->path.size) enlarge_path(gc); dstp = &gc->path.element[dst]; *dstp++ = startpos; dstp->variation = 0; dstp->pos = endc; dst += 2; } startpos.pos = endc; if ((offset += len) >= gc->ttexture[offi]) { offset -= gc->ttexture[offi]; if (gc->ttexture[++offi] <= 0) offi = 0; on = 1 - on; } else break; } } else { while (startpos.pos.x > pe.pos.x) { register fract len = gc->ttexture[offi] - offset; register fract xl, yl; struct fpoint endc; xl = frmul(len, xf); yl = frmul(len, yf); if (startpos.pos.x + xl < pe.pos.x) { endc = pe.pos; len = frdiv(pe.pos.x - startpos.pos.x, xf); } else { endc.x = startpos.pos.x + xl; endc.y = startpos.pos.y + yl; } if (on) { register struct path_element *dstp; if (dst + 2 >= gc->path.size) enlarge_path(gc); dstp = &gc->path.element[dst]; *dstp++ = startpos; dstp->variation = 0; dstp->pos = endc; dst += 2; } startpos.pos = endc; if ((offset += len) >= gc->ttexture[offi]) { offset -= gc->ttexture[offi]; if (gc->ttexture[++offi] <= 0) offi = 0; on = 1 - on; } else break; } } } startpos.pos = gc->path.element[src].pos; src++; } gc->path.used = dst; } cs_setdash(gc, arr, len, offset) register struct graphics_context *gc; register fract *arr; register len; fract offset; { if (len > sizeof gc->texture / sizeof gc->texture[0] - 1) len = sizeof gc->texture / sizeof gc->texture[0] - 1; gc->textrevision = 0; gc->texture[len] = 0; gc->offset = offset; while (--len >= 0) gc->texture[len] = arr[len]; } cs_currentdash(gc, arr, len, offset) register struct graphics_context *gc; register fract **arr; int *len; fract *offset; { register i; *offset = gc->offset; *arr = gc->texture; for (i = 0; gc->texture[i] != 0; i++) ; *len = i; }