|
|
1.1 root 1: /******************************Module*Header*******************************\
2: * Module Name: textout.c
3: *
4: * VGA DrvTextOut Entry point
5: *
6: * Copyright (c) 1992 Microsoft Corporation
7: \**************************************************************************/
8: #include "driver.h"
9: #include "textout.h"
10: #include "winperf.h" // performance API definitions (PERFCTR)
11:
12: #define SO_MASK \
13: ( \
14: SO_FLAG_DEFAULT_PLACEMENT | \
15: SO_ZERO_BEARINGS | \
16: SO_CHAR_INC_EQUAL_BM_BASE | \
17: SO_MAXEXT_EQUAL_BM_SIDE \
18: )
19:
20: // accelerator masks for four canonical directions of
21: // writing (multiples of 90 degrees)
22:
23: #define SO_LTOR (SO_MASK | SO_HORIZONTAL)
24: #define SO_RTOL (SO_LTOR | SO_REVERSED)
25: #define SO_TTOB (SO_MASK | SO_VERTICAL)
26: #define SO_BTOT (SO_TTOB | SO_REVERSED)
27:
28: /**************************************************************************\
29: * Function Declarations
30: \**************************************************************************/
31:
32: VOID vGlyphBlt (PDEVSURF,PRECTL,ULONG,PGLYPHPOS,ULONG,ULONG,ULONG,FLONG);
33: VOID vStringBlt(PDEVSURF,PRECTL,ULONG,PGLYPHPOS,ULONG,ULONG,ULONG,FLONG);
34: ULONG ulSetXParentRegs(ROP4,PULONG,BOOL);
35: VOID vResetVGARegs(void);
36: BOOL bIdenticalRect(PRECTL,PRECTL);
37: FLONG flClipRect(PRECTL,PRECTL,PRECTL);
38: VOID lclFillRect(CLIPOBJ *pco, ULONG culRcl, PRECTL prcl, PDEVSURF pdsurf,
39: INT iColor);
40: BOOL DrvIntersectRect(PRECTL prcDst, PRECTL prcSrc1, PRECTL prcSrc2);
41: VOID vFastText(GLYPHPOS *, ULONG, PBYTE, ULONG, ULONG, DEVSURF *, RECTL *,
42: RECTL *, INT, INT, ULONG, RECTL *);
43:
44: // definition of counter data area for performance counters (PERFCTR)
45: extern PPERF_COUNTER_BLOCK pCounterBlock;
46:
47: /**************************************************************************\
48: * Mix mode-Rop4 Mapping Table
49: \**************************************************************************/
50:
51: static ROP4 arop4[] = { // !!! This table needs serious fixing
52: 0x0000, /* 0 */
53: 0x0000, /* DPon */
54: 0x0000, /* DPna */
55: 0x0f0f, /* Pn */
56: 0x0000, /* PDna */
57: 0x5555, /* Dn */
58: 0x0000, /* DPx */
59: 0x0000, /* DPan */
60: 0x0000, /* DPa */
61: 0x0000, /* DPxn */
62: 0x0000, /* D */
63: 0x0000, /* DPno */
64: 0xf0f0, /* P */
65: 0x0000, /* PDno */
66: 0x0000, /* DPo */
67: 0xffff /* 1 */
68: };
69:
70: #define B_ORDERED_RECT(prcl) (((prcl) == (PRECTL)NULL) ? 1 : (((prcl)->left <= (prcl)->right) && ((prcl)->top <= (prcl)->bottom)))
71:
72:
73: /******************************Public*Routine******************************\
74: * BOOL DrvTextOut(pso,pstro,pfo,pco,prclExtra,prcOpaque,
75: * pvFore,pvBack,pptOrg,r2Fore,r2Back)
76: *
77: \**************************************************************************/
78:
79: BOOL DrvTextOut(
80: SURFOBJ *pso,
81: STROBJ *pstro,
82: FONTOBJ *pfo,
83: CLIPOBJ *pco,
84: PRECTL prclExtra,
85: PRECTL prclOpaque,
86: BRUSHOBJ *pboFore,
87: BRUSHOBJ *pboOpaque,
88: PPOINTL pptlOrg,
89: MIX mix)
90: {
91: PDEVSURF pdsurf; // Pointer to device surface
92:
93: ULONG iClip; // Clip object's complexity
94: ULONG iClipTmp; // Clip object's complexity
95: ULONG ircl; // index to current clip rect
96: BOOL bMore; // Flag for clip enumeration
97: RECT_ENUM txen; // Clip enumeration object
98:
99: GLYPHPOS *pgp; // pointer to the 1st glyph
100: GLYPHBITS *pgb; // pointer to glyph bits.
101:
102: BOOL bMoreGlyphs; // Glyph enumeration flag
103: ULONG cGlyph; // number of glyphs in one batch
104: ULONG iGlyph; // index to current glyph
105: RECTL rclGlyph; // string/glyph cell
106: RECTL rclTmp; // Temporary rectangle
107: RECTL rclBankTmp; // Temporary rectangle when bank
108: // clipping
109:
110: ROP4 rop4; // Rop tranlated from mix mode
111: ULONG iSolidTextColor; // Solid foreground text color
112: ULONG iSolidForeColor; // Solid foreground color
113: ULONG iSolidBkColor; // Solid background color
114:
115: FLONG flStr = 0; // Accelator flag for DrvTextOut()
116:
117: ULONG ulMixMode; // Glyph mix mode
118: PFN pfnBlt; // function to output glyph/string
119: FLONG flOption = 0; // Accelator flag for pfnBlt
120: FLONG flOptionTemp; // Working version of flOption
121:
122: RECTL arclTmp[4]; // Temp storage for portions of
123: // opaquing rect
124: ULONG culRcl; // Temp rectangle count
125:
126: PDWORD pdwCounter; // Pointer to counter to increment (PERFCTR)
127:
128: // Increment BitBlt counter (PERFCTR)
129: pdwCounter = ( (PDWORD) pCounterBlock ) + 1;
130: (*pdwCounter)++;
131:
132:
133: //---------------------------------------------------------------------
134: // Get the target surface information
135: //---------------------------------------------------------------------
136:
137: // Now find out if the target is the screen
138: pdsurf = (PDEVSURF) pso->dhsurf;
139:
140: //---------------------------------------------------------------------
141: // Get information about clip object.
142: //---------------------------------------------------------------------
143:
144: iClip = DC_TRIVIAL;
145:
146: if (pco != NULL) {
147: iClip = pco->iDComplexity;
148: }
149:
150: //---------------------------------------------------------------------
151: // Get text color.
152: //---------------------------------------------------------------------
153:
154: iSolidForeColor = iSolidTextColor = pboFore->iSolidColor;
155:
156: //---------------------------------------------------------------------
157: // See if this is text we can handle faster with special-case code.
158: //---------------------------------------------------------------------
159:
160: if ((((prclOpaque != NULL) && (iClip != DC_COMPLEX)) ||
161: // handle opaque both non-clipped &
162: // rectangle-clipped
163: ((prclOpaque == NULL) && (iClip == DC_TRIVIAL))) &&
164: // handle xpar non-clipped only
165: // for now
166: (pstro->pgp != NULL) && // no glyph enumeration for now
167: (prclExtra == NULL) && // no extra rects for now
168: ((pstro->flAccel & (SO_HORIZONTAL | SO_VERTICAL | SO_REVERSED)) ==
169: SO_HORIZONTAL)) { // only left-to-right text for now
170:
171: ULONG ulBufferWidthInBytes;
172: ULONG ulBufferBytes;
173: BOOL bTextPerfectFit;
174: ULONG fDrawFlags;
175: BYTE *pjTempBuffer;
176: BOOL bTempAlloc;
177:
178: // It's the type of text we can special-case; see if the temp buffer is
179: // big enough for the text; if not, try to allocate enough memory.
180: // Round up to the nearest dword multiple.
181:
182: ulBufferWidthInBytes = ((((pstro->rclBkGround.right + 15) & ~0x0F) -
183: (pstro->rclBkGround.left & ~0x0F)) >> 3);
184: ulBufferBytes = ((ulBufferWidthInBytes *
185: (pstro->rclBkGround.bottom - pstro->rclBkGround.top)) + 3)
186: & ~0x03;
187:
188: if (ulBufferBytes <= pdsurf->ulTempBufferSize) {
189: // The temp buffer is big enough, so we'll use it
190: pjTempBuffer = pdsurf->pvBankBufferPlane0;
191: bTempAlloc = FALSE;
192: } else {
193: // The temp buffer isn't big enough, so we'll try to allocate
194: // enough memory
195: if ((pjTempBuffer =
196: LocalAlloc(LMEM_FIXED, ulBufferBytes)) == NULL) {
197: // We couldn't get enough memory, so fall back to the general,
198: // slow code
199: goto NoFastText;
200: }
201:
202: // Mark that we have to free the buffer when we're done
203: bTempAlloc = TRUE;
204: }
205:
206: // One way or another, we've found a buffer that's big enough; set up
207: // for accelerated text drawing
208:
209: // Set fixed pitch, overlap, and top & bottom Y alignment flags
210: fDrawFlags = ((pstro->ulCharInc != 0) ? 0x01 : 0) |
211: (((pstro->flAccel & (SO_ZERO_BEARINGS |
212: SO_FLAG_DEFAULT_PLACEMENT)) !=
213: (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT))
214: ? 0x02 : 0) |
215: (((pstro->flAccel & (SO_ZERO_BEARINGS |
216: SO_FLAG_DEFAULT_PLACEMENT |
217: SO_MAXEXT_EQUAL_BM_SIDE)) ==
218: (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
219: SO_MAXEXT_EQUAL_BM_SIDE)) ? 0x04 : 0);
220:
221: // If there's an opaque rectangle, we'll do as much opaquing as
222: // possible as we do the text. If the opaque rectangle is larger than
223: // the text rectangle, then we'll do the fringe areas right now, and
224: // the text and associated background areas together later
225: if (prclOpaque != (PRECTL) NULL) {
226:
227: // This driver only handles solid brushes
228: iSolidBkColor = pboOpaque->iSolidColor;
229:
230: // See if we have fringe areas to do. If so, build a list of
231: // rectangles to fill, in rightdown order
232:
233: culRcl = 0;
234:
235: // Top fragment
236: if (pstro->rclBkGround.top > prclOpaque->top) {
237: arclTmp[culRcl].top = prclOpaque->top;
238: arclTmp[culRcl].left = prclOpaque->left;
239: arclTmp[culRcl].right = prclOpaque->right;
240: arclTmp[culRcl++].bottom = pstro->rclBkGround.top;
241: }
242:
243: // Left fragment
244: if (pstro->rclBkGround.left > prclOpaque->left) {
245: arclTmp[culRcl].top = pstro->rclBkGround.top;
246: arclTmp[culRcl].left = prclOpaque->left;
247: arclTmp[culRcl].right = pstro->rclBkGround.left;
248: arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom;
249: }
250:
251: // Right fragment
252: if (pstro->rclBkGround.right < prclOpaque->right) {
253: arclTmp[culRcl].top = pstro->rclBkGround.top;
254: arclTmp[culRcl].right = prclOpaque->right;
255: arclTmp[culRcl].left = pstro->rclBkGround.right;
256: arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom;
257: }
258:
259: // Bottom fragment
260: if (pstro->rclBkGround.bottom < prclOpaque->bottom) {
261: arclTmp[culRcl].bottom = prclOpaque->bottom;
262: arclTmp[culRcl].left = prclOpaque->left;
263: arclTmp[culRcl].right = prclOpaque->right;
264: arclTmp[culRcl++].top = pstro->rclBkGround.bottom;
265: }
266:
267: // Fill any fringe rectangles we found
268: if (culRcl != 0) {
269: if (iClip == DC_TRIVIAL) {
270: vTrgBlt(pdsurf, culRcl, arclTmp, R2_COPYPEN,
271: iSolidBkColor);
272: } else {
273: lclFillRect(pco, culRcl, arclTmp, pdsurf,
274: iSolidBkColor);
275: }
276: }
277: }
278:
279: // We're done with separate opaquing; any further opaquing will happen
280: // as part of the text drawing
281:
282: // Clear the buffer if the text isn't going to set every bit
283: bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
284: SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
285: SO_CHAR_INC_EQUAL_BM_BASE)) ==
286: (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
287: SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
288:
289: if (!bTextPerfectFit) {
290: // Note that we already rounded up to a dword multiple size.
291: vClearMemDword((ULONG *)pjTempBuffer, ulBufferBytes >> 2);
292: }
293:
294: // Draw the text into the temp buffer, and thence to the screen
295: vFastText(pstro->pgp,
296: pstro->cGlyphs,
297: ((PBYTE) pjTempBuffer) +
298: ((pstro->rclBkGround.left & 0x08) ? 1 : 0),
299: ulBufferWidthInBytes,
300: pstro->ulCharInc,
301: pdsurf,
302: &pstro->rclBkGround,
303: prclOpaque,
304: iSolidForeColor,
305: iSolidBkColor,
306: fDrawFlags,
307: (iClip == DC_TRIVIAL) ? NULL : &pco->rclBounds);
308:
309: // Free up any memory we allocated for the temp buffer
310: if (bTempAlloc) {
311: LocalFree(pjTempBuffer);
312: }
313:
314: return(TRUE);
315:
316: }
317:
318: NoFastText:
319:
320: //--------------------------------------------------------------------------
321: // Get the foreground and background colors
322: //--------------------------------------------------------------------------
323:
324: rop4 = arop4[(mix & 255) - R2_BLACK]; // Get ROP4 from mix mode
325:
326: // This driver only handles solid brushes
327:
328: // If no background rectangle, we need to paint only the glyph foreground.
329: // Set VGA registers for the current rop and foreground color at once and
330: // maintain them while blting the glyphs.
331:
332: if (prclOpaque == (PRECTL) NULL)
333: {
334: ulMixMode = ulSetXParentRegs(rop4, &iSolidForeColor, TRUE);
335: flStr |= TO_NO_OPAQUE_RECT;
336: } else {
337:
338: // This driver only handles solid brushes
339: iSolidBkColor = pboOpaque->iSolidColor;
340: // ASSERT ( iSolidBkColor != 0xFFFFFFFFL, "Non solid opaque brush\n" );
341: }
342:
343: //--------------------------------------------------------------------------
344: // Enumerate glyphs for the string, and output to screen one batch at a time.
345: // Here is how we will output background rectangle and glyphs:-
346: //
347: // if glyphs are non-justified and horizontally aligned
348: // if opaque background rectangle doesn't exactly match the string bound
349: // Paint portions of background that are outside text cells
350: // Output the string one batch at a time, drawing both fg & bg in cells
351: // else
352: // Paint opaque rectangle only once
353: // Output to screen one glyph at a time
354: //
355: //--------------------------------------------------------------------------
356:
357: // Set up the STROBJ for enumerating the glyphs
358:
359: // STROBJ_vEnumStart(pstro); // This is automatic.
360:
361: if ((pstro->flAccel == SO_LTOR) && (pstro->ulCharInc != 0))
362: {
363: flStr |= TO_FIXED_PITCH;
364: if ((pstro->ulCharInc & 7) == 0)
365: flStr |= TO_MULTIPLE_BYTE;
366: }
367:
368: do {
369:
370: // Get the next batch of glyphs
371:
372: if (pstro->pgp != NULL) {
373: // There's only the one batch of glyphs, so save ourselves a call
374: pgp = pstro->pgp;
375: cGlyph = pstro->cGlyphs;
376: bMoreGlyphs = FALSE;
377: } else {
378: bMoreGlyphs = STROBJ_bEnum(pstro,&cGlyph,&pgp);
379: }
380:
381: //--------------------------------------------------------------------
382: // No glyph, no work!
383: //--------------------------------------------------------------------
384:
385: if ( cGlyph ) {
386: // Collect information about the string.
387:
388: pgb = pgp->pgdf->pgb; // Locate the bitmap info.
389:
390: if ((flStr & TO_MULTIPLE_BYTE) &&
391: ((pgb->ptlOrigin.x + pgp->ptl.x) & 7) == 0) {
392: flStr |= TO_BYTE_ALIGNED;
393: }
394:
395: if ((pstro->flAccel == SO_LTOR) &&
396: (pgb->sizlBitmap.cy <= MAX_GLYPH_HEIGHT)) {
397: // We can blt horizontally aligned string with non-justified
398: // text at once.
399:
400: pfnBlt = (PFN)vStringBlt;
401: flOption |= VGB_ENTIRE_STRING_BLT;
402:
403: // we can special-case an aligned byte-size string
404:
405: flOption |= (flStr & (VGB_BYTE_ALIGNED | VGB_MULTIPLE_BYTE));
406:
407: // If there's an opaque rectangle, then if the opaque
408: // rectangle exactly matches the text rectangle, we'll do the
409: // opaque rectangle as we do the text. If the opaque rectangle
410: // is larger than the text rectangle, then we'll do the fringe
411: // areas right now, and the text and associated background
412: // areas together, later.
413: if (!(flStr & TO_NO_OPAQUE_RECT)) {
414:
415: // See if we have fringe areas to do. If so, build a
416: // list of rectangles to fill, in rightdown order
417:
418: culRcl = 0;
419:
420: // Top fragment
421: if (pstro->rclBkGround.top > prclOpaque->top) {
422: arclTmp[culRcl].top = prclOpaque->top;
423: arclTmp[culRcl].left = prclOpaque->left;
424: arclTmp[culRcl].right = prclOpaque->right;
425: arclTmp[culRcl++].bottom = pstro->rclBkGround.top;
426: }
427:
428: // Left fragment
429: if (pstro->rclBkGround.left > prclOpaque->left) {
430: arclTmp[culRcl].top = pstro->rclBkGround.top;
431: arclTmp[culRcl].left = prclOpaque->left;
432: arclTmp[culRcl].right = pstro->rclBkGround.left;
433: arclTmp[culRcl++].bottom =
434: pstro->rclBkGround.bottom;
435: }
436:
437: // Right fragment
438: if (pstro->rclBkGround.right < prclOpaque->right) {
439: arclTmp[culRcl].top = pstro->rclBkGround.top;
440: arclTmp[culRcl].right = prclOpaque->right;
441: arclTmp[culRcl].left = pstro->rclBkGround.right;
442: arclTmp[culRcl++].bottom =
443: pstro->rclBkGround.bottom;
444: }
445:
446: // Bottom fragment
447: if (pstro->rclBkGround.bottom < prclOpaque->bottom) {
448: arclTmp[culRcl].bottom = prclOpaque->bottom;
449: arclTmp[culRcl].left = prclOpaque->left;
450: arclTmp[culRcl].right = prclOpaque->right;
451: arclTmp[culRcl++].top = pstro->rclBkGround.bottom;
452: }
453:
454: // Fill any fringe rectangles we found
455: if (culRcl > 0) {
456: if (iClip == DC_TRIVIAL) {
457: vTrgBlt(pdsurf, culRcl, arclTmp, R2_COPYPEN,
458: iSolidBkColor);
459: } else {
460: lclFillRect(pco, culRcl, arclTmp, pdsurf,
461: iSolidBkColor);
462: }
463: }
464:
465:
466: // The opaque rectangle exactly matches the text
467: // background cells. We can simultaneously paint it
468: // with the glyph. Then, pretend no background
469: // rectangle.
470:
471: flStr |= TO_NO_OPAQUE_RECT;
472: flOption |= VGB_OPAQUE_BKGRND;
473:
474: // Although we do not want to set the VGA regs, we
475: // need to know their mode when we actually blt.
476:
477: ulMixMode = ulSetXParentRegs(rop4, &iSolidForeColor, FALSE);
478:
479: }
480:
481: // It is foolishly assumed in the clipping vStrBlt that GDI
482: // puts all positions in the GLYPHPOS array even when the font
483: // is fixed pitch.
484:
485: if (pstro->ulCharInc != 0) {
486: UINT ii;
487: LONG x,y;
488:
489: x = pgp[0].ptl.x;
490: y = pgp[0].ptl.y;
491:
492: for (ii=1; ii<cGlyph; ii++) {
493: x += pstro->ulCharInc;
494: pgp[ii].ptl.x = x;
495: pgp[ii].ptl.y = y;
496: }
497: }
498: } else {
499: // We need to output one glyph at a time.
500:
501: pfnBlt = (PFN) vGlyphBlt;
502:
503: // It is foolishly assumed in vGlyphBlt that GDI puts all
504: // positions in the GLYPHPOS array even when the font is
505: // fixed pitch.
506:
507: if (pstro->ulCharInc != 0) {
508: UINT ii;
509: LONG x,y;
510:
511: x = pgp[0].ptl.x;
512: y = pgp[0].ptl.y;
513: for (ii=1; ii<cGlyph; ii++) {
514: x += pstro->ulCharInc;
515: pgp[ii].ptl.x = x;
516: pgp[ii].ptl.y = y;
517: }
518: }
519: }
520: }
521:
522: //------------------------------------------------------------------
523: // Paint background rectangle if exists.
524: //------------------------------------------------------------------
525:
526: if (!(flStr & TO_NO_OPAQUE_RECT))
527: {
528: switch ( iClip )
529: {
530: case DC_RECT:
531:
532: // Intersect opaque and clip rectangles
533:
534: flClipRect(&rclTmp, prclOpaque, &pco->rclBounds);
535:
536: if (BINVALIDRECT(rclTmp))
537: {
538: break;
539: };
540: prclOpaque = &rclTmp;
541:
542: case DC_TRIVIAL:
543: vTrgBlt(pdsurf, 1, prclOpaque, R2_COPYPEN, iSolidBkColor);
544: break;
545:
546: case DC_COMPLEX:
547:
548: CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY,
549: ENUM_RECT_LIMIT);
550: bMore = TRUE;
551:
552: do
553: {
554: if (bMore) {
555: bMore = CLIPOBJ_bEnum(pco, (ULONG)
556: sizeof(txen), (PVOID) &txen);
557: }
558:
559: for (ircl = 0; ircl < txen.c; ircl++)
560: {
561:
562: // Clip only if we have clipping region
563:
564: flClipRect ( &rclTmp, prclOpaque, &txen.arcl[ircl] );
565:
566: if (!(BINVALIDRECT(rclTmp)))
567: {
568: // rop4 <--> PATCOPY
569:
570: vTrgBlt(pdsurf, 1, &rclTmp,
571: R2_COPYPEN, iSolidBkColor);
572: };
573: }
574:
575: } while (bMore);
576: break;
577: }
578:
579: // We need to paint the background only once. So pretend it
580: // does not exist anymore.
581:
582: flStr |= TO_NO_OPAQUE_RECT;
583:
584: // Set VGA registers for transparent glyphs.
585:
586: ulMixMode = ulSetXParentRegs(rop4, &iSolidForeColor, TRUE);
587:
588: }
589:
590: //----------------------------------------------------------------------
591: // We are ready to output glyphs to screen. By now either the background
592: // rectangle (if any) was painted or we will paint it while outputting
593: // each glyph/string.
594: //----------------------------------------------------------------------
595:
596: for (iGlyph = 0; iGlyph < cGlyph; iGlyph++)
597: {
598: pgb = pgp[iGlyph].pgdf->pgb;
599: iClipTmp = iClip;
600:
601: if (!(flOption & VGB_ENTIRE_STRING_BLT))
602: {
603: pgp[iGlyph].ptl.x += pgb->ptlOrigin.x;
604: pgp[iGlyph].ptl.y += pgb->ptlOrigin.y;
605:
606: rclGlyph.left = pgp[iGlyph].ptl.x;
607: rclGlyph.right = rclGlyph.left + pgb->sizlBitmap.cx;
608: rclGlyph.top = pgp[iGlyph].ptl.y;
609: rclGlyph.bottom = rclGlyph.top + pgb->sizlBitmap.cy;
610:
611: if ((iClipTmp == DC_TRIVIAL) &&
612: ((rclGlyph.left < pco->rclBounds.left) ||
613: (rclGlyph.top < pco->rclBounds.top) ||
614: (rclGlyph.right > pco->rclBounds.right) ||
615: (rclGlyph.bottom > pco->rclBounds.bottom)))
616: iClipTmp = DC_RECT;
617: } else {
618: // Build the correct bounding box for the current batch of
619: // glyphs (the bounding box in the STROBJ is for the entire
620: // string, not on a per-batch basis)
621: rclGlyph.left = pgp[iGlyph].ptl.x;
622: rclGlyph.right = pgp[iGlyph + cGlyph - 1].ptl.x +
623: pgp[iGlyph + cGlyph - 1].pgdf->pgb->sizlBitmap.cx;
624: rclGlyph.top = pstro->rclBkGround.top;
625: rclGlyph.bottom = pstro->rclBkGround.bottom;
626: }
627:
628: flOption &= ~(VGB_VERT_CLIPPED_GLYPH | VGB_HORIZ_CLIPPED_GLYPH);
629:
630: switch ( iClipTmp )
631: {
632: case DC_RECT:
633:
634: // Intersect glyph and clip rectangles
635:
636: flOption |= flClipRect(&rclGlyph, &rclGlyph, &pco->rclBounds);
637: if (BINVALIDRECT(rclGlyph))
638: break;
639:
640: case DC_TRIVIAL:
641: // Cycle through all banks that the (possibly clipped)
642: // glpyh rect spans
643:
644: // If the proper bank for the top scan line of
645: // the clipped glyph isn't mapped in, map it in
646: if ((rclGlyph.top < pdsurf->rcl1WindowClip.top) ||
647: (rclGlyph.top >= pdsurf->rcl1WindowClip.bottom)) {
648:
649: // Map in the bank containing the top (possibly
650: // clipped) glyph line
651: pdsurf->pfnBankControl(pdsurf,
652: rclGlyph.top,
653: JustifyTop);
654: }
655:
656: // Now draw the part of the rect that's in each
657: // bank
658:
659: for (;;) {
660:
661: flOptionTemp = flOption |
662: flClipRect(&rclBankTmp, &rclGlyph,
663: &pdsurf->rcl1WindowClip);
664:
665: (*pfnBlt)(pdsurf, &rclBankTmp, cGlyph,
666: &pgp[iGlyph], iSolidForeColor, iSolidBkColor,
667: ulMixMode, flOptionTemp);
668:
669: // Done if this bank contains the last line
670: // of the fill
671: if (rclGlyph.bottom <= pdsurf->rcl1WindowClip.bottom) {
672: break;
673: }
674:
675: // Map in the next bank
676: pdsurf->pfnBankControl(pdsurf,
677: pdsurf->rcl1WindowClip.bottom,
678: JustifyTop);
679:
680: }
681:
682: break;
683:
684: case DC_COMPLEX:
685: CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY,
686: ENUM_RECT_LIMIT);
687: bMore = TRUE;
688:
689: do
690: {
691: if (bMore) {
692: // Enumerate more clip rects
693: bMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(txen),
694: (PVOID) &txen);
695: }
696:
697: // Draw the portion of the glyph that intersects each
698: // clip rect in turn
699: for (ircl = 0; ircl < txen.c; ircl++)
700: {
701: // Clip the glyph to the next clip rect, and set
702: // our clipping flags
703: flOption |= flClipRect ( &rclTmp, &rclGlyph,
704: &txen.arcl[ircl] );
705:
706: // If we have a valid rectangle to draw, draw it
707: if (!(BINVALIDRECT(rclTmp))) {
708: // Cycle through all banks that the clipped
709: // glpyh rect spans
710:
711: // If the proper bank for the top scan line of
712: // the clipped glyph isn't mapped in, map it in
713: if ((rclTmp.top <
714: pdsurf->rcl1WindowClip.top) ||
715: (rclTmp.top >=
716: pdsurf->rcl1WindowClip.bottom)) {
717:
718: // Map in the bank containing the top
719: // clipped glyph line
720: pdsurf->pfnBankControl(pdsurf,
721: rclTmp.top,
722: JustifyTop);
723: }
724:
725: // Now draw the part of the rect that's in each
726: // bank
727:
728: for (;;) {
729:
730: flOptionTemp = flOption |
731: flClipRect(&rclBankTmp, &rclTmp,
732: &pdsurf->rcl1WindowClip);
733:
734:
735: (*pfnBlt)(pdsurf, &rclBankTmp, cGlyph,
736: &pgp[iGlyph], iSolidForeColor,
737: iSolidBkColor, ulMixMode,
738: flOptionTemp);
739:
740: // Done if this bank contains the last line
741: // of the fill
742: if (rclTmp.bottom <=
743: pdsurf->rcl1WindowClip.bottom) {
744: break;
745: }
746:
747: // Map in the next bank
748: pdsurf->pfnBankControl(pdsurf,
749: pdsurf->rcl1WindowClip.bottom,
750: JustifyTop);
751:
752: }
753: }
754:
755: flOption &= ~(VGB_VERT_CLIPPED_GLYPH |
756: VGB_HORIZ_CLIPPED_GLYPH);
757: }
758: } while (bMore);
759: break;
760: }
761:
762: // We might have blted the entire string.
763:
764: if (flOption & VGB_ENTIRE_STRING_BLT)
765: break;
766: }
767:
768: } while (bMoreGlyphs);
769:
770: // Reset VGA registers
771:
772: vResetVGARegs();
773:
774: //--------------------------------------------------------------------------
775: // Now handle the 'extra' rectangles.
776: //--------------------------------------------------------------------------
777:
778: if (prclExtra != (PRECTL) NULL)
779: {
780: while (prclExtra->left != prclExtra->right)
781: {
782: switch ( iClip )
783: {
784: case DC_TRIVIAL:
785: vTrgBlt(pdsurf, 1, prclExtra, mix, iSolidTextColor);
786: break;
787:
788: case DC_RECT:
789:
790: // Intersect opaque and clip rectangles
791:
792: flClipRect ( &rclTmp, prclExtra, &pco->rclBounds );
793:
794: if (BINVALIDRECT(rclTmp))
795: break;
796:
797: vTrgBlt(pdsurf, 1, &rclTmp, mix, iSolidTextColor);
798: break;
799:
800: case DC_COMPLEX:
801: CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY,
802: ENUM_RECT_LIMIT);
803: bMore = TRUE;
804:
805: do
806: {
807: if (bMore) {
808: bMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(txen),
809: (PVOID) &txen);
810: }
811:
812: for (ircl = 0; ircl < txen.c; ircl++)
813: {
814: flClipRect ( &rclTmp, prclExtra, &txen.arcl[ircl] );
815:
816: if (!(BINVALIDRECT(rclTmp)))
817: {
818: vTrgBlt(pdsurf, 1, &rclTmp,
819: mix, iSolidTextColor);
820: };
821: }
822: } while (bMore);
823: break;
824: };
825:
826: prclExtra++; // Advance to next extra rectangle
827: }
828: }
829:
830: //--------------------------------------------------------------------------
831: // Clean up the surface
832: //--------------------------------------------------------------------------
833:
834: pptlOrg;
835: return(TRUE);
836: }
837:
838:
839: //--------------------------------------------------------------------------
840: // Fills the specified rectangles on the specified surface with the
841: // specified color, honoring the requested clipping. No more than four
842: // rectangles should be passed in. Intended for drawing the areas of the
843: // opaquing rectangle that extended beyond the text box. The rectangles must
844: // be in left to right, top to bottom order. Assumes there is at least one
845: // rectangle in the list.
846: //--------------------------------------------------------------------------
847:
848: VOID lclFillRect(
849: CLIPOBJ *pco,
850: ULONG culRcl,
851: PRECTL prcl,
852: PDEVSURF pdsurf,
853: INT iColor)
854: {
855: BOOL bMore; // Flag for clip enumeration
856: RECT_ENUM txen; // Clip enumeration object
857: ULONG i, j;
858: RECTL arclTmp[4];
859: ULONG culRclTmp;
860: RECTL *prclTmp, *prclClipTmp;
861: INT iLastBottom;
862: RECTL *pClipRcl;
863: INT iClip;
864:
865: // ASSERT(culRcl <= 4, "Too many rects");
866:
867: iClip = DC_TRIVIAL;
868:
869: if (pco != NULL) {
870: iClip = pco->iDComplexity;
871: }
872:
873: switch ( iClip ) {
874:
875: case DC_TRIVIAL:
876:
877: vTrgBlt(pdsurf, culRcl, prcl, R2_COPYPEN, iColor);
878:
879: break;
880:
881: case DC_RECT:
882:
883: prclTmp = &pco->rclBounds;
884:
885: // Generate a list of clipped rects
886: for (culRclTmp=0, i=0; i<culRcl; i++, prcl++) {
887:
888: // Intersect fill and clip rectangles
889: if (DrvIntersectRect(&arclTmp[culRclTmp], prcl, prclTmp)) {
890:
891: // Add to list if anything's left to draw
892: culRclTmp++;
893: }
894: }
895:
896: // Draw the clipped rects
897: if (culRclTmp != 0) {
898: vTrgBlt(pdsurf, culRclTmp, arclTmp, R2_COPYPEN, iColor);
899: }
900:
901: break;
902:
903: case DC_COMPLEX:
904:
905: // Bottom of last rectangle to fill
906: iLastBottom = prcl[culRcl-1].bottom;
907:
908: // Initialize the clip rectangle enumeration to rightdown so we can
909: // take advantage of the rectangle list being rightdown
910: CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN,
911: ENUM_RECT_LIMIT);
912:
913: // Scan through all the clip rectangles, looking for intersects
914: // of fill areas with region rectangles
915: do {
916:
917: // Get a batch of region rectangles
918: bMore = CLIPOBJ_bEnum(pco, (ULONG)sizeof(txen), (PVOID)&txen);
919:
920: // Clip the rect list to each region rect
921: for (j = txen.c, pClipRcl = txen.arcl; j-- > 0; pClipRcl++) {
922:
923: // Since the rectangles and the region enumeration are both
924: // rightdown, we can zip through the region until we reach
925: // the first fill rect, and are done when we've passed the
926: // last fill rect.
927:
928: if (pClipRcl->top >= iLastBottom) {
929: // Past last fill rectangle; nothing left to do
930: return;
931: }
932:
933: // Do intersection tests only if we've reached the top of
934: // the first rectangle to fill
935: if (pClipRcl->bottom > prcl->top) {
936:
937: // We've reached the top Y scan of the first rect, so
938: // it's worth bothering checking for intersection
939:
940: // Generate a list of the rects clipped to this region
941: // rect
942: prclTmp = prcl;
943: prclClipTmp = arclTmp;
944: for (i = culRcl, culRclTmp=0; i-- > 0; prclTmp++) {
945:
946: // Intersect fill and clip rectangles
947: if (DrvIntersectRect(prclClipTmp, prclTmp,
948: pClipRcl)) {
949:
950: // Add to list if anything's left to draw
951: culRclTmp++;
952: prclClipTmp++;
953: }
954: }
955:
956: // Draw the clipped rects
957: if (culRclTmp != 0) {
958: vTrgBlt(pdsurf, culRclTmp, arclTmp, R2_COPYPEN,
959: iColor);
960: }
961: }
962: }
963: } while (bMore);
964:
965: break;
966: }
967:
968: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.