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.

845 lines
28 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: textout.c
  3. *
  4. * On every TextOut, GDI provides an array of 'GLYPHPOS' structures
  5. * for every glyph to be drawn. Each GLYPHPOS structure contains a
  6. * glyph handle and a pointer to a monochrome bitmap that describes
  7. * the glyph. (Note that unlike Windows 3.1, which provides a column-
  8. * major glyph bitmap, Windows NT always provides a row-major glyph
  9. * bitmap.) As such, there are three basic methods for drawing text
  10. * with hardware acceleration:
  11. *
  12. * 1) Glyph caching -- Glyph bitmaps are cached by the accelerator
  13. * (probably in off-screen memory), and text is drawn by
  14. * referring the hardware to the cached glyph locations.
  15. *
  16. * 2) Glyph expansion -- Each individual glyph is color-expanded
  17. * directly to the screen from the monochrome glyph bitmap
  18. * supplied by GDI.
  19. *
  20. * 3) Buffer expansion -- The CPU is used to draw all the glyphs into
  21. * a 1bpp monochrome bitmap, and the hardware is then used
  22. * to color-expand the result.
  23. *
  24. * The fastest method depends on a number of variables, such as the
  25. * color expansion speed, bus speed, CPU speed, average glyph size,
  26. * and average string length.
  27. *
  28. * Glyph expansion is typically faster than buffer expansion for very
  29. * large glyphs, even on the ISA bus, because less copying by the CPU
  30. * needs to be done. Unfortunately, large glyphs are pretty rare.
  31. *
  32. * An advantange of the buffer expansion method is that opaque text will
  33. * never flash -- the other two methods typically need to draw the
  34. * opaquing rectangle before laying down the glyphs, which may cause
  35. * a flash if the raster is caught at the wrong time.
  36. *
  37. * This driver implements glyph expansion and buffer expansion --
  38. * methods 2) and 3). Depending on the hardware capabilities at
  39. * run-time, we'll use whichever one will be faster.
  40. *
  41. * Copyright (c) 1992-1995 Microsoft Corporation
  42. *
  43. \**************************************************************************/
  44. #include "precomp.h"
  45. POINTL gptlZero = { 0, 0 }; // Specifies that the origin of the
  46. // temporary buffer given to the 1bpp
  47. // transfer routine for fasttext is
  48. // at (0, 0)
  49. #define FIFTEEN_BITS ((1 << 15)-1)
  50. /******************************Public*Routine******************************\
  51. * VOID vClipSolid
  52. *
  53. * Fills the specified rectangles with the specified color, honoring
  54. * the requested clipping. No more than four rectangles should be passed in.
  55. * Intended for drawing the areas of the opaquing rectangle that extend
  56. * beyond the text box. The rectangles must be in left to right, top to
  57. * bottom order. Assumes there is at least one rectangle in the list.
  58. *
  59. \**************************************************************************/
  60. VOID vClipSolid(
  61. PDEV* ppdev,
  62. LONG crcl,
  63. RECTL* prcl,
  64. ULONG iColor,
  65. CLIPOBJ* pco)
  66. {
  67. BOOL bMore; // Flag for clip enumeration
  68. CLIPENUM ce; // Clip enumeration object
  69. ULONG i;
  70. ULONG j;
  71. RECTL arclTmp[4];
  72. ULONG crclTmp;
  73. RECTL* prclTmp;
  74. RECTL* prclClipTmp;
  75. LONG iLastBottom;
  76. RECTL* prclClip;
  77. RBRUSH_COLOR rbc;
  78. ASSERTDD((crcl > 0) && (crcl <= 4), "Expected 1 to 4 rectangles");
  79. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  80. "Expected a non-null clip object");
  81. rbc.iSolidColor = iColor;
  82. if (pco->iDComplexity == DC_RECT)
  83. {
  84. crcl = cIntersect(&pco->rclBounds, prcl, crcl);
  85. if (crcl != 0)
  86. {
  87. (ppdev->pfnFillSolid)(ppdev, crcl, prcl, R4_PATCOPY,
  88. rbc, NULL);
  89. }
  90. }
  91. else // iDComplexity == DC_COMPLEX
  92. {
  93. // Bottom of last rectangle to fill
  94. iLastBottom = prcl[crcl - 1].bottom;
  95. // Initialize the clip rectangle enumeration to right-down so we can
  96. // take advantage of the rectangle list being right-down:
  97. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  98. // Scan through all the clip rectangles, looking for intersects
  99. // of fill areas with region rectangles:
  100. do {
  101. // Get a batch of region rectangles:
  102. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
  103. // Clip the rect list to each region rect:
  104. for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
  105. {
  106. // Since the rectangles and the region enumeration are both
  107. // right-down, we can zip through the region until we reach
  108. // the first fill rect, and are done when we've passed the
  109. // last fill rect.
  110. if (prclClip->top >= iLastBottom)
  111. {
  112. // Past last fill rectangle; nothing left to do:
  113. return;
  114. }
  115. // Do intersection tests only if we've reached the top of
  116. // the first rectangle to fill:
  117. if (prclClip->bottom > prcl->top)
  118. {
  119. // We've reached the top Y scan of the first rect, so
  120. // it's worth bothering checking for intersection.
  121. // Generate a list of the rects clipped to this region
  122. // rect:
  123. prclTmp = prcl;
  124. prclClipTmp = arclTmp;
  125. for (i = crcl, crclTmp = 0; i-- != 0; prclTmp++)
  126. {
  127. // Intersect fill and clip rectangles
  128. if (bIntersect(prclTmp, prclClip, prclClipTmp))
  129. {
  130. // Add to list if anything's left to draw:
  131. crclTmp++;
  132. prclClipTmp++;
  133. }
  134. }
  135. // Draw the clipped rects
  136. if (crclTmp != 0)
  137. {
  138. (ppdev->pfnFillSolid)(ppdev, crclTmp, &arclTmp[0],
  139. R4_PATCOPY, rbc, NULL);
  140. }
  141. }
  142. }
  143. } while (bMore);
  144. }
  145. }
  146. BOOL bVerifyStrObj(STROBJ* pstro)
  147. {
  148. BOOL bMoreGlyphs;
  149. LONG cGlyph;
  150. GLYPHPOS * pgp;
  151. LONG iGlyph = 0;
  152. RECTL * prclDraw;
  153. GLYPHPOS * pgpTmp;
  154. POINTL ptlPlace;
  155. do
  156. {
  157. // Get the next batch of glyphs:
  158. if (pstro->pgp != NULL)
  159. {
  160. // There's only the one batch of glyphs, so save ourselves
  161. // a call:
  162. pgp = pstro->pgp;
  163. cGlyph = pstro->cGlyphs;
  164. bMoreGlyphs = FALSE;
  165. }
  166. else
  167. {
  168. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  169. }
  170. prclDraw = &pstro->rclBkGround;
  171. pgpTmp = pgp;
  172. ptlPlace = pgpTmp->ptl;
  173. while (cGlyph)
  174. {
  175. if (((ptlPlace.x + pgpTmp->pgdf->pgb->ptlOrigin.x + pgpTmp->pgdf->pgb->sizlBitmap.cx) > (prclDraw->right)) ||
  176. ((ptlPlace.x + pgpTmp->pgdf->pgb->ptlOrigin.x) < (prclDraw->left)) ||
  177. ((ptlPlace.y + pgpTmp->pgdf->pgb->ptlOrigin.y + pgpTmp->pgdf->pgb->sizlBitmap.cy) > (prclDraw->bottom)) ||
  178. ((ptlPlace.y + pgpTmp->pgdf->pgb->ptlOrigin.y) < (prclDraw->top))
  179. )
  180. {
  181. DISPDBG((0,"------------------------------------------------------------"));
  182. DISPDBG((0,"Glyph %d extends beyond pstro->rclBkGround", iGlyph));
  183. DISPDBG((0,"\tpstro->rclBkGround (%d,%d,%d,%d)",
  184. pstro->rclBkGround.left,
  185. pstro->rclBkGround.top,
  186. pstro->rclBkGround.right,
  187. pstro->rclBkGround.bottom));
  188. DISPDBG((0,"\teffective glyph rect (%d,%d,%d,%d)",
  189. (ptlPlace.x + pgpTmp->pgdf->pgb->ptlOrigin.x),
  190. (ptlPlace.y + pgpTmp->pgdf->pgb->ptlOrigin.y),
  191. (ptlPlace.x + pgpTmp->pgdf->pgb->ptlOrigin.x + pgpTmp->pgdf->pgb->sizlBitmap.cx),
  192. (ptlPlace.y + pgpTmp->pgdf->pgb->ptlOrigin.y + pgpTmp->pgdf->pgb->sizlBitmap.cy)));
  193. DISPDBG((0,"\tglyph pos (%d,%d)",ptlPlace.x,ptlPlace.y));
  194. DISPDBG((0,"\tglyph origin (%d,%d)",
  195. pgpTmp->pgdf->pgb->ptlOrigin.x,
  196. pgpTmp->pgdf->pgb->ptlOrigin.y));
  197. DISPDBG((0,"\tglyph sizl (%d,%d)",
  198. pgpTmp->pgdf->pgb->sizlBitmap.cx,
  199. pgpTmp->pgdf->pgb->sizlBitmap.cy));
  200. DISPDBG((0,"------------------------------------------------------------"));
  201. RIP("time to call the font guys...");
  202. return(FALSE);
  203. }
  204. cGlyph--;
  205. iGlyph++;
  206. pgpTmp++;
  207. if (pstro->ulCharInc == 0)
  208. {
  209. ptlPlace = pgpTmp->ptl;
  210. }
  211. else
  212. {
  213. ptlPlace.x += pstro->ulCharInc;
  214. }
  215. }
  216. } while (bMoreGlyphs);
  217. return(TRUE);
  218. }
  219. /******************************Public*Routine******************************\
  220. * BOOL bBufferExpansion
  221. *
  222. * Outputs text using the 'buffer expansion' method. The CPU draws to a
  223. * 1bpp buffer, and the result is color-expanded to the screen using the
  224. * hardware.
  225. *
  226. * Note that this is x86 only ('vFastText', which draws the glyphs to the
  227. * 1bpp buffer, is writen in Asm).
  228. *
  229. * If you're just getting your driver working, this is the fastest way to
  230. * bring up working accelerated text. All you have to do is write the
  231. * 'Xfer1bpp' function that's also used by the blt code. This
  232. * 'bBufferExpansion' routine shouldn't need to be modified at all.
  233. *
  234. \**************************************************************************/
  235. #if defined(i386)
  236. BOOL bBufferExpansion(
  237. PDEV* ppdev,
  238. STROBJ* pstro,
  239. CLIPOBJ* pco,
  240. RECTL* prclExtra,
  241. RECTL* prclOpaque,
  242. BRUSHOBJ* pboFore,
  243. BRUSHOBJ* pboOpaque)
  244. {
  245. BYTE jClip;
  246. BOOL bMore; // Flag for clip enumeration
  247. GLYPHPOS* pgp; // Points to the first glyph
  248. BOOL bMoreGlyphs; // Glyph enumeration flag
  249. ULONG cGlyph; // # of glyphs in one batch
  250. RECTL arclTmp[4]; // Temporary storage for portions
  251. // of opaquing rectangle
  252. RECTL* prclClip; // Points to list of clip rectangles
  253. RECTL* prclDraw; // Actual text to be drawn
  254. RECTL rclDraw;
  255. ULONG crcl; // Temporary rectangle count
  256. ULONG ulBufferBytes;
  257. ULONG ulBufferHeight;
  258. BOOL bTextPerfectFit;
  259. ULONG flDraw;
  260. BOOL bTmpAlloc;
  261. SURFOBJ so;
  262. CLIPENUM ce;
  263. RBRUSH_COLOR rbc;
  264. ROP4 rop4MonoExpand; // Dictates whether opaque or
  265. // transparent text
  266. XLATEOBJ xlo; // Temporary for passing colors
  267. XLATECOLORS xlc; // Temporary for keeping colors
  268. jClip = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  269. // The foreground color will always be solid:
  270. xlc.iForeColor = pboFore->iSolidColor;
  271. ASSERTDD(xlc.iForeColor != -1, "Expected solid foreground color");
  272. // See if the temporary buffer is big enough for the text; if
  273. // not, try to allocate enough memory. We round up to the
  274. // nearest dword multiple:
  275. so.lDelta = ((((pstro->rclBkGround.right + 31) & ~31) -
  276. (pstro->rclBkGround.left & ~31)) >> 3);
  277. ulBufferHeight = pstro->rclBkGround.bottom - pstro->rclBkGround.top;
  278. ulBufferBytes = so.lDelta * ulBufferHeight;
  279. if (((ULONG)so.lDelta > FIFTEEN_BITS) ||
  280. (ulBufferHeight > FIFTEEN_BITS))
  281. {
  282. // the math will have overflowed
  283. return(FALSE);
  284. }
  285. // Use our temporary buffer if it's big enough, otherwise
  286. // allocate a buffer on the fly:
  287. if (ulBufferBytes >= TMP_BUFFER_SIZE)
  288. {
  289. // The textout is so big that I doubt this allocation will
  290. // cost a significant amount in performance:
  291. bTmpAlloc = TRUE;
  292. so.pvScan0 = EngAllocUserMem(ulBufferBytes, ALLOC_TAG);
  293. if (so.pvScan0 == NULL)
  294. return(FALSE);
  295. }
  296. else
  297. {
  298. bTmpAlloc = FALSE;
  299. so.pvScan0 = ppdev->pvTmpBuffer;
  300. }
  301. // Set fixed pitch, overlap, and top and bottom 'y' alignment
  302. // flags:
  303. if (!(pstro->flAccel & SO_HORIZONTAL) ||
  304. (pstro->flAccel & SO_REVERSED))
  305. {
  306. flDraw = 0;
  307. }
  308. else
  309. {
  310. flDraw = ((pstro->ulCharInc != 0) ? 0x01 : 0) |
  311. (((pstro->flAccel & (SO_ZERO_BEARINGS |
  312. SO_FLAG_DEFAULT_PLACEMENT)) !=
  313. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT))
  314. ? 0x02 : 0) |
  315. (((pstro->flAccel & (SO_ZERO_BEARINGS |
  316. SO_FLAG_DEFAULT_PLACEMENT |
  317. SO_MAXEXT_EQUAL_BM_SIDE)) ==
  318. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  319. SO_MAXEXT_EQUAL_BM_SIDE)) ? 0x04 : 0);
  320. }
  321. // If there's an opaque rectangle, we'll do as much opaquing
  322. // as possible as we do the text. If the opaque rectangle is
  323. // larger than the text rectangle, then we'll do the fringe
  324. // areas right now, and the text and associated background
  325. // areas together later:
  326. rop4MonoExpand = R4_XPAR_EXPAND;
  327. DISPDBG((11,"[%d] rop4MonoExpand(%04x)", __LINE__, rop4MonoExpand));
  328. if (prclOpaque != NULL)
  329. {
  330. rop4MonoExpand = R4_SRCCOPY;
  331. DISPDBG((11,"[%d] rop4MonoExpand(%04x)", __LINE__, rop4MonoExpand));
  332. // Since we didn't set GCAPS_ARBRUSHOPAQUE (yes, it's
  333. // missing a 'b'), we don't have to worry about getting
  334. // anything other than a solid opaquing brush. I wouldn't
  335. // recommend handling it anyway, since I'll bet it would
  336. // break quite a few applications:
  337. xlc.iBackColor = pboOpaque->iSolidColor;
  338. ASSERTDD(xlc.iBackColor != -1, "Expected solid background color");
  339. // See if we have fringe areas to do. If so, build a list of
  340. // rectangles to fill, in right-down order:
  341. crcl = 0;
  342. // Top fragment:
  343. if (pstro->rclBkGround.top > prclOpaque->top)
  344. {
  345. arclTmp[crcl].top = prclOpaque->top;
  346. arclTmp[crcl].left = prclOpaque->left;
  347. arclTmp[crcl].right = prclOpaque->right;
  348. arclTmp[crcl++].bottom = pstro->rclBkGround.top;
  349. }
  350. // Left fragment:
  351. if (pstro->rclBkGround.left > prclOpaque->left)
  352. {
  353. arclTmp[crcl].top = pstro->rclBkGround.top;
  354. arclTmp[crcl].left = prclOpaque->left;
  355. arclTmp[crcl].right = pstro->rclBkGround.left;
  356. arclTmp[crcl++].bottom = pstro->rclBkGround.bottom;
  357. }
  358. // Right fragment:
  359. if (pstro->rclBkGround.right < prclOpaque->right)
  360. {
  361. arclTmp[crcl].top = pstro->rclBkGround.top;
  362. arclTmp[crcl].right = prclOpaque->right;
  363. arclTmp[crcl].left = pstro->rclBkGround.right;
  364. arclTmp[crcl++].bottom = pstro->rclBkGround.bottom;
  365. }
  366. // Bottom fragment:
  367. if (pstro->rclBkGround.bottom < prclOpaque->bottom)
  368. {
  369. arclTmp[crcl].bottom = prclOpaque->bottom;
  370. arclTmp[crcl].left = prclOpaque->left;
  371. arclTmp[crcl].right = prclOpaque->right;
  372. arclTmp[crcl++].top = pstro->rclBkGround.bottom;
  373. }
  374. // Fill any fringe rectangles we found:
  375. if (crcl != 0)
  376. {
  377. if (jClip == DC_TRIVIAL)
  378. {
  379. rbc.iSolidColor = xlc.iBackColor;
  380. (ppdev->pfnFillSolid)(ppdev, crcl, arclTmp, R4_PATCOPY, rbc, NULL);
  381. }
  382. else
  383. {
  384. vClipSolid(ppdev, crcl, arclTmp, xlc.iBackColor, pco);
  385. }
  386. }
  387. }
  388. // We're done with separate opaquing; any further opaquing will
  389. // happen as part of the text drawing.
  390. // Clear the buffer if the text isn't going to set every bit:
  391. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  392. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  393. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  394. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  395. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  396. if (!bTextPerfectFit)
  397. {
  398. // Note that we already rounded up to a dword multiple size.
  399. vClearMemDword((ULONG*) so.pvScan0, ulBufferBytes >> 2);
  400. }
  401. // Fake up the translate object that will provide the 1bpp
  402. // transfer routine the foreground and background colors:
  403. xlo.pulXlate = (ULONG*) &xlc;
  404. // Draw the text into the temp buffer, and thence to the screen:
  405. #if DBG
  406. if (!bVerifyStrObj(pstro))
  407. {
  408. return FALSE;
  409. }
  410. STROBJ_vEnumStart(pstro);
  411. #endif
  412. do
  413. {
  414. // Get the next batch of glyphs:
  415. if (pstro->pgp != NULL)
  416. {
  417. // There's only the one batch of glyphs, so save ourselves
  418. // a call:
  419. pgp = pstro->pgp;
  420. cGlyph = pstro->cGlyphs;
  421. bMoreGlyphs = FALSE;
  422. }
  423. else
  424. {
  425. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  426. }
  427. // LATER: remove double clip intersection from ASM code
  428. if (cGlyph)
  429. {
  430. prclClip = NULL;
  431. prclDraw = &pstro->rclBkGround;
  432. if (jClip == DC_TRIVIAL)
  433. {
  434. Output_Text:
  435. vFastText(pgp,
  436. cGlyph,
  437. so.pvScan0,
  438. so.lDelta,
  439. pstro->ulCharInc,
  440. &pstro->rclBkGround,
  441. prclOpaque,
  442. flDraw,
  443. prclClip,
  444. prclExtra);
  445. if (!bMoreGlyphs)
  446. {
  447. DISPDBG((11,"[%d] rop4MonoExpand(%04x)", __LINE__, rop4MonoExpand));
  448. (ppdev->pfnXfer1bpp)(ppdev,
  449. 1,
  450. prclDraw,
  451. rop4MonoExpand,
  452. &so,
  453. &gptlZero,
  454. &pstro->rclBkGround,
  455. &xlo);
  456. }
  457. }
  458. else if (jClip == DC_RECT)
  459. {
  460. if (bIntersect(&pco->rclBounds, &pstro->rclBkGround,
  461. &rclDraw))
  462. {
  463. DISPDBG((11,"text was DC_RECT clipping"));
  464. arclTmp[0] = pco->rclBounds;
  465. arclTmp[1].bottom = 0; // Terminate list
  466. prclClip = &arclTmp[0];
  467. prclDraw = &rclDraw;
  468. // Save some code size by jumping to the common
  469. // functions calls:
  470. goto Output_Text;
  471. }
  472. }
  473. else // jClip == DC_COMPLEX
  474. {
  475. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES,
  476. CD_ANY, 0);
  477. do
  478. {
  479. bMore = CLIPOBJ_bEnum(pco,
  480. sizeof(ce) - sizeof(RECTL),
  481. (ULONG*) &ce);
  482. ce.c = cIntersect(&pstro->rclBkGround,
  483. ce.arcl, ce.c);
  484. if (ce.c != 0)
  485. {
  486. ce.arcl[ce.c].bottom = 0; // Terminate list
  487. vFastText(pgp,
  488. cGlyph,
  489. so.pvScan0,
  490. so.lDelta,
  491. pstro->ulCharInc,
  492. &pstro->rclBkGround,
  493. prclOpaque,
  494. flDraw,
  495. &ce.arcl[0],
  496. prclExtra);
  497. if (!bMoreGlyphs)
  498. {
  499. DISPDBG((11,"[%d] rop4MonoExpand(%04x)", __LINE__, rop4MonoExpand));
  500. (ppdev->pfnXfer1bpp)(ppdev,
  501. ce.c,
  502. &ce.arcl[0],
  503. rop4MonoExpand,
  504. &so,
  505. &gptlZero,
  506. &pstro->rclBkGround,
  507. &xlo);
  508. }
  509. }
  510. } while (bMore);
  511. break;
  512. }
  513. }
  514. } while (bMoreGlyphs);
  515. // Free up any memory we allocated for the temp buffer:
  516. if (bTmpAlloc)
  517. {
  518. EngFreeUserMem(so.pvScan0);
  519. }
  520. return(TRUE);
  521. }
  522. #endif // defined(i386)
  523. /******************************Public*Routine******************************\
  524. * BOOL DrvTextOut
  525. *
  526. * If it's the fastest method, outputs text using the 'glyph expansion'
  527. * method. Each individual glyph is color-expanded directly to the
  528. * screen from the monochrome glyph bitmap supplied by GDI.
  529. *
  530. * If it's not the fastest method, calls the routine that implements the
  531. * 'buffer expansion' method.
  532. *
  533. \**************************************************************************/
  534. BOOL DrvTextOut(
  535. SURFOBJ* pso,
  536. STROBJ* pstro,
  537. FONTOBJ* pfo,
  538. CLIPOBJ* pco,
  539. RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
  540. // to fill these extra rectangles (it is used
  541. // largely for underlines). It's not a big
  542. // performance win (GDI will call our DrvBitBlt
  543. // to draw the extra rectangles).
  544. RECTL* prclOpaque,
  545. BRUSHOBJ* pboFore,
  546. BRUSHOBJ* pboOpaque,
  547. POINTL* pptlBrush,
  548. MIX mix)
  549. {
  550. PDEV* ppdev;
  551. DSURF* pdsurf;
  552. OH* poh;
  553. BOOL bTextPerfectFit;
  554. ULONG cGlyph;
  555. BOOL bMoreGlyphs;
  556. GLYPHPOS* pgp;
  557. GLYPHBITS* pgb;
  558. BYTE* pjGlyph;
  559. LONG cyGlyph;
  560. POINTL ptlOrigin;
  561. LONG ulCharInc;
  562. BYTE iDComplexity;
  563. LONG lDelta;
  564. LONG cw;
  565. // The DDI spec says we'll only ever get foreground and background
  566. // mixes of R2_COPYPEN:
  567. ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
  568. // Pass the surface off to GDI if it's a device bitmap that we've
  569. // converted to a DIB:
  570. pdsurf = (DSURF*) pso->dhsurf;
  571. if (pdsurf->dt != DT_DIB)
  572. {
  573. // We'll be drawing to the screen or an off-screen DFB; copy the
  574. // surface's offset now so that we won't need to refer to the DSURF
  575. // again:
  576. poh = pdsurf->poh;
  577. ppdev = (PDEV*) pso->dhpdev;
  578. ppdev->xOffset = poh->x;
  579. ppdev->yOffset = poh->y;
  580. ppdev->xyOffset = (poh->x * ppdev->cBpp) +
  581. (poh->y * ppdev->lDelta);
  582. if (ppdev->bAutoBanking)
  583. {
  584. PVOID pvScan0;
  585. BOOL bRet;
  586. BYTE* pjBase = ppdev->pjBase;
  587. pvScan0 = ppdev->psoFrameBuffer->pvScan0;
  588. (BYTE*)ppdev->psoFrameBuffer->pvScan0 += ppdev->xyOffset;
  589. WAIT_FOR_IDLE_ACL(ppdev, pjBase);
  590. bRet = EngTextOut(ppdev->psoFrameBuffer, pstro, pfo, pco, prclExtra,
  591. prclOpaque, pboFore, pboOpaque, pptlBrush, mix);
  592. ppdev->psoFrameBuffer->pvScan0 = pvScan0;
  593. return(bRet);
  594. }
  595. {
  596. #if defined(i386)
  597. {
  598. // We don't want to use the 'glyph expansion' method, so use
  599. // the 'buffer expansion' method instead:
  600. return(bBufferExpansion(ppdev, pstro, pco, prclExtra, prclOpaque,
  601. pboFore, pboOpaque));
  602. }
  603. #else
  604. {
  605. BANK bnk;
  606. BOOL b;
  607. RECTL rclDraw;
  608. RECTL *prclDst = &pco->rclBounds;
  609. // The bank manager requires that the 'draw' rectangle be
  610. // well-ordered:
  611. rclDraw = *prclDst;
  612. if (rclDraw.left > rclDraw.right)
  613. {
  614. rclDraw.left = prclDst->right;
  615. rclDraw.right = prclDst->left;
  616. }
  617. if (rclDraw.top > rclDraw.bottom)
  618. {
  619. rclDraw.top = prclDst->bottom;
  620. rclDraw.bottom = prclDst->top;
  621. }
  622. vBankStart(ppdev, &rclDraw, pco, &bnk);
  623. b = TRUE;
  624. do {
  625. b &= EngTextOut(bnk.pso,
  626. pstro,
  627. pfo,
  628. bnk.pco,
  629. prclExtra,
  630. prclOpaque,
  631. pboFore,
  632. pboOpaque,
  633. pptlBrush,
  634. mix);
  635. } while (bBankEnum(&bnk));
  636. return(b);
  637. }
  638. #endif
  639. }
  640. }
  641. else
  642. {
  643. // We're drawing to a DFB we've converted to a DIB, so just call GDI
  644. // to handle it:
  645. return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra, prclOpaque,
  646. pboFore, pboOpaque, pptlBrush, mix));
  647. }
  648. return(TRUE);
  649. }
  650. /******************************Public*Routine******************************\
  651. * BOOL bEnableText
  652. *
  653. * Performs the necessary setup for the text drawing subcomponent.
  654. *
  655. \**************************************************************************/
  656. BOOL bEnableText(
  657. PDEV* ppdev)
  658. {
  659. // Our text algorithms require no initialization. If we were to
  660. // do glyph caching, we would probably want to allocate off-screen
  661. // memory and do a bunch of other stuff here.
  662. return(TRUE);
  663. }
  664. /******************************Public*Routine******************************\
  665. * VOID vDisableText
  666. *
  667. * Performs the necessary clean-up for the text drawing subcomponent.
  668. *
  669. \**************************************************************************/
  670. VOID vDisableText(PDEV* ppdev)
  671. {
  672. // Here we free any stuff allocated in 'bEnableText'.
  673. }
  674. /******************************Public*Routine******************************\
  675. * VOID vAssertModeText
  676. *
  677. * Disables or re-enables the text drawing subcomponent in preparation for
  678. * full-screen entry/exit.
  679. *
  680. \**************************************************************************/
  681. VOID vAssertModeText(
  682. PDEV* ppdev,
  683. BOOL bEnable)
  684. {
  685. // If we were to do off-screen glyph caching, we would probably want
  686. // to invalidate our cache here, because it will get destroyed when
  687. // we switch to full-screen.
  688. }
  689. /******************************Public*Routine******************************\
  690. * VOID DrvDestroyFont
  691. *
  692. * We're being notified that the given font is being deallocated; clean up
  693. * anything we've stashed in the 'pvConsumer' field of the 'pfo'.
  694. *
  695. \**************************************************************************/
  696. VOID DrvDestroyFont(FONTOBJ *pfo)
  697. {
  698. // This call isn't hooked, so GDI will never call it.
  699. //
  700. // This merely exists as a stub function for the sample multi-screen
  701. // support, so that MulDestroyFont can illustrate how multiple screen
  702. // text supports when the driver caches glyphs. If this driver did
  703. // glyph caching, we might have used the 'pvConsumer' field of the
  704. // 'pfo', which we would have to clean up.
  705. }