|
|
1.1 ! root 1: /*********************************************************** ! 2: Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts, ! 3: and the Massachusetts Institute of Technology, Cambridge, Massachusetts. ! 4: ! 5: All Rights Reserved ! 6: ! 7: Permission to use, copy, modify, and distribute this software and its ! 8: documentation for any purpose and without fee is hereby granted, ! 9: provided that the above copyright notice appear in all copies and that ! 10: both that copyright notice and this permission notice appear in ! 11: supporting documentation, and that the names of Digital or MIT not be ! 12: used in advertising or publicity pertaining to distribution of the ! 13: software without specific, written prior permission. ! 14: ! 15: DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ! 16: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL ! 17: DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ! 18: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, ! 19: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ! 20: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS ! 21: SOFTWARE. ! 22: ! 23: ******************************************************************/ ! 24: /* $Header: miwidedash.c,v 1.13 87/08/31 17:01:06 toddb Exp $ */ ! 25: /* Author: Todd "Mr. Wide Line" Newman */ ! 26: ! 27: #include "X.h" ! 28: #include "Xprotostr.h" ! 29: #include "miscstruct.h" ! 30: #include "mistruct.h" ! 31: #include "scrnintstr.h" ! 32: #include "windowstr.h" ! 33: #include "gcstruct.h" ! 34: #include "pixmapstr.h" ! 35: #include "mifpoly.h" ! 36: ! 37: #define GCVALSALU 0 ! 38: #define GCVALSFORE 1 ! 39: #define GCVALSBACK 2 ! 40: #define GCVALSWIDTH 3 ! 41: #define GCVALSCAPSTYLE 4 ! 42: #define GCVALSARCMODE 5 ! 43: static int gcvals[] = {GXcopy, 1, 0, 0, 0, ArcChord}; ! 44: ! 45: /* Neither Fish nor Fowl, it's a Wide Dashed Line. */ ! 46: /* Actually, wide, dashed lines Are pretty foul. (You knew that was coming, ! 47: * didn't you.) */ ! 48: ! 49: /* MIWIDEDASH -- Public entry for PolyLine Requests when the GC speicifies ! 50: * that we must be dashing (All Hail Errol Flynn) ! 51: * ! 52: * We must use the raster op to decide how whether we will draw directly into ! 53: * the Drawable or squeegee bits through a scratch pixmap to avoid the dash ! 54: * interfering with itself. ! 55: * ! 56: * miDashLine will convert the poly line we were called with into the ! 57: * appropriate set of line segments. ! 58: * Based on the dash style we then draw the segments. For OnOff dashes we ! 59: * draw every other segment and cap each segment. For DoubleDashes, we ! 60: * draw every other segment starting with the first in the foreground color, ! 61: * then draw every other segment starting with the second in the background ! 62: * color. Then we cap the first and last segments "by hand." ! 63: */ ! 64: void ! 65: miWideDash(pDraw, pGC, mode, npt, pPtsIn) ! 66: DrawablePtr pDraw; ! 67: GCPtr pGC; ! 68: int mode; ! 69: int npt; ! 70: DDXPointPtr pPtsIn; ! 71: { ! 72: ! 73: SppPointPtr pPts, ppt; ! 74: int nseg, which, whichPrev, i, j, xOrg, yOrg, width, ! 75: fTricky, arcmode, xMin, xMax, yMin, yMax, ! 76: dxi, dyi, gcflags; ! 77: unsigned long oldfore, newfore; ! 78: miDashPtr dashes; ! 79: double dy, dx, m; ! 80: Bool IsDoubleDash = (pGC->lineStyle == LineDoubleDash), ! 81: fXmajor; ! 82: SppPointRec pt, PointStash[4], PolyPoints[4]; ! 83: DDXPointPtr pPtIn; ! 84: DrawablePtr pDrawTo; ! 85: GCPtr pGCTo; ! 86: ! 87: ! 88: m = EPSILON; ! 89: if (mode == CoordModePrevious) ! 90: { ! 91: DDXPointPtr pptT; ! 92: int nptTmp; ! 93: ! 94: pptT = pPtsIn + 1; ! 95: nptTmp = npt - 1; ! 96: while (nptTmp--) ! 97: { ! 98: pptT->x += (pptT-1)->x; ! 99: pptT->y += (pptT-1)->y; ! 100: pptT++; ! 101: } ! 102: } ! 103: ! 104: width = pGC->lineWidth; ! 105: switch(pGC->alu) ! 106: { ! 107: case GXclear: /* 0 */ ! 108: case GXcopy: /* src */ ! 109: case GXcopyInverted: /* NOT src */ ! 110: case GXset: /* 1 */ ! 111: fTricky = FALSE; ! 112: xOrg = yOrg = 0; ! 113: pDrawTo = pDraw; ! 114: pGCTo = pGC; ! 115: if(pGCTo->arcMode != ArcChord) ! 116: { ! 117: arcmode = pGCTo->arcMode; ! 118: DoChangeGC(pGCTo, GCArcMode, &gcvals[GCVALSARCMODE], 0); ! 119: ValidateGC(pDrawTo, pGCTo); ! 120: } ! 121: else ! 122: arcmode = ArcChord; ! 123: ! 124: break; ! 125: case GXand: /* src AND dst */ ! 126: case GXandReverse: /* src AND NOT dst */ ! 127: case GXandInverted: /* NOT src AND dst */ ! 128: case GXnoop: /* dst */ ! 129: case GXxor: /* src XOR dst */ ! 130: case GXor : /* src OR dst */ ! 131: case GXnor: /* NOT src AND NOT dst */ ! 132: case GXequiv: /* NOT src XOR dst */ ! 133: case GXinvert: /* NOT dst */ ! 134: case GXorReverse: /* src OR NOT dst */ ! 135: case GXorInverted: /* NOT src OR dst */ ! 136: case GXnand: /* NOT src OR NOT dst */ ! 137: fTricky = TRUE; ! 138: yMin = yMax = pPtsIn[0].y; ! 139: xMin = xMax = pPtsIn[0].x; ! 140: ! 141: for (i = 1; i < npt; i++) ! 142: { ! 143: xMin = min(xMin, pPtsIn[i].x); ! 144: xMax = max(xMax, pPtsIn[i].x); ! 145: yMin = min(yMin, pPtsIn[i].y); ! 146: yMax = max(yMax, pPtsIn[i].y); ! 147: } ! 148: xOrg = xMin - (width + 1)/2; ! 149: yOrg = yMin - (width + 1)/2; ! 150: dxi = xMax - xMin + width; ! 151: dyi = yMax - yMin + width; ! 152: pDrawTo = (DrawablePtr) (*pDraw->pScreen->CreatePixmap) ! 153: (pDraw->pScreen, dxi, dyi, 1, XYBitmap); ! 154: pGCTo = GetScratchGC(1, pDraw->pScreen); ! 155: gcvals[GCVALSWIDTH] = width; ! 156: gcvals[GCVALSCAPSTYLE] = pGC->capStyle; ! 157: gcflags = GCFunction | GCForeground | GCBackground | GCLineWidth | ! 158: GCCapStyle; ! 159: if(pGCTo->arcMode != ArcChord) ! 160: gcflags |= GCArcMode; ! 161: DoChangeGC(pGCTo, gcflags, gcvals, 0); ! 162: ValidateGC(pDrawTo, pGCTo); ! 163: miClearDrawable(pDrawTo, pGCTo); ! 164: ! 165: } ! 166: ! 167: dashes = miDashLine(npt, pPtsIn, ! 168: pGC->numInDashList, pGC->dash, pGC->dashOffset, &nseg); ! 169: if(!(pPts = (SppPointPtr) Xalloc((nseg + 1) * sizeof(SppPointRec)))) ! 170: { ! 171: Xfree(dashes); ! 172: if(fTricky) ! 173: (*pDraw->pScreen->DestroyPixmap)(pDrawTo); ! 174: return; ! 175: } ! 176: ppt = pPts; ! 177: pPtIn = pPtsIn; ! 178: whichPrev = EVEN_DASH; ! 179: ! 180: j = 0; ! 181: for(i = 0; i < nseg + 1; i++) ! 182: { ! 183: if(dashes[i].newLine) ! 184: { ! 185: /* calculate slope of the line */ ! 186: dx = (double) ((pPtsIn + 1)->x - pPtIn->x); ! 187: dy = (double) ((pPtsIn + 1)->y - pPtIn->y); ! 188: pPtIn++; ! 189: /* use slope of line to figure out how to use error term */ ! 190: fXmajor = (fabs(dx) > fabs(dy)); ! 191: if(fXmajor) ! 192: m = !ISZERO(dx) ? (dy/dx) : EPSILON; ! 193: else ! 194: m = !ISZERO(dy) ? (dx/dy) : EPSILON; ! 195: } ! 196: /* Add this point to our list, adjusting the error term as needed */ ! 197: ppt->x = (double) dashes[i].pt.x; ! 198: ppt->y = (double) dashes[i].pt.y; ! 199: ! 200: if(i < 2 || i > nseg - 2) ! 201: { ! 202: PointStash[j++] = *ppt; ! 203: } ! 204: ppt++; ! 205: which = dashes[i].which; ! 206: if(which != whichPrev) ! 207: { ! 208: if(which == ODD_DASH) ! 209: { ! 210: /* Display the collect line */ ! 211: (*pGC->LineHelper)(pDrawTo, pGCTo, !IsDoubleDash, ! 212: ppt - pPts, pPts, xOrg, yOrg); ! 213: } ! 214: /* Reset the line and start a new dash */ ! 215: pPts[0] = ppt[-1]; ! 216: ppt = &pPts[1]; ! 217: whichPrev = which; ! 218: } ! 219: ! 220: } ! 221: if(IsDoubleDash) ! 222: { ! 223: ppt = pPts; ! 224: pPtIn = pPtsIn; ! 225: whichPrev = EVEN_DASH; ! 226: ! 227: /* cap the first (and maybe the last) line segment(s) appropriately */ ! 228: if(pGC->capStyle == CapProjecting) ! 229: { ! 230: pt = miExtendSegment(PointStash[0], PointStash[1], width/2); ! 231: miGetPts(pt, PointStash[0], ! 232: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], &PolyPoints[3], ! 233: width); ! 234: miFillSppPoly(pDrawTo, pGCTo, 4, PolyPoints, xOrg, yOrg); ! 235: if(dashes[nseg].which == EVEN_DASH) ! 236: { ! 237: pt = miExtendSegment(PointStash[3], PointStash[2], width/2); ! 238: miGetPts(pt, PointStash[3], ! 239: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], ! 240: &PolyPoints[3], width); ! 241: miFillSppPoly(pDrawTo, pGCTo, 4, PolyPoints, xOrg, yOrg); ! 242: } ! 243: ! 244: } ! 245: else if (pGC->capStyle == CapRound) ! 246: { ! 247: miGetPts(PointStash[0], PointStash[1], ! 248: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], &PolyPoints[3], ! 249: width); ! 250: miRoundCap(pDrawTo, pGCTo, PointStash[0], PointStash[1], ! 251: PolyPoints[0], PolyPoints[3], FirstEnd, xOrg, yOrg); ! 252: if(dashes[nseg].which == EVEN_DASH) ! 253: { ! 254: miGetPts(PointStash[3], PointStash[2], ! 255: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], ! 256: &PolyPoints[3], width); ! 257: miRoundCap(pDrawTo, pGCTo, PointStash[3], PointStash[2], ! 258: PolyPoints[3], PolyPoints[0], SecondEnd, xOrg, yOrg); ! 259: } ! 260: } ! 261: oldfore = pGC->fgPixel; ! 262: newfore = pGC->bgPixel; ! 263: DoChangeGC(pGCTo, GCForeground, &newfore, 0); ! 264: ValidateGC(pDrawTo, pGCTo); ! 265: ! 266: for(i = 0; i < nseg + 1; i++) ! 267: { ! 268: if(dashes[i].newLine) ! 269: { ! 270: /* calculate slope of the line */ ! 271: dx = (double) ((pPtIn + 1)->x - pPtIn->x); ! 272: dy = (double) ((pPtIn + 1)->y - pPtIn->y); ! 273: /* use slope of line to figure out how to use error term */ ! 274: fXmajor = (fabs(dx) > fabs(dy)); ! 275: if(fXmajor) ! 276: m = ISZERO(dx) ? (dy/dx) : EPSILON; ! 277: else ! 278: m = ISZERO(dy) ? (dx/dy) : EPSILON; ! 279: pPtIn++; ! 280: } ! 281: /* Add this point to our list */ ! 282: ppt->x = (double) dashes[i].pt.x + ! 283: (fXmajor ? 0.0 : dashes[i].e*m); ! 284: ppt->y = (double) dashes[i].pt.y + ! 285: (fXmajor ? dashes[i].e*m : 0.0); ! 286: ppt++; ! 287: which = dashes[i].which; ! 288: if(which != whichPrev) ! 289: { ! 290: if(which == EVEN_DASH) ! 291: { ! 292: /* Display the collected line */ ! 293: (*pGC->LineHelper)(pDrawTo, pGCTo, FALSE, ! 294: ppt - pPts, pPts, xOrg, yOrg); ! 295: } ! 296: /* Reset the line and start a new dash */ ! 297: pPts[0] = ppt[-1]; ! 298: ppt = &pPts[1]; ! 299: whichPrev = which; ! 300: } ! 301: ! 302: } ! 303: ! 304: /* cap the last line segments appropriately */ ! 305: if(dashes[nseg].which == ODD_DASH) ! 306: { ! 307: if(pGC->capStyle == CapProjecting) ! 308: { ! 309: pt = miExtendSegment(PointStash[3], PointStash[2], width/2); ! 310: miGetPts(pt, PointStash[3], ! 311: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], ! 312: &PolyPoints[3], width); ! 313: miFillSppPoly(pDrawTo, pGCTo, 4, PolyPoints, xOrg, yOrg); ! 314: ! 315: } ! 316: else if (pGC->capStyle == CapRound) ! 317: { ! 318: miGetPts(PointStash[3], PointStash[2], ! 319: &PolyPoints[0], &PolyPoints[1], &PolyPoints[2], ! 320: &PolyPoints[3], width); ! 321: miRoundCap(pDrawTo, pGCTo, PointStash[3], PointStash[2], ! 322: PolyPoints[3], PolyPoints[0], SecondEnd, xOrg, yOrg); ! 323: } ! 324: } ! 325: DoChangeGC(pGCTo, GCForeground, &oldfore, 0); ! 326: } ! 327: if(arcmode != ArcChord) ! 328: { ! 329: DoChangeGC(pGCTo, GCArcMode, &gcvals[GCVALSARCMODE], 0); ! 330: } ! 331: ValidateGC(pDrawTo, pGCTo); ! 332: if(fTricky) ! 333: { ! 334: if (pGC->miTranslate && (pDraw->type == DRAWABLE_WINDOW) ) ! 335: { ! 336: xOrg += ((WindowPtr)pDraw)->absCorner.x; ! 337: yOrg += ((WindowPtr)pDraw)->absCorner.y; ! 338: } ! 339: ! 340: (*pGC->PushPixels)(pGC, pDrawTo, pDraw, dxi, dyi, xOrg, yOrg); ! 341: (*pDraw->pScreen->DestroyPixmap)(pDrawTo); ! 342: FreeScratchGC(pGCTo); ! 343: } ! 344: Xfree(dashes); ! 345: Xfree(pPts); ! 346: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.