Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1307 lines
42 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: textout.c
  3. *
  4. * Copyright (c) 1992-1995 Microsoft Corporation
  5. *
  6. \**************************************************************************/
  7. #include "precomp.h"
  8. /******************************Public*Routine******************************\
  9. * VOID vClipSolid
  10. *
  11. * Fills the specified rectangles with the specified colour, honouring
  12. * the requested clipping. No more than four rectangles should be passed in.
  13. * Intended for drawing the areas of the opaquing rectangle that extend
  14. * beyond the text box. The rectangles must be in left to right, top to
  15. * bottom order. Assumes there is at least one rectangle in the list.
  16. *
  17. \**************************************************************************/
  18. VOID vClipSolid(
  19. PDEV* ppdev,
  20. LONG crcl,
  21. RECTL* prcl,
  22. ULONG iColor,
  23. CLIPOBJ* pco)
  24. {
  25. BOOL bMore; // Flag for clip enumeration
  26. CLIPENUM ce; // Clip enumeration object
  27. ULONG i;
  28. ULONG j;
  29. RECTL arclTmp[4];
  30. ULONG crclTmp;
  31. RECTL* prclTmp;
  32. RECTL* prclClipTmp;
  33. LONG iLastBottom;
  34. RECTL* prclClip;
  35. RBRUSH_COLOR rbc;
  36. ASSERTDD((crcl > 0) && (crcl <= 4), "Expected 1 to 4 rectangles");
  37. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  38. "Expected a non-null clip object");
  39. rbc.iSolidColor = iColor;
  40. if (pco->iDComplexity == DC_RECT)
  41. {
  42. crcl = cIntersect(&pco->rclBounds, prcl, crcl);
  43. if (crcl != 0)
  44. {
  45. (ppdev->pfnFillSolid)(ppdev, crcl, prcl, 0xf0f0, rbc, NULL);
  46. }
  47. }
  48. else // iDComplexity == DC_COMPLEX
  49. {
  50. // Bottom of last rectangle to fill
  51. iLastBottom = prcl[crcl - 1].bottom;
  52. // Initialize the clip rectangle enumeration to right-down so we can
  53. // take advantage of the rectangle list being right-down:
  54. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  55. // Scan through all the clip rectangles, looking for intersects
  56. // of fill areas with region rectangles:
  57. do {
  58. // Get a batch of region rectangles:
  59. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
  60. // Clip the rect list to each region rect:
  61. for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
  62. {
  63. // Since the rectangles and the region enumeration are both
  64. // right-down, we can zip through the region until we reach
  65. // the first fill rect, and are done when we've passed the
  66. // last fill rect.
  67. if (prclClip->top >= iLastBottom)
  68. {
  69. // Past last fill rectangle; nothing left to do:
  70. return;
  71. }
  72. // Do intersection tests only if we've reached the top of
  73. // the first rectangle to fill:
  74. if (prclClip->bottom > prcl->top)
  75. {
  76. // We've reached the top Y scan of the first rect, so
  77. // it's worth bothering checking for intersection.
  78. // Generate a list of the rects clipped to this region
  79. // rect:
  80. prclTmp = prcl;
  81. prclClipTmp = arclTmp;
  82. for (i = crcl, crclTmp = 0; i-- != 0; prclTmp++)
  83. {
  84. // Intersect fill and clip rectangles
  85. if (bIntersect(prclTmp, prclClip, prclClipTmp))
  86. {
  87. // Add to list if anything's left to draw:
  88. crclTmp++;
  89. prclClipTmp++;
  90. }
  91. }
  92. // Draw the clipped rects
  93. if (crclTmp != 0)
  94. {
  95. (ppdev->pfnFillSolid)(ppdev, crclTmp, &arclTmp[0],
  96. 0xf0f0, rbc, NULL);
  97. }
  98. }
  99. }
  100. } while (bMore);
  101. }
  102. }
  103. /******************************Public*Routine******************************\
  104. * VOID vIoClipText
  105. *
  106. \**************************************************************************/
  107. VOID vIoClipText(
  108. PDEV* ppdev,
  109. STROBJ* pstro,
  110. CLIPOBJ* pco)
  111. {
  112. BYTE* pjIoBase;
  113. BYTE* pjScreen;
  114. BOOL bMoreGlyphs;
  115. ULONG cGlyphOriginal;
  116. ULONG cGlyph;
  117. GLYPHPOS* pgpOriginal;
  118. GLYPHPOS* pgp;
  119. GLYPHBITS* pgb;
  120. POINTL ptlOrigin;
  121. BOOL bMore;
  122. CLIPENUM ce;
  123. RECTL* prclClip;
  124. ULONG ulCharInc;
  125. LONG cxGlyph;
  126. LONG cyGlyph;
  127. LONG xBias;
  128. LONG cx;
  129. LONG cy;
  130. ULONG* pdSrc;
  131. ULONG* pdDst;
  132. LONG cj;
  133. LONG cd;
  134. LONG xLeft;
  135. LONG yTop;
  136. LONG xRight;
  137. LONG yBottom;
  138. LONG lDelta;
  139. LONG i;
  140. BYTE* pjSrc;
  141. ASSERTDD(pco != NULL, "Don't expect NULL clip objects here");
  142. pjIoBase = ppdev->pjIoBase;
  143. pjScreen = ppdev->pjScreen;
  144. do {
  145. if (pstro->pgp != NULL)
  146. {
  147. // There's only the one batch of glyphs, so save ourselves
  148. // a call:
  149. pgpOriginal = pstro->pgp;
  150. cGlyphOriginal = pstro->cGlyphs;
  151. bMoreGlyphs = FALSE;
  152. }
  153. else
  154. {
  155. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  156. }
  157. if (cGlyphOriginal > 0)
  158. {
  159. ulCharInc = pstro->ulCharInc;
  160. if (pco->iDComplexity == DC_RECT)
  161. {
  162. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  163. // DC_RECT, but the last time I checked, those two calls took
  164. // more than 150 instructions to go through GDI. Since
  165. // 'rclBounds' already contains the DC_RECT clip rectangle,
  166. // and since it's such a common case, we'll special case it:
  167. bMore = FALSE;
  168. prclClip = &pco->rclBounds;
  169. ce.c = 1;
  170. goto SingleRectangle;
  171. }
  172. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  173. do {
  174. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  175. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  176. {
  177. SingleRectangle:
  178. pgp = pgpOriginal;
  179. cGlyph = cGlyphOriginal;
  180. pgb = pgp->pgdf->pgb;
  181. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  182. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  183. pdDst = (ULONG*) pjScreen;
  184. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  185. // Loop through all the glyphs for this rectangle:
  186. while (TRUE)
  187. {
  188. cxGlyph = pgb->sizlBitmap.cx;
  189. cyGlyph = pgb->sizlBitmap.cy;
  190. pdSrc = (ULONG*) pgb->aj;
  191. if ((prclClip->left <= ptlOrigin.x) &&
  192. (prclClip->top <= ptlOrigin.y) &&
  193. (prclClip->right >= ptlOrigin.x + cxGlyph) &&
  194. (prclClip->bottom >= ptlOrigin.y + cyGlyph))
  195. {
  196. //-----------------------------------------------------
  197. // Unclipped glyph
  198. IO_DEST_XY(ppdev, pjIoBase, ptlOrigin.x, ptlOrigin.y);
  199. IO_BITMAP_WIDTH(ppdev, pjIoBase, cxGlyph);
  200. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cyGlyph);
  201. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  202. cj = cyGlyph * ((cxGlyph + 7) >> 3);
  203. cd = cj >> 2;
  204. if (cd != 0)
  205. {
  206. do {
  207. WRITE_REGISTER_ULONG(pdDst, *pdSrc);
  208. MEMORY_BARRIER();
  209. pdSrc++;
  210. } while (--cd != 0);
  211. }
  212. // We have to be careful we don't output any more data
  213. // than we're supposed to, otherwise we get garbage on
  214. // the screen:
  215. switch (cj & 3)
  216. {
  217. case 1:
  218. WRITE_REGISTER_UCHAR(pdDst, *(UCHAR*) pdSrc);
  219. MEMORY_BARRIER();
  220. break;
  221. case 2:
  222. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  223. MEMORY_BARRIER();
  224. break;
  225. case 3:
  226. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  227. MEMORY_BARRIER();
  228. WRITE_REGISTER_UCHAR(pdDst, *((UCHAR*) pdSrc + 2));
  229. MEMORY_BARRIER();
  230. break;
  231. }
  232. IO_WAIT_TRANSFER_DONE(ppdev, pjIoBase);
  233. }
  234. else
  235. {
  236. //-----------------------------------------------------
  237. // Clipped glyph
  238. // Find the intersection of the glyph rectangle
  239. // and the clip rectangle:
  240. xLeft = max(prclClip->left, ptlOrigin.x);
  241. yTop = max(prclClip->top, ptlOrigin.y);
  242. xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
  243. yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
  244. // Check for trivial rejection:
  245. if (((cx = xRight - xLeft) > 0) &&
  246. ((cy = yBottom - yTop) > 0))
  247. {
  248. IO_DEST_XY(ppdev, pjIoBase, xLeft, yTop);
  249. IO_BITMAP_WIDTH(ppdev, pjIoBase, cx);
  250. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cy);
  251. xBias = (xLeft - ptlOrigin.x) & 7;
  252. cx += xBias;
  253. IO_SRC_ALIGN(ppdev, pjIoBase, xBias);
  254. lDelta = (cxGlyph + 7) >> 3;
  255. pjSrc = (BYTE*) pdSrc + (yTop - ptlOrigin.y) * lDelta
  256. + ((xLeft - ptlOrigin.x) >> 3);
  257. cj = (cx + 7) >> 3;
  258. lDelta -= cj;
  259. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  260. do {
  261. i = cj;
  262. do {
  263. WRITE_REGISTER_UCHAR((UCHAR*) pdDst, *pjSrc);
  264. MEMORY_BARRIER();
  265. pjSrc++;
  266. } while (--i != 0);
  267. pjSrc += lDelta;
  268. } while (--cy != 0);
  269. // Reset the alignment register in case we have more
  270. // unclipped glyphs in this string:
  271. IO_SRC_ALIGN(ppdev, pjIoBase, 0);
  272. IO_WAIT_TRANSFER_DONE(ppdev, pjIoBase);
  273. }
  274. }
  275. if (--cGlyph == 0)
  276. break;
  277. // Get ready for next glyph:
  278. pgp++;
  279. pgb = pgp->pgdf->pgb;
  280. if (ulCharInc == 0)
  281. {
  282. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  283. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  284. }
  285. else
  286. {
  287. ptlOrigin.x += ulCharInc;
  288. }
  289. }
  290. }
  291. } while (bMore);
  292. }
  293. } while (bMoreGlyphs);
  294. }
  295. /******************************Public*Routine******************************\
  296. * VOID vIoTextOut
  297. *
  298. \**************************************************************************/
  299. VOID vIoTextOut(
  300. PDEV* ppdev,
  301. STROBJ* pstro,
  302. FONTOBJ* pfo,
  303. CLIPOBJ* pco,
  304. RECTL* prclOpaque,
  305. BRUSHOBJ* pboFore,
  306. BRUSHOBJ* pboOpaque)
  307. {
  308. BYTE* pjIoBase;
  309. BOOL bTextPerfectFit;
  310. ULONG cGlyph;
  311. BOOL bMoreGlyphs;
  312. GLYPHPOS* pgp;
  313. GLYPHBITS* pgb;
  314. LONG cxGlyph;
  315. LONG cyGlyph;
  316. ULONG* pdSrc;
  317. ULONG* pdDst;
  318. BYTE* pjScreen;
  319. LONG cj;
  320. LONG cd;
  321. POINTL ptlOrigin;
  322. LONG ulCharInc;
  323. BYTE iDComplexity;
  324. pjIoBase = ppdev->pjIoBase;
  325. pjScreen = ppdev->pjScreen;
  326. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  327. if (prclOpaque != NULL)
  328. {
  329. ////////////////////////////////////////////////////////////
  330. // Opaque Initialization
  331. ////////////////////////////////////////////////////////////
  332. // If we paint the glyphs in 'opaque' mode, we may not actually
  333. // have to draw the opaquing rectangle up-front -- the process
  334. // of laying down all the glyphs will automatically cover all
  335. // of the pixels in the opaquing rectangle.
  336. //
  337. // The condition that must be satisfied is that the text must
  338. // fit 'perfectly' such that the entire background rectangle is
  339. // covered, and none of the glyphs overlap (if the glyphs
  340. // overlap, such as for italics, they have to be drawn in
  341. // transparent mode after the opaquing rectangle is cleared).
  342. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  343. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  344. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  345. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  346. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  347. if (!(bTextPerfectFit) ||
  348. (pstro->rclBkGround.top > prclOpaque->top) ||
  349. (pstro->rclBkGround.left > prclOpaque->left) ||
  350. (pstro->rclBkGround.right < prclOpaque->right) ||
  351. (pstro->rclBkGround.bottom < prclOpaque->bottom))
  352. {
  353. if (iDComplexity == DC_TRIVIAL)
  354. {
  355. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  356. IO_PREG_COLOR_8(ppdev, pjIoBase, pboOpaque->iSolidColor);
  357. IO_CTRL_REG_1(ppdev, pjIoBase, PACKED_PIXEL_VIEW |
  358. BITS_PER_PIX_8 |
  359. ENAB_TRITON_MODE);
  360. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  361. XY_DEST_ADDR);
  362. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  363. PIXELMASK_ONLY |
  364. PLANARMASK_NONE_0XFF |
  365. SRC_IS_PATTERN_REGS);
  366. IO_BITMAP_HEIGHT(ppdev, pjIoBase, prclOpaque->bottom - prclOpaque->top);
  367. IO_BITMAP_WIDTH(ppdev, pjIoBase, prclOpaque->right - prclOpaque->left);
  368. IO_DEST_XY(ppdev, pjIoBase, prclOpaque->left, prclOpaque->top);
  369. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  370. }
  371. else
  372. {
  373. vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
  374. }
  375. }
  376. if (bTextPerfectFit)
  377. {
  378. // If we have already drawn the opaquing rectangle (because
  379. // is was larger than the text rectangle), we could lay down
  380. // the glyphs in 'transparent' mode. But I've found the QVision
  381. // to be a bit faster drawing in opaque mode, so we'll stick
  382. // with that:
  383. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  384. IO_CTRL_REG_1(ppdev, pjIoBase, EXPAND_TO_FG |
  385. BITS_PER_PIX_8 |
  386. ENAB_TRITON_MODE);
  387. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  388. XY_DEST_ADDR);
  389. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  390. PIXELMASK_ONLY |
  391. PLANARMASK_NONE_0XFF |
  392. SRC_IS_CPU_DATA);
  393. IO_FG_COLOR(ppdev, pjIoBase, pboFore->iSolidColor);
  394. IO_BG_COLOR(ppdev, pjIoBase, pboOpaque->iSolidColor);
  395. IO_SRC_ALIGN(ppdev, pjIoBase, 0);
  396. goto SkipTransparentInitialization;
  397. }
  398. }
  399. ////////////////////////////////////////////////////////////
  400. // Transparent Initialization
  401. ////////////////////////////////////////////////////////////
  402. // Initialize the hardware for transparent text:
  403. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  404. IO_CTRL_REG_1(ppdev, pjIoBase, EXPAND_TO_FG |
  405. BITS_PER_PIX_8 |
  406. ENAB_TRITON_MODE);
  407. IO_BLT_CMD_1(ppdev, pjIoBase, XY_SRC_ADDR |
  408. XY_DEST_ADDR);
  409. IO_DATAPATH_CTRL(ppdev, pjIoBase, ROPSELECT_NO_ROPS |
  410. PIXELMASK_AND_SRC_DATA |
  411. PLANARMASK_NONE_0XFF |
  412. SRC_IS_CPU_DATA);
  413. IO_FG_COLOR(ppdev, pjIoBase, pboFore->iSolidColor);
  414. IO_SRC_ALIGN(ppdev, pjIoBase, 0);
  415. SkipTransparentInitialization:
  416. if (iDComplexity == DC_TRIVIAL)
  417. {
  418. do {
  419. if (pstro->pgp != NULL)
  420. {
  421. // There's only the one batch of glyphs, so save ourselves
  422. // a call:
  423. pgp = pstro->pgp;
  424. cGlyph = pstro->cGlyphs;
  425. bMoreGlyphs = FALSE;
  426. }
  427. else
  428. {
  429. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  430. }
  431. if (cGlyph > 0)
  432. {
  433. if (pstro->ulCharInc == 0)
  434. {
  435. ////////////////////////////////////////////////////////////
  436. // Proportional Spacing
  437. pdDst = (ULONG*) pjScreen;
  438. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  439. do {
  440. pgb = pgp->pgdf->pgb;
  441. IO_DEST_XY(ppdev, pjIoBase, pgp->ptl.x + pgb->ptlOrigin.x,
  442. pgp->ptl.y + pgb->ptlOrigin.y);
  443. cxGlyph = pgb->sizlBitmap.cx;
  444. IO_BITMAP_WIDTH(ppdev, pjIoBase, cxGlyph);
  445. cyGlyph = pgb->sizlBitmap.cy;
  446. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cyGlyph);
  447. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  448. pdSrc = (ULONG*) pgb->aj;
  449. cj = cyGlyph * ((cxGlyph + 7) >> 3);
  450. cd = cj >> 2;
  451. if (cd != 0)
  452. {
  453. do {
  454. WRITE_REGISTER_ULONG(pdDst, *pdSrc);
  455. MEMORY_BARRIER();
  456. pdSrc++;
  457. } while (--cd != 0);
  458. }
  459. // We have to be careful we don't output any more data
  460. // than we're supposed to, otherwise we get garbage on
  461. // the screen:
  462. switch (cj & 3)
  463. {
  464. case 1:
  465. WRITE_REGISTER_UCHAR(pdDst, *(UCHAR*) pdSrc);
  466. MEMORY_BARRIER();
  467. break;
  468. case 2:
  469. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  470. MEMORY_BARRIER();
  471. break;
  472. case 3:
  473. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  474. MEMORY_BARRIER();
  475. WRITE_REGISTER_UCHAR(pdDst, *((UCHAR*) pdSrc + 2));
  476. MEMORY_BARRIER();
  477. break;
  478. }
  479. IO_WAIT_TRANSFER_DONE(ppdev, pjIoBase);
  480. } while (pgp++, --cGlyph != 0);
  481. }
  482. else
  483. {
  484. ////////////////////////////////////////////////////////////
  485. // Mono Spacing
  486. ulCharInc = pstro->ulCharInc;
  487. pgb = pgp->pgdf->pgb;
  488. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  489. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  490. pdDst = (ULONG*) pjScreen;
  491. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  492. do {
  493. pgb = pgp->pgdf->pgb;
  494. IO_DEST_XY(ppdev, pjIoBase, ptlOrigin.x, ptlOrigin.y);
  495. ptlOrigin.x += ulCharInc;
  496. cxGlyph = pgb->sizlBitmap.cx;
  497. IO_BITMAP_WIDTH(ppdev, pjIoBase, cxGlyph);
  498. cyGlyph = pgb->sizlBitmap.cy;
  499. IO_BITMAP_HEIGHT(ppdev, pjIoBase, cyGlyph);
  500. IO_BLT_CMD_0(ppdev, pjIoBase, START_BLT);
  501. pdSrc = (ULONG*) pgb->aj;
  502. cj = cyGlyph * ((cxGlyph + 7) >> 3);
  503. cd = cj >> 2;
  504. if (cd != 0)
  505. {
  506. do {
  507. WRITE_REGISTER_ULONG(pdDst, *pdSrc);
  508. MEMORY_BARRIER();
  509. pdSrc++;
  510. } while (--cd != 0);
  511. }
  512. // We have to be careful we don't output any more data
  513. // than we're supposed to, otherwise we get garbage on
  514. // the screen:
  515. switch (cj & 3)
  516. {
  517. case 1:
  518. WRITE_REGISTER_UCHAR(pdDst, *(UCHAR*) pdSrc);
  519. MEMORY_BARRIER();
  520. break;
  521. case 2:
  522. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  523. MEMORY_BARRIER();
  524. break;
  525. case 3:
  526. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  527. MEMORY_BARRIER();
  528. WRITE_REGISTER_UCHAR(pdDst, *((UCHAR*) pdSrc + 2));
  529. MEMORY_BARRIER();
  530. break;
  531. }
  532. IO_WAIT_TRANSFER_DONE(ppdev, pjIoBase);
  533. } while (pgp++, --cGlyph != 0);
  534. }
  535. }
  536. } while (bMoreGlyphs);
  537. }
  538. else
  539. {
  540. // If there's clipping, call off to a function:
  541. vIoClipText(ppdev, pstro, pco);
  542. }
  543. IO_WAIT_FOR_IDLE(ppdev, pjIoBase);
  544. IO_BLT_CONFIG(ppdev, pjIoBase, RESET_BLT);
  545. IO_BLT_CONFIG(ppdev, pjIoBase, BLT_ENABLE);
  546. }
  547. /******************************Public*Routine******************************\
  548. * VOID vMmClipText
  549. *
  550. \**************************************************************************/
  551. VOID vMmClipText(
  552. PDEV* ppdev,
  553. STROBJ* pstro,
  554. CLIPOBJ* pco)
  555. {
  556. BYTE* pjMmBase;
  557. BYTE* pjScreen;
  558. BOOL bMoreGlyphs;
  559. ULONG cGlyphOriginal;
  560. ULONG cGlyph;
  561. GLYPHPOS* pgpOriginal;
  562. GLYPHPOS* pgp;
  563. GLYPHBITS* pgb;
  564. POINTL ptlOrigin;
  565. BOOL bMore;
  566. CLIPENUM ce;
  567. RECTL* prclClip;
  568. ULONG ulCharInc;
  569. LONG cxGlyph;
  570. LONG cyGlyph;
  571. LONG xBias;
  572. LONG cx;
  573. LONG cy;
  574. ULONG* pdSrc;
  575. ULONG* pdDst;
  576. LONG cj;
  577. LONG cd;
  578. LONG xLeft;
  579. LONG yTop;
  580. LONG xRight;
  581. LONG yBottom;
  582. LONG lDelta;
  583. LONG i;
  584. BYTE* pjSrc;
  585. ASSERTDD(pco != NULL, "Don't expect NULL clip objects here");
  586. pjMmBase = ppdev->pjMmBase;
  587. pjScreen = ppdev->pjScreen;
  588. do {
  589. if (pstro->pgp != NULL)
  590. {
  591. // There's only the one batch of glyphs, so save ourselves
  592. // a call:
  593. pgpOriginal = pstro->pgp;
  594. cGlyphOriginal = pstro->cGlyphs;
  595. bMoreGlyphs = FALSE;
  596. }
  597. else
  598. {
  599. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  600. }
  601. if (cGlyphOriginal > 0)
  602. {
  603. ulCharInc = pstro->ulCharInc;
  604. if (pco->iDComplexity == DC_RECT)
  605. {
  606. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  607. // DC_RECT, but the last time I checked, those two calls took
  608. // more than 150 instructions to go through GDI. Since
  609. // 'rclBounds' already contains the DC_RECT clip rectangle,
  610. // and since it's such a common case, we'll special case it:
  611. bMore = FALSE;
  612. prclClip = &pco->rclBounds;
  613. ce.c = 1;
  614. goto SingleRectangle;
  615. }
  616. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  617. do {
  618. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  619. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  620. {
  621. SingleRectangle:
  622. pgp = pgpOriginal;
  623. cGlyph = cGlyphOriginal;
  624. pgb = pgp->pgdf->pgb;
  625. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  626. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  627. pdDst = (ULONG*) pjScreen;
  628. MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
  629. // Loop through all the glyphs for this rectangle:
  630. while (TRUE)
  631. {
  632. cxGlyph = pgb->sizlBitmap.cx;
  633. cyGlyph = pgb->sizlBitmap.cy;
  634. pdSrc = (ULONG*) pgb->aj;
  635. if ((prclClip->left <= ptlOrigin.x) &&
  636. (prclClip->top <= ptlOrigin.y) &&
  637. (prclClip->right >= ptlOrigin.x + cxGlyph) &&
  638. (prclClip->bottom >= ptlOrigin.y + cyGlyph))
  639. {
  640. //-----------------------------------------------------
  641. // Unclipped glyph
  642. MM_DEST_XY(ppdev, pjMmBase, ptlOrigin.x, ptlOrigin.y);
  643. MM_BITMAP_WIDTH(ppdev, pjMmBase, cxGlyph);
  644. MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyGlyph);
  645. MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
  646. cj = cyGlyph * ((cxGlyph + 7) >> 3);
  647. cd = cj >> 2;
  648. if (cd != 0)
  649. {
  650. do {
  651. WRITE_REGISTER_ULONG(pdDst, *pdSrc);
  652. MEMORY_BARRIER();
  653. pdSrc++;
  654. } while (--cd != 0);
  655. }
  656. // We have to be careful we don't output any more data
  657. // than we're supposed to, otherwise we get garbage on
  658. // the screen:
  659. switch (cj & 3)
  660. {
  661. case 1:
  662. WRITE_REGISTER_UCHAR(pdDst, *(UCHAR*) pdSrc);
  663. MEMORY_BARRIER();
  664. break;
  665. case 2:
  666. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  667. MEMORY_BARRIER();
  668. break;
  669. case 3:
  670. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  671. MEMORY_BARRIER();
  672. WRITE_REGISTER_UCHAR(pdDst, *((UCHAR*) pdSrc + 2));
  673. MEMORY_BARRIER();
  674. break;
  675. }
  676. MM_WAIT_TRANSFER_DONE(ppdev, pjMmBase);
  677. }
  678. else
  679. {
  680. //-----------------------------------------------------
  681. // Clipped glyph
  682. // Find the intersection of the glyph rectangle
  683. // and the clip rectangle:
  684. xLeft = max(prclClip->left, ptlOrigin.x);
  685. yTop = max(prclClip->top, ptlOrigin.y);
  686. xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
  687. yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
  688. // Check for trivial rejection:
  689. if (((cx = xRight - xLeft) > 0) &&
  690. ((cy = yBottom - yTop) > 0))
  691. {
  692. MM_DEST_XY(ppdev, pjMmBase, xLeft, yTop);
  693. MM_BITMAP_WIDTH(ppdev, pjMmBase, cx);
  694. MM_BITMAP_HEIGHT(ppdev, pjMmBase, cy);
  695. xBias = (xLeft - ptlOrigin.x) & 7;
  696. cx += xBias;
  697. MM_SRC_ALIGN(ppdev, pjMmBase, xBias);
  698. lDelta = (cxGlyph + 7) >> 3;
  699. pjSrc = (BYTE*) pdSrc + (yTop - ptlOrigin.y) * lDelta
  700. + ((xLeft - ptlOrigin.x) >> 3);
  701. cj = (cx + 7) >> 3;
  702. lDelta -= cj;
  703. MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
  704. do {
  705. i = cj;
  706. do {
  707. WRITE_REGISTER_UCHAR((UCHAR*) pdDst, *pjSrc);
  708. MEMORY_BARRIER();
  709. pjSrc++;
  710. } while (--i != 0);
  711. pjSrc += lDelta;
  712. } while (--cy != 0);
  713. // Reset the alignment register in case we have more
  714. // unclipped glyphs in this string:
  715. MM_SRC_ALIGN(ppdev, pjMmBase, 0);
  716. MM_WAIT_TRANSFER_DONE(ppdev, pjMmBase);
  717. }
  718. }
  719. if (--cGlyph == 0)
  720. break;
  721. // Get ready for next glyph:
  722. pgp++;
  723. pgb = pgp->pgdf->pgb;
  724. if (ulCharInc == 0)
  725. {
  726. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  727. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  728. }
  729. else
  730. {
  731. ptlOrigin.x += ulCharInc;
  732. }
  733. }
  734. }
  735. } while (bMore);
  736. }
  737. } while (bMoreGlyphs);
  738. }
  739. /******************************Public*Routine******************************\
  740. * VOID vMmTextOut
  741. *
  742. \**************************************************************************/
  743. VOID vMmTextOut(
  744. PDEV* ppdev,
  745. STROBJ* pstro,
  746. FONTOBJ* pfo,
  747. CLIPOBJ* pco,
  748. RECTL* prclOpaque,
  749. BRUSHOBJ* pboFore,
  750. BRUSHOBJ* pboOpaque)
  751. {
  752. BYTE* pjMmBase;
  753. BOOL bTextPerfectFit;
  754. ULONG cGlyph;
  755. BOOL bMoreGlyphs;
  756. GLYPHPOS* pgp;
  757. GLYPHBITS* pgb;
  758. LONG cxGlyph;
  759. LONG cyGlyph;
  760. ULONG* pdSrc;
  761. ULONG* pdDst;
  762. BYTE* pjScreen;
  763. LONG cj;
  764. LONG cd;
  765. POINTL ptlOrigin;
  766. LONG ulCharInc;
  767. BYTE iDComplexity;
  768. pjMmBase = ppdev->pjMmBase;
  769. pjScreen = ppdev->pjScreen;
  770. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  771. if (prclOpaque != NULL)
  772. {
  773. ////////////////////////////////////////////////////////////
  774. // Opaque Initialization
  775. ////////////////////////////////////////////////////////////
  776. // If we paint the glyphs in 'opaque' mode, we may not actually
  777. // have to draw the opaquing rectangle up-front -- the process
  778. // of laying down all the glyphs will automatically cover all
  779. // of the pixels in the opaquing rectangle.
  780. //
  781. // The condition that must be satisfied is that the text must
  782. // fit 'perfectly' such that the entire background rectangle is
  783. // covered, and none of the glyphs overlap (if the glyphs
  784. // overlap, such as for italics, they have to be drawn in
  785. // transparent mode after the opaquing rectangle is cleared).
  786. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  787. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  788. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  789. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  790. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  791. if (!(bTextPerfectFit) ||
  792. (pstro->rclBkGround.top > prclOpaque->top) ||
  793. (pstro->rclBkGround.left > prclOpaque->left) ||
  794. (pstro->rclBkGround.right < prclOpaque->right) ||
  795. (pstro->rclBkGround.bottom < prclOpaque->bottom))
  796. {
  797. if (iDComplexity == DC_TRIVIAL)
  798. {
  799. MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
  800. MM_PREG_COLOR_8(ppdev, pjMmBase, pboOpaque->iSolidColor);
  801. MM_CTRL_REG_1(ppdev, pjMmBase, PACKED_PIXEL_VIEW |
  802. BLOCK_WRITE | // Note
  803. BITS_PER_PIX_8 |
  804. ENAB_TRITON_MODE);
  805. MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
  806. XY_DEST_ADDR);
  807. MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
  808. PIXELMASK_ONLY |
  809. PLANARMASK_NONE_0XFF |
  810. SRC_IS_PATTERN_REGS);
  811. MM_BITMAP_HEIGHT(ppdev, pjMmBase, prclOpaque->bottom - prclOpaque->top);
  812. MM_BITMAP_WIDTH(ppdev, pjMmBase, prclOpaque->right - prclOpaque->left);
  813. MM_DEST_XY(ppdev, pjMmBase, prclOpaque->left, prclOpaque->top);
  814. MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
  815. }
  816. else
  817. {
  818. vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
  819. }
  820. }
  821. if (bTextPerfectFit)
  822. {
  823. // If we have already drawn the opaquing rectangle (because
  824. // is was larger than the text rectangle), we could lay down
  825. // the glyphs in 'transparent' mode. But I've found the QVision
  826. // to be a bit faster drawing in opaque mode, so we'll stick
  827. // with that:
  828. MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
  829. MM_CTRL_REG_1(ppdev, pjMmBase, EXPAND_TO_FG |
  830. BITS_PER_PIX_8 |
  831. ENAB_TRITON_MODE);
  832. MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
  833. XY_DEST_ADDR);
  834. MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
  835. PIXELMASK_ONLY |
  836. PLANARMASK_NONE_0XFF |
  837. SRC_IS_CPU_DATA);
  838. MM_FG_COLOR(ppdev, pjMmBase, pboFore->iSolidColor);
  839. MM_BG_COLOR(ppdev, pjMmBase, pboOpaque->iSolidColor);
  840. MM_SRC_ALIGN(ppdev, pjMmBase, 0);
  841. goto SkipTransparentInitialization;
  842. }
  843. }
  844. ////////////////////////////////////////////////////////////
  845. // Transparent Initialization
  846. ////////////////////////////////////////////////////////////
  847. // Initialize the hardware for transparent text:
  848. MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
  849. MM_CTRL_REG_1(ppdev, pjMmBase, EXPAND_TO_FG |
  850. BITS_PER_PIX_8 |
  851. ENAB_TRITON_MODE);
  852. MM_BLT_CMD_1(ppdev, pjMmBase, XY_SRC_ADDR |
  853. XY_DEST_ADDR);
  854. MM_DATAPATH_CTRL(ppdev, pjMmBase, ROPSELECT_NO_ROPS |
  855. PIXELMASK_AND_SRC_DATA |
  856. PLANARMASK_NONE_0XFF |
  857. SRC_IS_CPU_DATA);
  858. MM_FG_COLOR(ppdev, pjMmBase, pboFore->iSolidColor);
  859. MM_SRC_ALIGN(ppdev, pjMmBase, 0);
  860. SkipTransparentInitialization:
  861. if (iDComplexity == DC_TRIVIAL)
  862. {
  863. do {
  864. if (pstro->pgp != NULL)
  865. {
  866. // There's only the one batch of glyphs, so save ourselves
  867. // a call:
  868. pgp = pstro->pgp;
  869. cGlyph = pstro->cGlyphs;
  870. bMoreGlyphs = FALSE;
  871. }
  872. else
  873. {
  874. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  875. }
  876. if (cGlyph > 0)
  877. {
  878. if (pstro->ulCharInc == 0)
  879. {
  880. ////////////////////////////////////////////////////////////
  881. // Proportional Spacing
  882. pdDst = (ULONG*) pjScreen;
  883. MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
  884. do {
  885. pgb = pgp->pgdf->pgb;
  886. MM_DEST_XY(ppdev, pjMmBase, pgp->ptl.x + pgb->ptlOrigin.x,
  887. pgp->ptl.y + pgb->ptlOrigin.y);
  888. cxGlyph = pgb->sizlBitmap.cx;
  889. MM_BITMAP_WIDTH(ppdev, pjMmBase, cxGlyph);
  890. cyGlyph = pgb->sizlBitmap.cy;
  891. MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyGlyph);
  892. MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
  893. pdSrc = (ULONG*) pgb->aj;
  894. cj = cyGlyph * ((cxGlyph + 7) >> 3);
  895. cd = cj >> 2;
  896. if (cd != 0)
  897. {
  898. do {
  899. WRITE_REGISTER_ULONG(pdDst, *pdSrc);
  900. MEMORY_BARRIER();
  901. pdSrc++;
  902. } while (--cd != 0);
  903. }
  904. // We have to be careful we don't output any more data
  905. // than we're supposed to, otherwise we get garbage on
  906. // the screen:
  907. switch (cj & 3)
  908. {
  909. case 1:
  910. WRITE_REGISTER_UCHAR(pdDst, *(UCHAR*) pdSrc);
  911. MEMORY_BARRIER();
  912. break;
  913. case 2:
  914. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  915. MEMORY_BARRIER();
  916. break;
  917. case 3:
  918. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  919. MEMORY_BARRIER();
  920. WRITE_REGISTER_UCHAR(pdDst, *((UCHAR*) pdSrc + 2));
  921. MEMORY_BARRIER();
  922. break;
  923. }
  924. MM_WAIT_TRANSFER_DONE(ppdev, pjMmBase);
  925. } while (pgp++, --cGlyph != 0);
  926. }
  927. else
  928. {
  929. ////////////////////////////////////////////////////////////
  930. // Mono Spacing
  931. ulCharInc = pstro->ulCharInc;
  932. pgb = pgp->pgdf->pgb;
  933. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  934. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  935. pdDst = (ULONG*) pjScreen;
  936. MM_WAIT_FOR_IDLE(ppdev, pjMmBase);
  937. do {
  938. pgb = pgp->pgdf->pgb;
  939. MM_DEST_XY(ppdev, pjMmBase, ptlOrigin.x, ptlOrigin.y);
  940. ptlOrigin.x += ulCharInc;
  941. cxGlyph = pgb->sizlBitmap.cx;
  942. MM_BITMAP_WIDTH(ppdev, pjMmBase, cxGlyph);
  943. cyGlyph = pgb->sizlBitmap.cy;
  944. MM_BITMAP_HEIGHT(ppdev, pjMmBase, cyGlyph);
  945. MM_BLT_CMD_0(ppdev, pjMmBase, START_BLT);
  946. pdSrc = (ULONG*) pgb->aj;
  947. cj = cyGlyph * ((cxGlyph + 7) >> 3);
  948. cd = cj >> 2;
  949. if (cd != 0)
  950. {
  951. do {
  952. WRITE_REGISTER_ULONG(pdDst, *pdSrc);
  953. MEMORY_BARRIER();
  954. pdSrc++;
  955. } while (--cd != 0);
  956. }
  957. // We have to be careful we don't output any more data
  958. // than we're supposed to, otherwise we get garbage on
  959. // the screen:
  960. switch (cj & 3)
  961. {
  962. case 1:
  963. WRITE_REGISTER_UCHAR(pdDst, *(UCHAR*) pdSrc);
  964. MEMORY_BARRIER();
  965. break;
  966. case 2:
  967. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  968. MEMORY_BARRIER();
  969. break;
  970. case 3:
  971. WRITE_REGISTER_USHORT(pdDst, *(USHORT*) pdSrc);
  972. MEMORY_BARRIER();
  973. WRITE_REGISTER_UCHAR(pdDst, *((UCHAR*) pdSrc + 2));
  974. MEMORY_BARRIER();
  975. break;
  976. }
  977. MM_WAIT_TRANSFER_DONE(ppdev, pjMmBase);
  978. } while (pgp++, --cGlyph != 0);
  979. }
  980. }
  981. } while (bMoreGlyphs);
  982. }
  983. else
  984. {
  985. // If there's clipping, call off to a function:
  986. vMmClipText(ppdev, pstro, pco);
  987. }
  988. }
  989. /******************************Public*Routine******************************\
  990. * BOOL DrvTextOut
  991. *
  992. \**************************************************************************/
  993. BOOL DrvTextOut(
  994. SURFOBJ* pso,
  995. STROBJ* pstro,
  996. FONTOBJ* pfo,
  997. CLIPOBJ* pco,
  998. RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
  999. // to fill these extra rectangles (it is used
  1000. // largely for underlines). It's not a big
  1001. // performance win (GDI will call our DrvBitBlt
  1002. // to draw the extra rectangles).
  1003. RECTL* prclOpaque,
  1004. BRUSHOBJ* pboFore,
  1005. BRUSHOBJ* pboOpaque,
  1006. POINTL* pptlBrush,
  1007. MIX mix)
  1008. {
  1009. PDEV* ppdev;
  1010. DSURF* pdsurf;
  1011. OH* poh;
  1012. pdsurf = (DSURF*) pso->dhsurf;
  1013. if (pdsurf->dt != DT_DIB)
  1014. {
  1015. poh = pdsurf->poh;
  1016. ppdev = (PDEV*) pso->dhpdev;
  1017. ppdev->xOffset = poh->x;
  1018. ppdev->yOffset = poh->y;
  1019. // The DDI spec says we'll only ever get foreground and background
  1020. // mixes of R2_COPYPEN:
  1021. ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
  1022. ppdev->pfnTextOut(ppdev, pstro, pfo, pco, prclOpaque, pboFore, pboOpaque);
  1023. }
  1024. else
  1025. {
  1026. // We're drawing to a DFB we've converted to a DIB, so just call GDI
  1027. // to handle it:
  1028. return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra, prclOpaque,
  1029. pboFore, pboOpaque, pptlBrush, mix));
  1030. }
  1031. return(TRUE);
  1032. }
  1033. /******************************Public*Routine******************************\
  1034. * VOID DrvDestroyFont
  1035. *
  1036. * We're being notified that the given font is being deallocated; clean up
  1037. * anything we've stashed in the 'pvConsumer' field of the 'pfo'.
  1038. *
  1039. \**************************************************************************/
  1040. VOID DrvDestroyFont(
  1041. FONTOBJ* pfo)
  1042. {
  1043. // !!!
  1044. // This call isn't hooked, so GDI will never call it.
  1045. //
  1046. // This merely exists as a stub function for the sample multi-screen
  1047. // support, so that MulDestroyFont can illustrate how multiple screen
  1048. // text supports when the driver caches glyphs. If this driver did
  1049. // glyph caching, we might have used the 'pvConsumer' field of the
  1050. // 'pfo', which we would have to clean up.
  1051. }
  1052. /******************************Public*Routine******************************\
  1053. * BOOL bEnableText
  1054. *
  1055. * Performs the necessary setup for the text drawing subcomponent.
  1056. *
  1057. \**************************************************************************/
  1058. BOOL bEnableText(
  1059. PDEV* ppdev)
  1060. {
  1061. // Our text algorithms require no initialization. If we were to
  1062. // do glyph caching, we would probably want to allocate off-screen
  1063. // memory and do a bunch of other stuff here.
  1064. return(TRUE);
  1065. }
  1066. /******************************Public*Routine******************************\
  1067. * VOID vDisableText
  1068. *
  1069. * Performs the necessary clean-up for the text drawing subcomponent.
  1070. *
  1071. \**************************************************************************/
  1072. VOID vDisableText(PDEV* ppdev)
  1073. {
  1074. // Here we free any stuff allocated in 'bEnableText'.
  1075. }
  1076. /******************************Public*Routine******************************\
  1077. * VOID vAssertModeText
  1078. *
  1079. * Disables or re-enables the text drawing subcomponent in preparation for
  1080. * full-screen entry/exit.
  1081. *
  1082. \**************************************************************************/
  1083. VOID vAssertModeText(
  1084. PDEV* ppdev,
  1085. BOOL bEnable)
  1086. {
  1087. // If we were to do off-screen glyph caching, we would probably want
  1088. // to invalidate our cache here, because it will get destroyed when
  1089. // we switch to full-screen.
  1090. }