|
|
1.1 root 1: /******************************Module*Header*******************************\
2: * Module Name: text.c
3: *
4: * Optimized TextOut for the MIPS. Reduces the total number of memory writes
5: * required to output a glyph which significantly improves performance when
6: * using slower video memory.
7: *
8: * Copyright (c) 1992 Microsoft Corporation
9: \**************************************************************************/
10:
11: #include "driver.h"
12:
13: //
14: // Define string object accelerator masks.
15: //
16:
17: #define SO_MASK \
18: (SO_FLAG_DEFAULT_PLACEMENT | SO_ZERO_BEARINGS | \
19: SO_CHAR_INC_EQUAL_BM_BASE | SO_MAXEXT_EQUAL_BM_SIDE)
20:
21: #define SO_LTOR (SO_MASK | SO_HORIZONTAL)
22: #define SO_RTOL (SO_LTOR | SO_REVERSED)
23: #define SO_TTOB (SO_MASK | SO_VERTICAL)
24: #define SO_BTOT (SO_TTOB | SO_REVERSED)
25:
26: //
27: // Define enumeration structure.
28: //
29:
30: #define BB_RECT_LIMIT 20
31:
32: typedef struct _ENUMRECTLIST {
33: ULONG c;
34: RECTL arcl[BB_RECT_LIMIT];
35: } ENUMRECTLIST;
36:
37: //
38: // Define function prototype for glyph output routines.
39: //
40:
41: typedef
42: VOID
43: (*PDRVP_GLYPHOUT_ROUTINE) (
44: IN PBYTE DrawPoint,
45: IN PULONG GlyphBits,
46: IN ULONG GlyphWidth,
47: IN ULONG GlyphHeight
48: );
49:
50: VOID
51: DrvpOutputGlyphTransparent (
52: IN PBYTE DrawPoint,
53: IN PBYTE GlyphBitmap,
54: IN ULONG GlyphWidth,
55: IN ULONG GlyphHeight
56: );
57:
58: //
59: // Define big endian color mask table conversion table.
60: //
61:
62: const ULONG DrvpColorMask[16] = {
63: 0x00000000, // 0000 -> 0000
64: 0xff000000, // 0001 -> 1000
65: 0x00ff0000, // 0010 -> 0100
66: 0xffff0000, // 0011 -> 1100
67: 0x0000ff00, // 0100 -> 0010
68: 0xff00ff00, // 0101 -> 1010
69: 0x00ffff00, // 0110 -> 0110
70: 0xffffff00, // 0111 -> 1110
71: 0x000000ff, // 1000 -> 0001
72: 0xff0000ff, // 1001 -> 1001
73: 0x00ff00ff, // 1010 -> 0101
74: 0xffff00ff, // 1011 -> 1101
75: 0x0000ffff, // 1100 -> 0011
76: 0xff00ffff, // 1101 -> 1011
77: 0x00ffffff, // 1110 -> 0111
78: 0xffffffff}; // 1111 -> 1111
79:
80: //
81: // Define draw color table that is generated for text output.
82: //
83:
84: ULONG DrvpDrawColorTable[16];
85:
86: //
87: // Define foreground color for transparent output.
88: //
89:
90: ULONG DrvpForeGroundColor;
91:
92: //
93: // Define scanline width value.
94: //
95:
96: ULONG DrvpScanLineWidth;
97:
98: //
99: // Define global opaque glyph output routine address table.
100: //
101:
102: extern PDRVP_GLYPHOUT_ROUTINE DrvpOpaqueTable[8];
103:
104: /******************************Public*Routine******************************\
105: * DrvpIntersectRect
106: *
107: * This routine checks to see if the two specified retangles intersect.
108: *
109: * A value of TRUE is returned if the rectangles intersect. Otherwise,
110: * a value of FALSE is returned.
111: *
112: \**************************************************************************/
113:
114: BOOL DrvpIntersectRect (
115: IN PRECTL Rectl1,
116: IN PRECTL Rectl2,
117: OUT PRECTL DestRectl)
118:
119: {
120:
121: //
122: // Compute the maximum left edge and the minimum right edge.
123: //
124:
125: DestRectl->left = max(Rectl1->left, Rectl2->left);
126: DestRectl->right = min(Rectl1->right, Rectl2->right);
127:
128: //
129: // If the minimum right edge is greater than the maximum left edge,
130: // then the rectanges may intersect. Otherwise, they do not intersect.
131: //
132:
133: if (DestRectl->left < DestRectl->right) {
134:
135: //
136: // Compute the maximum top edge and the minimum bottom edge.
137: //
138:
139: DestRectl->top = max(Rectl1->top, Rectl2->top);
140: DestRectl->bottom = min(Rectl1->bottom, Rectl2->bottom);
141:
142: //
143: // If the minimum bottom edge is greater than the maximum top
144: // edge, then the rectanges intersect. Otherwise, they do not
145: // intersect.
146: //
147:
148: if (DestRectl->top < DestRectl->bottom) {
149: return TRUE;
150: }
151: }
152:
153: return FALSE;
154: }
155:
156: /******************************Public*Routine******************************\
157: * DrvpSolidColorFill
158: *
159: * Routine Description:
160: *
161: * This routine fills a rectangle with a solid color.
162: *
163: * Arguments:
164: *
165: * Rectangle - Supplies a pointer to a rectangle.
166: *
167: * FillColor - Supplies the fill color.
168: *
169: *
170: * Return Value:
171: *
172: * None.
173: *
174: \**************************************************************************/
175:
176: VOID DrvpSolidColorFill (
177: IN SURFOBJ *pso,
178: IN PRECTL Rectangle,
179: IN ULONG FillColor)
180:
181: {
182:
183: PUCHAR Destination;
184: ULONG Index;
185: ULONG Length;
186: LONG lDelta = pso->lDelta;
187:
188: //
189: // Compute rectangle fill parameters and fill rectangle with solid color.
190: //
191:
192: Destination = ((PBYTE) pso->pvScan0) + (Rectangle->top * lDelta) + Rectangle->left;
193: Length = Rectangle->right - Rectangle->left;
194: for (Index = 0; Index < (Rectangle->bottom - Rectangle->top); Index += 1) {
195: RtlFillMemory((PVOID)Destination, Length, FillColor);
196: Destination += lDelta;
197: }
198:
199: return;
200: }
201:
202: /******************************Public*Routine******************************\
203: * DrvpEqualRectangle
204: *
205: * This routine compares two rectangles for equality.
206: *
207: \**************************************************************************/
208:
209: BOOL DrvpEqualRectangle (
210: IN RECTL *prcl1,
211: IN RECTL *prcl2)
212:
213: {
214:
215: if ((prcl1->left == prcl2->left) && (prcl1->right == prcl2->right) &&
216: (prcl1->bottom == prcl2->bottom) && (prcl1->top == prcl2->top)) {
217: return TRUE;
218:
219: } else {
220: return FALSE;
221: }
222: }
223:
224: /******************************Public*Routine******************************\
225: * DrvpFillRectangle
226: *
227: * This routine fills a rectangle with clipping.
228: *
229: \**************************************************************************/
230:
231: VOID DrvpFillRectangle (
232: IN SURFOBJ *pso,
233: IN CLIPOBJ *pco,
234: IN RECTL *prcl,
235: IN BRUSHOBJ *pbo)
236:
237: {
238:
239: ENUMRECTLIST ClipEnum;
240: RECTL Region;
241: ULONG Index;
242: BOOL More;
243: ULONG iDComplexity;
244:
245: if (pco) {
246: iDComplexity = pco->iDComplexity;
247:
248: } else {
249: iDComplexity = DC_TRIVIAL;
250: }
251:
252:
253: //
254: // Clip and fill the rectangle with the specified color.
255: //
256:
257: switch(iDComplexity) {
258: case DC_TRIVIAL:
259: DrvpSolidColorFill(pso, prcl, pbo->iSolidColor);
260: return;
261:
262: case DC_RECT:
263: More = FALSE;
264: ClipEnum.c = 1;
265: ClipEnum.arcl[0] = pco->rclBounds;
266: break;
267:
268: case DC_COMPLEX:
269: More = TRUE;
270: CLIPOBJ_cEnumStart(pco,
271: FALSE,
272: CT_RECTANGLES,
273: CD_LEFTWARDS,
274: BB_RECT_LIMIT);
275:
276: break;
277: }
278:
279: //
280: // Do a solid color fill for each nonclipped region.
281: //
282:
283: do {
284:
285: //
286: // If more clip regions is TRUE, then get the next batch of
287: // clipping regions.
288: //
289:
290: if (More != FALSE) {
291: More = CLIPOBJ_bEnum(pco, sizeof(ClipEnum), (PVOID)&ClipEnum);
292: }
293:
294: //
295: // If the clipping is not trival, then do the clipping for the
296: // next region and do the solid fill. Otherwise, do the solid
297: // fill with no clipping.
298: //
299:
300: for (Index = 0; Index < ClipEnum.c; Index += 1) {
301: if (DrvpIntersectRect(&ClipEnum.arcl[Index],
302: prcl,
303: &Region)) {
304: DrvpSolidColorFill(pso, &Region, pbo->iSolidColor);
305: }
306: }
307:
308: } while (More);
309: return;
310: }
311:
312: /******************************Public*Routine******************************\
313: * DrvTextOut
314: *
315: * This routine outputs text to the screen.
316: *
317: * History:
318: * 07-Jul-1992 -by- David N. Cutler [davec]
319: * Wrote it.
320: \**************************************************************************/
321:
322: BOOL DrvTextOut (
323: IN SURFOBJ *pso,
324: IN STROBJ *pstro,
325: IN FONTOBJ *pfo,
326: IN CLIPOBJ *pco,
327: IN RECTL *prclExtra,
328: IN RECTL *prclOpaque,
329: IN BRUSHOBJ *pboFore,
330: IN BRUSHOBJ *pboOpaque,
331: IN POINTL *pptlOrg,
332: IN MIX mix)
333:
334: {
335:
336: ULONG BackGroundColor;
337: PBYTE DrawPoint;
338: FONTINFO FontInformation;
339: ULONG ForeGroundColor;
340: ULONG GlyphCount;
341: PGLYPHPOS GlyphEnd;
342: ULONG GlyphHeight;
343: PGLYPHPOS GlyphList;
344: PDRVP_GLYPHOUT_ROUTINE GlyphOutputRoutine;
345: PGLYPHPOS GlyphStart;
346: ULONG GlyphWidth;
347: LONG GlyphStride;
348: ULONG Index;
349: BOOL More;
350: RECTL OpaqueRectl;
351: LONG OriginX;
352: LONG OriginY;
353: PBYTE pjScreenBase;
354: GLYPHBITS *pgb;
355:
356: //
357: // DrvTextOut will only get called with solid color brushes and
358: // the mix mode being the simplest R2_COPYPEN. The driver must
359: // set a capabilities bit to get called with more complicated
360: // mix brushes.
361: //
362:
363: // ASSERT(pboFore->iSolidColor != 0xffffffff);
364: // ASSERT(pboOpaque->iSolidColor != 0xffffffff);
365: // ASSERT(mix == ((R2_COPYPEN << 8) | R2_COPYPEN));
366:
367: //
368: // If the complexity of the clipping is not trival, then let GDI
369: // process the request.
370: //
371:
372: if (pco->iDComplexity != DC_TRIVIAL) {
373: return(EngTextOut(pso,
374: pstro,
375: pfo,
376: pco,
377: prclExtra,
378: prclOpaque,
379: pboFore,
380: pboOpaque,
381: pptlOrg,
382: mix));
383: }
384:
385: //
386: // The foreground color is used for the text and extra rectangle
387: // if it specified. The background color is used for the opaque
388: // rectangle. If the foreground color is not a solid color brush
389: // or the opaque rectangle is specified and is not a solid color
390: // brush, then let GDI process the request.
391: //
392:
393: DrvpScanLineWidth = pso->lDelta;
394: pjScreenBase = pso->pvScan0;
395:
396: //
397: // Check if the background and foreground can be draw at the same time.
398: //
399:
400: ForeGroundColor = pboFore->iSolidColor;
401: ForeGroundColor |= (ForeGroundColor << 8);
402: ForeGroundColor |= (ForeGroundColor << 16);
403: if (((pstro->flAccel == SO_LTOR) || (pstro->flAccel == SO_RTOL) ||
404: (pstro->flAccel == SO_TTOB) || (pstro->flAccel == SO_BTOT)) &&
405: (prclOpaque != NULL) && (pfo->cxMax <= 32)) {
406:
407: //
408: // The background and the foreground can be draw at the same
409: // time. Generate the drawing color table and draw the text
410: // opaquely.
411: //
412:
413: BackGroundColor = pboOpaque->iSolidColor;
414: BackGroundColor |= (BackGroundColor << 8);
415: BackGroundColor |= (BackGroundColor << 16);
416: for (Index = 0; Index < 16; Index += 1) {
417: DrvpDrawColorTable[Index] =
418: (ForeGroundColor & DrvpColorMask[Index]) |
419: (BackGroundColor & (~DrvpColorMask[Index]));
420: }
421:
422: //
423: // If the top of the opaque rectangle is less than the top of the
424: // background rectangle, then fill the region between the top of
425: // opaque rectangle and the top of the background rectangle and
426: // reduce the size of the opaque rectangle.
427: //
428:
429: OpaqueRectl = *prclOpaque;
430: if (OpaqueRectl.top < pstro->rclBkGround.top) {
431: OpaqueRectl.bottom = pstro->rclBkGround.top;
432: DrvpFillRectangle(pso,pco, &OpaqueRectl, pboOpaque);
433: OpaqueRectl.top = pstro->rclBkGround.top;
434: OpaqueRectl.bottom = prclOpaque->bottom;
435: }
436:
437: //
438: // If the bottom of the opaque rectangle is greater than the bottom
439: // of the background rectangle, then fill the region between the
440: // bottom of the background rectangle and the bottom of the opaque
441: // rectangle and reduce the size of the opaque rectangle.
442: //
443:
444: if (OpaqueRectl.bottom > pstro->rclBkGround.bottom) {
445: OpaqueRectl.top = pstro->rclBkGround.bottom;
446: DrvpFillRectangle(pso, pco, &OpaqueRectl, pboOpaque);
447: OpaqueRectl.top = pstro->rclBkGround.top;
448: OpaqueRectl.bottom = pstro->rclBkGround.bottom;
449: }
450:
451: //
452: // If the left of the opaque rectangle is less than the left of
453: // the background rectangle, then fill the region between the
454: // left of the opaque rectangle and the left of the background
455: // rectangle.
456: //
457:
458: if (OpaqueRectl.left < pstro->rclBkGround.left) {
459: OpaqueRectl.right = pstro->rclBkGround.left;
460: DrvpFillRectangle(pso, pco, &OpaqueRectl, pboOpaque);
461: OpaqueRectl.right = prclOpaque->right;
462: }
463:
464: //
465: // If the right of the opaque rectangle is greater than the right
466: // of the background rectangle, then fill the region between the
467: // right of the opaque rectangle and the right of the background
468: // rectangle.
469: //
470:
471: if (OpaqueRectl.right > pstro->rclBkGround.right) {
472: OpaqueRectl.left = pstro->rclBkGround.right;
473: DrvpFillRectangle(pso, pco, &OpaqueRectl, pboOpaque);
474: }
475:
476: //
477: // If the font is fixed pitch, then optimize the computation of
478: // x and y coordinate values. Otherwise, compute the x and y values
479: // for each glyph.
480: //
481:
482: if (pstro->ulCharInc != 0) {
483:
484: //
485: // The font is fixed pitch. Capture the glyph dimensions and
486: // compute the starting display address.
487: //
488:
489: if (pstro->pgp == NULL) {
490: More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
491:
492: } else {
493: GlyphCount = pstro->cGlyphs;
494: GlyphList = pstro->pgp;
495: More = FALSE;
496: }
497:
498: pgb = GlyphList->pgdf->pgb;
499: GlyphWidth = pgb->sizlBitmap.cx;
500: GlyphHeight = pgb->sizlBitmap.cy;
501: OriginX = GlyphList->ptl.x + pgb->ptlOrigin.x;
502: OriginY = GlyphList->ptl.y + pgb->ptlOrigin.y;
503: DrawPoint = pjScreenBase + ((OriginY * DrvpScanLineWidth) + OriginX);
504:
505: //
506: // Compute the glyph stride.
507: //
508:
509: GlyphStride = pstro->ulCharInc;
510: if ((pstro->flAccel & SO_VERTICAL) != 0) {
511: GlyphStride *= DrvpScanLineWidth;
512: }
513:
514: //
515: // If the direction of drawing is reversed, then the stride is
516: // negative.
517: //
518:
519: if ((pstro->flAccel & SO_REVERSED) != 0) {
520: GlyphStride = - GlyphStride;
521: }
522:
523: //
524: // Output the initial set of glyphs.
525: //
526:
527: GlyphOutputRoutine = DrvpOpaqueTable[(GlyphWidth - 1) >> 2];
528: GlyphEnd = &GlyphList[GlyphCount];
529: GlyphStart = GlyphList;
530: do {
531: pgb = GlyphStart->pgdf->pgb;
532: (GlyphOutputRoutine)(DrawPoint,
533: (PULONG)&pgb->aj[0],
534: GlyphWidth,
535: GlyphHeight);
536:
537: DrawPoint += GlyphStride;
538: GlyphStart += 1;
539: } while (GlyphStart != GlyphEnd);
540:
541: //
542: // Output the subsequent set of glyphs.
543: //
544:
545: while (More) {
546: More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
547: GlyphEnd = &GlyphList[GlyphCount];
548: GlyphStart = GlyphList;
549: do {
550: pgb = GlyphStart->pgdf->pgb;
551: (GlyphOutputRoutine)(DrawPoint,
552: (PULONG)&pgb->aj[0],
553: GlyphWidth,
554: GlyphHeight);
555:
556: DrawPoint += GlyphStride;
557: GlyphStart += 1;
558: } while (GlyphStart != GlyphEnd);
559: }
560:
561: } else {
562:
563: //
564: // The font is not fixed pitch. Compute the x and y values for
565: // each glyph individually.
566: //
567:
568: do {
569: More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
570: GlyphEnd = &GlyphList[GlyphCount];
571: GlyphStart = GlyphList;
572: do {
573: pgb = GlyphStart->pgdf->pgb;
574: OriginX = GlyphStart->ptl.x + pgb->ptlOrigin.x;
575: OriginY = GlyphStart->ptl.y + pgb->ptlOrigin.y;
576: DrawPoint = pjScreenBase +
577: ((OriginY * DrvpScanLineWidth) + OriginX);
578:
579: GlyphWidth = pgb->sizlBitmap.cx;
580: GlyphOutputRoutine = DrvpOpaqueTable[(GlyphWidth - 1) >> 2];
581: (GlyphOutputRoutine)(DrawPoint,
582: (PULONG)&pgb->aj[0],
583: GlyphWidth,
584: pgb->sizlBitmap.cy);
585:
586: GlyphStart += 1;
587: } while(GlyphStart != GlyphEnd);
588: } while(More);
589: }
590:
591: } else {
592:
593: //
594: // The background and the foreground cannot be draw at the same
595: // time. Set the foreground color and fill the background rectangle,
596: // if specified, and then draw the text transparently.
597: //
598:
599: DrvpForeGroundColor = ForeGroundColor;
600: if (prclOpaque != NULL) {
601: DrvpFillRectangle(pso, pco, prclOpaque, pboOpaque);
602: }
603:
604: //
605: // If the font is fixed pitch, then optimize the computation of
606: // x and y coordinate values. Otherwise, compute the x and y values
607: // for each glyph.
608: //
609:
610: if (pstro->ulCharInc != 0) {
611:
612: //
613: // The font is fixed pitch. Capture the glyph dimensions and
614: // compute the starting display address.
615: //
616:
617: if (pstro->pgp == NULL) {
618: More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
619:
620: } else {
621: GlyphCount = pstro->cGlyphs;
622: GlyphList = pstro->pgp;
623: More = FALSE;
624: }
625:
626: pgb = GlyphList->pgdf->pgb;
627: GlyphWidth = pgb->sizlBitmap.cx;
628: GlyphHeight = pgb->sizlBitmap.cy;
629: OriginX = GlyphList->ptl.x + pgb->ptlOrigin.x;
630: OriginY = GlyphList->ptl.y + pgb->ptlOrigin.y;
631: DrawPoint = pjScreenBase + ((OriginY * DrvpScanLineWidth) + OriginX);
632:
633: //
634: // Compute the glyph stride.
635: //
636:
637: GlyphStride = pstro->ulCharInc;
638: if ((pstro->flAccel & SO_VERTICAL) != 0) {
639: GlyphStride *= DrvpScanLineWidth;
640: }
641:
642: //
643: // If the direction of drawing is reversed, then the stride is
644: // negative.
645: //
646:
647: if ((pstro->flAccel & SO_REVERSED) != 0) {
648: GlyphStride = -GlyphStride;
649: }
650:
651: //
652: // Output the initial set of glyphs.
653: //
654:
655: GlyphEnd = &GlyphList[GlyphCount];
656: GlyphStart = GlyphList;
657: do {
658: pgb = GlyphStart->pgdf->pgb;
659: DrvpOutputGlyphTransparent(DrawPoint,
660: &pgb->aj[0],
661: GlyphWidth,
662: GlyphHeight);
663:
664: DrawPoint += GlyphStride;
665: GlyphStart += 1;
666: } while (GlyphStart != GlyphEnd);
667:
668: //
669: // Output the subsequent set of glyphs.
670: //
671:
672: while (More) {
673: More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
674: GlyphEnd = &GlyphList[GlyphCount];
675: GlyphStart = GlyphList;
676: do {
677: pgb = GlyphStart->pgdf->pgb;
678: DrvpOutputGlyphTransparent(DrawPoint,
679: &pgb->aj[0],
680: GlyphWidth,
681: GlyphHeight);
682:
683: DrawPoint += GlyphStride;
684: GlyphStart += 1;
685: } while (GlyphStart != GlyphEnd);
686: }
687:
688: } else {
689:
690: //
691: // The font is not fixed pitch. Compute the x and y values for
692: // each glyph individually.
693: //
694:
695: do {
696: More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
697: GlyphEnd = &GlyphList[GlyphCount];
698: GlyphStart = GlyphList;
699: do {
700: pgb = GlyphStart->pgdf->pgb;
701: OriginX = GlyphStart->ptl.x + pgb->ptlOrigin.x;
702: OriginY = GlyphStart->ptl.y + pgb->ptlOrigin.y;
703: DrawPoint = pjScreenBase +
704: ((OriginY * DrvpScanLineWidth) + OriginX);
705:
706: DrvpOutputGlyphTransparent(DrawPoint,
707: &pgb->aj[0],
708: pgb->sizlBitmap.cx,
709: pgb->sizlBitmap.cy);
710:
711: GlyphStart += 1;
712: } while(GlyphStart != GlyphEnd);
713: } while(More);
714: }
715: }
716:
717: //
718: // Fill the extra rectangles if specified.
719: //
720:
721: if (prclExtra != (PRECTL)NULL) {
722: while (prclExtra->left != prclExtra->right) {
723: DrvpFillRectangle(pso, pco, prclExtra, pboFore);
724: prclExtra += 1;
725: }
726: }
727:
728: return(TRUE);
729: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.