|
|
1.1 root 1: /******************************Module*Header*******************************\
2: * Module Name: Stroke.c
3: *
4: * DrvStrokePath for VGA driver
5: *
6: * Copyright (c) 1992 Microsoft Corporation
7: \**************************************************************************/
8:
9: #include "driver.h"
10:
11: #include "lines.h"
12:
13: // External calls
14:
15: VOID vSetStrips(ULONG, ULONG);
16: VOID vClearStrips(ULONG);
17:
18: #define MIN(A,B) ((A) < (B) ? (A) : (B))
19:
20: // Prototypes to go to the screen:
21:
22: VOID vStripSolidHorizontal(STRIP*, LINESTATE*, LONG*);
23: VOID vStripSolidHorizontalSet(STRIP*, LINESTATE*, LONG*);
24: VOID vStripSolidVertical(STRIP*, LINESTATE*, LONG*);
25: VOID vStripSolidDiagonalHorizontal(STRIP*, LINESTATE*, LONG*);
26: VOID vStripSolidDiagonalVertical(STRIP*, LINESTATE*, LONG*);
27:
28: VOID vStripStyledHorizontal(STRIP*, LINESTATE*, LONG*);
29: VOID vStripStyledVertical(STRIP*, LINESTATE*, LONG*);
30:
31: VOID vStripMaskedHorizontal(STRIP*, LINESTATE*, LONG*);
32: VOID vStripMaskedVertical(STRIP*, LINESTATE*, LONG*);
33:
34: PFNSTRIP gapfnStripSolidSet[] = {
35:
36: // Special strip drawers for solid lines with SET style ROPs:
37:
38: vStripSolidHorizontalSet,
39: vStripSolidVertical,
40: vStripSolidDiagonalHorizontal,
41: vStripSolidDiagonalVertical
42: };
43:
44: PFNSTRIP gapfnStrip[] = {
45:
46: // The order of these first 3 sets of strip drawers is determined by
47: // the FL_STYLE_MASK bits of the line flags:
48:
49: vStripSolidHorizontal,
50: vStripSolidVertical,
51: vStripSolidDiagonalHorizontal,
52: vStripSolidDiagonalVertical,
53:
54: vStripStyledHorizontal,
55: vStripStyledVertical,
56: NULL, // Diagonal goes here
57: NULL, // Diagonal goes here
58:
59: vStripMaskedHorizontal,
60: vStripMaskedVertical,
61: NULL, // Diagonal goes here
62: NULL, // Diagonal goes here
63: };
64:
65: // Prototypes to go to a device-format bitmap:
66:
67: VOID vBitmapSolidHorizontal(STRIP*, LINESTATE*, LONG*);
68: VOID vBitmapSolidVertical(STRIP*, LINESTATE*, LONG*);
69: VOID vBitmapSolidDiagonal(STRIP*, LINESTATE*, LONG*);
70:
71: VOID vBitmapStyledHorizontal(STRIP*, LINESTATE*, LONG*);
72: VOID vBitmapStyledVertical(STRIP*, LINESTATE*, LONG*);
73:
74: // For two-pass ROPs:
75:
76: VOID vCatchTwoPass(STRIP*, LINESTATE*, LONG*);
77:
78: PFNSTRIP gapfnCatchTwoPass[] = {
79: vCatchTwoPass,
80: vCatchTwoPass,
81: vCatchTwoPass,
82: vCatchTwoPass
83: };
84:
85: // VGA ulVgaMode constants:
86:
87: #define DR_SET 0x00
88: #define DR_AND 0x08
89: #define DR_OR 0x10
90: #define DR_XOR 0x18
91:
92: // Bit flag set if two passes needed:
93:
94: #define DR_2PASS 0x80
95:
96: // Table to convert ROP to usable information:
97:
98: static struct {
99: ULONG ulColorAnd;
100: ULONG ulColorXor;
101: ULONG ulVgaMode;
102: } arop[] = {
103: {0x00, 0xff, DR_SET}, // 1 R2_WHITE
104: {0x00, 0x00, DR_SET}, // 0 R2_BLACK
105: {0xff, 0xff, DR_AND|DR_2PASS}, // DPon R2_NOTMERGEPEN Dest invert + DPna
106: {0xff, 0xff, DR_AND}, // DPna R2_MASKNOTPEN
107: {0xff, 0xff, DR_SET}, // PN R2_NOTCOPYPEN
108: {0xff, 0x00, DR_AND|DR_2PASS}, // PDna R2_MASKPENNOT Dest invert + DPa
109: {0x00, 0xff, DR_XOR}, // Dn R2_NOT Invert dest without pen
110: {0xff, 0x00, DR_XOR}, // DPx R2_XORPEN
111: {0xff, 0xff, DR_OR|DR_2PASS}, // DPan R2_NOTMASKPEN Dest invert + DPno
112: {0xff, 0x00, DR_AND}, // DPa R2_MASKPEN
113: {0xff, 0xff, DR_XOR}, // DPxn R2_NOTXORPEN DPxn == DPnx
114: {0x00, 0x00, DR_OR}, // D R2_NOP Silliness!
115: {0xff, 0xff, DR_OR}, // DPno R2_MERGENOTPEN
116: {0xff, 0x00, DR_SET}, // P R2_COPYPEN
117: {0xff, 0x00, DR_OR|DR_2PASS}, // PDno R2_MERGEPENNOT Dest invert + DPo
118: {0xff, 0x00, DR_OR}, // DPo R2_MERGEPEN
119: };
120:
121: // The gaulAndXorTable contains and-masks and xor-masks for setting
122: // pels to one of four possible values. The and-masks have been
123: // inverted, and are stored in the low byte of each word. The
124: // xor-masks are stored in the high bytes.
125: //
126: // ROP XOR ~AND
127: // -------------------
128: // DDx 00 FF Set to zero
129: // Dn FF 00 Not destination
130: // D 00 00 Leave alone
131: // DDxn FF FF Set to one
132:
133: ULONG gaulAndXorTable[] = {
134: 0x00ff, // Set to zero
135: 0xff00, // Not destination
136: 0x0000, // Leave alone
137: 0xffff // Set to one
138: };
139:
140: ULONG gaulInitMasksLtoR[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f };
141: ULONG gaulInitMasksRtoL[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe };
142:
143: /******************************Public*Routine******************************\
144: * BOOL DrvStrokePath(pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix)
145: *
146: * Strokes the path.
147: *
148: \**************************************************************************/
149:
150: BOOL DrvStrokePath(
151: SURFOBJ* pso,
152: PATHOBJ* ppo,
153: CLIPOBJ* pco,
154: XFORMOBJ* pxo,
155: BRUSHOBJ* pbo,
156: POINTL* pptlBrushOrg,
157: LINEATTRS* pla,
158: MIX mix)
159: {
160: STYLEPOS aspLtoR[STYLE_MAX_COUNT];
161: STYLEPOS aspRtoL[STYLE_MAX_COUNT];
162: LINESTATE ls;
163: PFNSTRIP* apfn;
164: FLONG fl;
165: PDEVSURF pdsurf;
166: ULONG ulVgaMode;
167:
168: UNREFERENCED_PARAMETER(pxo);
169: UNREFERENCED_PARAMETER(pptlBrushOrg);
170:
171: // Verify that things are as they should be:
172:
173: // ASSERT(pso != (SURFOBJ*) NULL, "DrvStrokePath: surface");
174: // ASSERT(ppo != (PATHOBJ*) NULL, "DrvStrokePath: path");
175: // ASSERT(pco != (CLIPOBJ*) NULL, "DrvStrokePath: clipobj");
176: // ASSERT(pbo != (BRUSHOBJ*) NULL, "DrvStrokePath: brushobj");
177: // ASSERT(pla != (LINEATTRS*) NULL && !(pla->fl & LA_GEOMETRIC),
178: // "DrvStrokePath: lineattrs");
179: // ASSERT(pbo->iSolidColor != 0xffffffff,
180: // "DrvStrokePath: brushobj isn't solid");
181:
182: // Get the device ready:
183:
184: pdsurf = (PDEVSURF) pso->dhsurf;
185: // ASSERT(pdsurf != (PDEVSURF) NULL, "DrvStrokePath: no surface");
186:
187: fl = 0;
188:
189: // Look after styling initialization:
190:
191: if (pla->fl & LA_ALTERNATE)
192: {
193: // ASSERT(pla->pstyle == (FLOAT_LONG*) NULL && pla->cstyle == 0,
194: // "Non-empty style array for PS_ALTERNATE");
195:
196: ls.spTotal = 1;
197: ls.spTotal2 = 2;
198: ls.xyDensity = 1;
199: fl |= (FL_ALTERNATESTYLED | FL_MASKSTYLED);
200: }
201: else if (pla->pstyle != (FLOAT_LONG*) NULL)
202: {
203: PFLOAT_LONG pstyle;
204:
205: // ASSERT(pla->cstyle <= STYLE_MAX_COUNT, "Style array too large");
206:
207: pstyle = &pla->pstyle[pla->cstyle];
208:
209: ls.xyDensity = STYLE_DENSITY;
210: ls.spTotal = 0;
211: while (pstyle-- > pla->pstyle)
212: {
213: ls.spTotal += pstyle->l;
214: }
215: ls.spTotal *= STYLE_DENSITY;
216: ls.spTotal2 = 2 * ls.spTotal;
217:
218: // Compute starting style position (this is guaranteed not to overflow):
219:
220: ls.spNext = HIWORD(pla->elStyleState.l) * STYLE_DENSITY +
221: LOWORD(pla->elStyleState.l);
222:
223: // We optimize the style arrays that are even length and sum to 8. We
224: // also don't have any masked strip drawers for DFBs:
225:
226: if (ls.spTotal == (8 * STYLE_DENSITY) &&
227: (pla->cstyle & 1) == 0)
228: {
229: // Do "masked" styles.
230: // -------------------
231: //
232: // This case is merely an optimization; you can remove it and
233: // all style lines will still work. It just so happens that the
234: // default styles (such as PS_DOT, PS_DASHDOT, etc.) will all
235: // sum to 8, and there are some optimizations we can do on the
236: // VGA for that case.
237: //
238: // We make an 8 bit mask that represents each style unit in the
239: // style array, and we pass this to the "Masked" strip drawers
240: // (instead of calling the "Styled" strip drawers which still
241: // handle the arbitrary styles).
242:
243: LONG ii;
244:
245: ls.ulStyleMaskLtoR = 0;
246: ls.ulStyleMaskRtoL = 0;
247:
248: for (pstyle = pla->pstyle, ii = 8; ii > 0;)
249: {
250: LONG l1 = (pstyle++)->l;
251: LONG l2 = (pstyle++)->l;
252:
253: ls.ulStyleMaskRtoL >>= l1 + l2;
254: ls.ulStyleMaskRtoL |= gaulInitMasksRtoL[l2];
255:
256: ls.ulStyleMaskLtoR <<= l1 + l2;
257: ls.ulStyleMaskLtoR |= gaulInitMasksLtoR[l2];
258:
259: ii -= (l1 + l2);
260: }
261:
262: // Replicate byte and initialize to style position zero:
263:
264: ls.ulStyleMaskLtoR |= (ls.ulStyleMaskLtoR << 8);
265: ls.ulStyleMaskLtoR |= (ls.ulStyleMaskLtoR << 16);
266:
267: ls.ulStyleMaskRtoL |= (ls.ulStyleMaskRtoL << 8);
268: ls.ulStyleMaskRtoL |= (ls.ulStyleMaskRtoL << 16);
269:
270: // Check if we should start with a gap or start with a dash:
271:
272: if (pla->fl & LA_STARTGAP)
273: {
274: ls.ulStyleMaskLtoR = ~ls.ulStyleMaskLtoR;
275: ls.ulStyleMaskRtoL = ~ls.ulStyleMaskRtoL;
276: }
277:
278: // Initialize some other state:
279:
280: fl |= FL_MASKSTYLED;
281: }
282: else
283:
284: // Okay, we've got to do it the slow way:
285:
286: {
287: // Handle Arbitrary Styles
288: // -----------------------
289: //
290: // Because arbitrary styles are new to Win32, many apps won't
291: // know about them and will use the default styles (which will
292: // be handled by the "Masked" optimization case above), and so
293: // this code path won't get exercised too often. (See GDI's
294: // ExtCreatePen API.)
295: //
296: // But you still have to handle them, and do them right!
297:
298: FLOAT_LONG* pstyle;
299: STYLEPOS* pspDown;
300: STYLEPOS* pspUp;
301:
302: fl |= FL_ARBITRARYSTYLED;
303: ls.cStyle = pla->cstyle;
304: ls.aspRtoL = aspRtoL;
305: ls.aspLtoR = aspLtoR;
306:
307: if (pla->fl & LA_STARTGAP)
308: ls.ulStartMask = 0xffffffffL;
309: else
310: ls.ulStartMask = 0L;
311:
312: pstyle = pla->pstyle;
313: pspDown = &ls.aspRtoL[ls.cStyle - 1];
314: pspUp = &ls.aspLtoR[0];
315:
316: // We always draw strips left-to-right, but styles have to be laid
317: // down in the direction of the original line. This means that in
318: // the strip code we have to traverse the style array in the
319: // opposite direction;
320:
321: while (pspDown >= &ls.aspRtoL[0])
322: {
323: // ASSERT(pstyle->l > 0 && pstyle->l <= STYLE_MAX_VALUE,
324: // "Illegal style array value");
325:
326: *pspDown = pstyle->l * STYLE_DENSITY;
327: *pspUp = *pspDown;
328:
329: pspUp++;
330: pspDown--;
331: pstyle++;
332: }
333: }
334: }
335:
336: {
337: ULONG iColor;
338: ULONG iStripIndex;
339:
340: fl |= FL_PHYSICAL_DEVICE;
341:
342: // Compute the pointer to the correct strip drawing table. We
343: // have a special table for solid lines done with VGA mode == SET:
344:
345: iStripIndex = 4 * ((fl & FL_STYLE_MASK) >> FL_STYLE_SHIFT);
346: apfn = &gapfnStrip[iStripIndex];
347:
348: mix &= 0xf;
349: ulVgaMode = arop[mix].ulVgaMode;
350:
351: if (ulVgaMode == DR_SET && iStripIndex == 0)
352: apfn = &gapfnStripSolidSet[0];
353:
354: // Compute the correct color, based on the ROP we're doing:
355:
356: iColor = (pbo->iSolidColor & arop[mix].ulColorAnd)
357: ^ (arop[mix].ulColorXor);
358:
359: if (!(ulVgaMode & DR_2PASS))
360: vSetStrips(iColor, ulVgaMode);
361: else
362: {
363: // If the ROP requires 2 passes, we sneakily change our strip
364: // table pointer to point to only our own routine, and it
365: // handles calling the appropriate strip routines twice:
366:
367: ls.ulVgaMode = ulVgaMode ^ DR_2PASS;
368: ls.iColor = iColor;
369: ls.apfnStrip = apfn;
370: apfn = gapfnCatchTwoPass;
371: }
372: }
373:
374: // Set up to enumerate the path:
375:
376: if (pco->iDComplexity != DC_COMPLEX)
377: {
378: RECTL arclClip[4]; // For rectangular clipping
379: PATHDATA pd;
380: RECTL* prclClip = (RECTL*) NULL;
381: BOOL bMore;
382: ULONG cptfx;
383: POINTFIX ptfxStartFigure;
384: POINTFIX ptfxLast;
385: POINTFIX* pptfxFirst;
386: POINTFIX* pptfxBuf;
387:
388: if (pco->iDComplexity == DC_RECT)
389: {
390: fl |= FL_SIMPLE_CLIP;
391:
392: arclClip[0] = pco->rclBounds;
393:
394: // FL_FLIP_D:
395:
396: arclClip[1].top = pco->rclBounds.left;
397: arclClip[1].left = pco->rclBounds.top;
398: arclClip[1].bottom = pco->rclBounds.right;
399: arclClip[1].right = pco->rclBounds.bottom;
400:
401: // FL_FLIP_V:
402:
403: arclClip[2].top = -pco->rclBounds.bottom + 1;
404: arclClip[2].left = pco->rclBounds.left;
405: arclClip[2].bottom = -pco->rclBounds.top + 1;
406: arclClip[2].right = pco->rclBounds.right;
407:
408: // FL_FLIP_V | FL_FLIP_D:
409:
410: arclClip[3].top = pco->rclBounds.left;
411: arclClip[3].left = -pco->rclBounds.bottom + 1;
412: arclClip[3].bottom = pco->rclBounds.right;
413: arclClip[3].right = -pco->rclBounds.top + 1;
414:
415: prclClip = arclClip;
416: }
417:
418: PATHOBJ_vEnumStart(ppo);
419:
420: do {
421: bMore = PATHOBJ_bEnum(ppo, &pd);
422:
423: cptfx = pd.count;
424: if (cptfx == 0)
425: {
426: // ASSERT(!bMore, "Empty path record in non-empty path");
427: break;
428: }
429:
430: if (pd.flags & PD_BEGINSUBPATH)
431: {
432: ptfxStartFigure = *pd.pptfx;
433: pptfxFirst = pd.pptfx;
434: pptfxBuf = pd.pptfx + 1;
435: cptfx--;
436: }
437: else
438: {
439: pptfxFirst = &ptfxLast;
440: pptfxBuf = pd.pptfx;
441: }
442:
443: if (pd.flags & PD_RESETSTYLE)
444: ls.spNext = 0;
445:
446: // We have to check for cptfx == 0 because the only point in the
447: // subpath may have been the StartFigure point:
448:
449: if (cptfx > 0)
450: {
451: if (!bLines(pdsurf,
452: pptfxFirst,
453: pptfxBuf,
454: (RUN*) NULL,
455: cptfx,
456: &ls,
457: prclClip,
458: apfn,
459: fl))
460: return(FALSE);
461: }
462:
463: ptfxLast = pd.pptfx[pd.count - 1];
464:
465: if (pd.flags & PD_CLOSEFIGURE)
466: {
467: if (!bLines(pdsurf,
468: &ptfxLast,
469: &ptfxStartFigure,
470: (RUN*) NULL,
471: 1,
472: &ls,
473: prclClip,
474: apfn,
475: fl))
476: return(FALSE);
477: }
478: } while (bMore);
479:
480: if (fl & FL_STYLED)
481: {
482: // Save the style state:
483:
484: ULONG ulHigh;
485: ULONG ulLow;
486:
487: // !!! The engine handles unnormalized style states. This can
488: // !!! be removed. Might have to remove some asserts in the
489: // !!! engine.
490:
491: // Masked styles don't normalize the style state. It's a good
492: // thing to do, so let's do it now:
493:
494: if ((ULONG) ls.spNext >= (ULONG) ls.spTotal2)
495: ls.spNext = (ULONG) ls.spNext % (ULONG) ls.spTotal2;
496:
497: ulHigh = ls.spNext / ls.xyDensity;
498: ulLow = ls.spNext % ls.xyDensity;
499:
500: pla->elStyleState.l = MAKELONG(ulLow, ulHigh);
501: }
502: }
503: else
504: {
505: // Local state for path enumeration:
506:
507: BOOL bMore;
508: union {
509: BYTE aj[offsetof(CLIPLINE, arun) + RUN_MAX * sizeof(RUN)];
510: CLIPLINE cl;
511: } cl;
512:
513: fl |= FL_COMPLEX_CLIP;
514:
515: // We use the clip object when non-simple clipping is involved:
516:
517: PATHOBJ_vEnumStartClipLines(ppo, pco, pso, pla);
518:
519: do {
520: bMore = PATHOBJ_bEnumClipLines(ppo, sizeof(cl), &cl.cl);
521: if (cl.cl.c != 0)
522: {
523: if (fl & FL_STYLED)
524: {
525: ls.spComplex = HIWORD(cl.cl.lStyleState) * ls.xyDensity
526: + LOWORD(cl.cl.lStyleState);
527: }
528: if (!bLines(pdsurf,
529: &cl.cl.ptfxA,
530: &cl.cl.ptfxB,
531: &cl.cl.arun[0],
532: cl.cl.c,
533: &ls,
534: (RECTL*) NULL,
535: apfn,
536: fl))
537: return(FALSE);
538: }
539: } while (bMore);
540: }
541:
542: if (fl & FL_PHYSICAL_DEVICE)
543: vClearStrips(ulVgaMode);
544:
545: return(TRUE);
546: }
547:
548: /******************************Public*Routine******************************\
549: * VOID vCatchTwoPass(pstrip, pls, plStripEnd)
550: *
551: * Handles ROPs that cannot be done in a single pass using the VGA
552: * hardware. In order not to have a check in our main drawing loop for
553: * two-pass ROPs, we change the strip function table so that this function
554: * intercepts the call to draw the strips.
555: *
556: * This routine then figures out the appropriate actual strip drawer, and
557: * makes two calls to it: first to invert the destination, then to do the
558: * rest of the ROP.
559: *
560: \**************************************************************************/
561:
562: VOID vCatchTwoPass(STRIP* pstrip, LINESTATE* pls, LONG* plStripEnd)
563: {
564: BYTE* pjScreen = pstrip->pjScreen;
565: BYTE jBitMask = pstrip->jBitMask;
566: BYTE jStyleMask = pstrip->jStyleMask;
567: STYLEPOS* psp = pstrip->psp;
568: STYLEPOS spRemaining = pstrip->spRemaining;
569:
570: // Figure out the actual strip routine we're supposed to call:
571:
572: PFNSTRIP pfn = pls->apfnStrip[(pstrip->flFlips & FL_STRIP_MASK) >>
573: FL_STRIP_SHIFT];
574:
575: // On the first pass, we invert the destination:
576:
577: vSetStrips(0xff, DR_XOR);
578:
579: (*pfn)(pstrip, pls, plStripEnd);
580:
581: // We reset our strip variables for the second pass and handle the rest
582: // of the ROP:
583:
584: pstrip->pjScreen = pjScreen;
585: pstrip->jBitMask = jBitMask;
586: pstrip->jStyleMask = jStyleMask;
587: pstrip->psp = psp;
588: pstrip->spRemaining = spRemaining;
589:
590: vSetStrips(pls->iColor, pls->ulVgaMode);
591:
592: (*pfn)(pstrip, pls, plStripEnd);
593: }
594:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.