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.

2701 lines
81 KiB

  1. /******************************Module*Header*******************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: textout.c
  8. *
  9. * On every TextOut, GDI provides an array of 'GLYPHPOS' structures
  10. * for every glyph to be drawn. Each GLYPHPOS structure contains a
  11. * glyph handle and a pointer to a monochrome bitmap that describes
  12. * the glyph. (Note that unlike Windows 3.1, which provides a column-
  13. * major glyph bitmap, Windows NT always provides a row-major glyph
  14. * bitmap.) As such, there are three basic methods for drawing text
  15. * with hardware acceleration:
  16. *
  17. * 1) Glyph caching -- Glyph bitmaps are cached by the accelerator
  18. * (probably in off-screen memory), and text is drawn by
  19. * referring the hardware to the cached glyph locations.
  20. *
  21. * 2) Glyph expansion -- Each individual glyph is colour-expanded
  22. * directly to the screen from the monochrome glyph bitmap
  23. * supplied by GDI.
  24. *
  25. * 3) Buffer expansion -- The CPU is used to draw all the glyphs into
  26. * a 1bpp monochrome bitmap, and the hardware is then used
  27. * to colour-expand the result.
  28. *
  29. * In addition, 2) and 3) can each have two permutations:
  30. *
  31. * a) Glyphs are bit-packed -- The fastest method, where no bits
  32. * are used as padding between scans of the glyph.
  33. *
  34. * b) Glyphs are byte-, word-, or dword-packed -- The slower method,
  35. * where the hardware requires that each scan be padded with
  36. * unused bits to fill out to the end of the byte, word, or
  37. * dword.
  38. *
  39. * The fastest method depends on a number of variables, such as the
  40. * colour expansion speed, bus speed, CPU speed, average glyph size,
  41. * and average string length.
  42. *
  43. * For the S3 with normal sized glyphs, I've found that caching the
  44. * glyphs in off-screen memory is typically the slowest method.
  45. * Buffer expansion is typically fastest on the slow ISA bus (or when
  46. * memory-mapped I/O isn't available on the x86), and glyph expansion
  47. * is best on fast buses such as VL and PCI.
  48. *
  49. * This driver implements glyph expansion and buffer expansion --
  50. * methods 2) and 3). Depending on the hardware capabilities at
  51. * run-time, we'll use whichever one will be faster.
  52. *
  53. * Copyright (c) 1992-1998 Microsoft Corporation
  54. *
  55. \**************************************************************************/
  56. #include "precomp.h"
  57. RECTL grclMax = { 0, 0, 0x8000, 0x8000 };
  58. // Maximal clip rectangle for trivial clipping
  59. BYTE gajBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
  60. // Converts bit index to set bit
  61. #define FIFTEEN_BITS ((1 << 15)-1)
  62. /******************************Public*Routine******************************\
  63. * VOID vClipSolid
  64. *
  65. * Fills the specified rectangles with the specified colour, honouring
  66. * the requested clipping. No more than four rectangles should be passed in.
  67. * Intended for drawing the areas of the opaquing rectangle that extend
  68. * beyond the text box. The rectangles must be in left to right, top to
  69. * bottom order. Assumes there is at least one rectangle in the list.
  70. *
  71. \**************************************************************************/
  72. VOID vClipSolid(
  73. PDEV* ppdev,
  74. LONG crcl,
  75. RECTL* prcl,
  76. ULONG iColor,
  77. CLIPOBJ* pco)
  78. {
  79. BOOL bMore; // Flag for clip enumeration
  80. CLIPENUM ce; // Clip enumeration object
  81. ULONG i;
  82. ULONG j;
  83. RECTL arclTmp[4];
  84. ULONG crclTmp;
  85. RECTL* prclTmp;
  86. RECTL* prclClipTmp;
  87. LONG iLastBottom;
  88. RECTL* prclClip;
  89. RBRUSH_COLOR rbc;
  90. ASSERTDD((crcl > 0) && (crcl <= 4), "Expected 1 to 4 rectangles");
  91. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  92. "Expected a non-null clip object");
  93. rbc.iSolidColor = iColor;
  94. if (pco->iDComplexity == DC_RECT)
  95. {
  96. crcl = cIntersect(&pco->rclBounds, prcl, crcl);
  97. if (crcl != 0)
  98. {
  99. (ppdev->pfnFillSolid)(ppdev, crcl, prcl, 0xf0f0, rbc, NULL);
  100. }
  101. }
  102. else // iDComplexity == DC_COMPLEX
  103. {
  104. // Bottom of last rectangle to fill
  105. iLastBottom = prcl[crcl - 1].bottom;
  106. // Initialize the clip rectangle enumeration to right-down so we can
  107. // take advantage of the rectangle list being right-down:
  108. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  109. // Scan through all the clip rectangles, looking for intersects
  110. // of fill areas with region rectangles:
  111. do {
  112. // Get a batch of region rectangles:
  113. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
  114. // Clip the rect list to each region rect:
  115. for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
  116. {
  117. // Since the rectangles and the region enumeration are both
  118. // right-down, we can zip through the region until we reach
  119. // the first fill rect, and are done when we've passed the
  120. // last fill rect.
  121. if (prclClip->top >= iLastBottom)
  122. {
  123. // Past last fill rectangle; nothing left to do:
  124. return;
  125. }
  126. // Do intersection tests only if we've reached the top of
  127. // the first rectangle to fill:
  128. if (prclClip->bottom > prcl->top)
  129. {
  130. // We've reached the top Y scan of the first rect, so
  131. // it's worth bothering checking for intersection.
  132. // Generate a list of the rects clipped to this region
  133. // rect:
  134. prclTmp = prcl;
  135. prclClipTmp = arclTmp;
  136. for (i = crcl, crclTmp = 0; i-- != 0; prclTmp++)
  137. {
  138. // Intersect fill and clip rectangles
  139. if (bIntersect(prclTmp, prclClip, prclClipTmp))
  140. {
  141. // Add to list if anything's left to draw:
  142. crclTmp++;
  143. prclClipTmp++;
  144. }
  145. }
  146. // Draw the clipped rects
  147. if (crclTmp != 0)
  148. {
  149. (ppdev->pfnFillSolid)(ppdev, crclTmp, &arclTmp[0],
  150. 0xf0f0, rbc, NULL);
  151. }
  152. }
  153. }
  154. } while (bMore);
  155. }
  156. }
  157. /******************************Public*Routine******************************\
  158. * BOOL bIoTextOut
  159. *
  160. * Outputs text using the 'buffer expansion' method. We call GDI to draw
  161. * all the glyphs to a single monochrome buffer, and then we use the
  162. * hardware to colour expand the result to the screen.
  163. *
  164. \**************************************************************************/
  165. BOOL bIoTextOut(
  166. SURFOBJ* pso,
  167. STROBJ* pstro,
  168. FONTOBJ* pfo,
  169. CLIPOBJ* pco,
  170. RECTL* prclOpaque,
  171. BRUSHOBJ* pboFore,
  172. BRUSHOBJ* pboOpaque)
  173. {
  174. PDEV* ppdev;
  175. RECTL* prclBounds;
  176. LONG lDelta;
  177. ULONG ulBufferHeight;
  178. ULONG ulBufferBytes;
  179. BOOL bTmpAlloc;
  180. VOID* pvTmp;
  181. SURFOBJ* psoTmp;
  182. BOOL bOpaque;
  183. BRUSHOBJ boFore;
  184. BRUSHOBJ boOpaque;
  185. BOOL bRet;
  186. XLATECOLORS xlc; // Temporary for keeping colours
  187. XLATEOBJ xlo; // Temporary for passing colours
  188. CLIPENUM ce; // Clip enumeration object
  189. RBRUSH_COLOR rbc;
  190. RECTL* prclClip;
  191. RECTL rclClip;
  192. BOOL bMore;
  193. ROP4 rop4;
  194. ppdev = (PDEV*) pso->dhpdev;
  195. // If asked to do an opaque TextOut, we'll set it up so that the
  196. // 1bpp blt we do will automatically opaque the 'rclBkGround'
  197. // rectangle. But we have to handle here the case if 'prclOpaque'
  198. // is bigger than 'rclBkGround':
  199. if ((prclOpaque != NULL) &&
  200. ((prclOpaque->left != pstro->rclBkGround.left) ||
  201. (prclOpaque->top != pstro->rclBkGround.top) ||
  202. (prclOpaque->right != pstro->rclBkGround.right) ||
  203. (prclOpaque->bottom != pstro->rclBkGround.bottom)))
  204. {
  205. rbc.iSolidColor = pboOpaque->iSolidColor;
  206. prclClip = prclOpaque;
  207. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  208. {
  209. Output_Opaque:
  210. ppdev->pfnFillSolid(ppdev,
  211. 1,
  212. prclClip,
  213. 0xf0f0,
  214. rbc,
  215. NULL);
  216. }
  217. else if (pco->iDComplexity == DC_RECT)
  218. {
  219. if (bIntersect(&pco->rclBounds, prclOpaque, &rclClip))
  220. {
  221. prclClip = &rclClip;
  222. // Save some code size by jumping to the common
  223. // functions calls:
  224. goto Output_Opaque;
  225. }
  226. }
  227. else // pco->iDComplexity == DC_COMPLEX
  228. {
  229. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  230. do
  231. {
  232. bMore = CLIPOBJ_bEnum(pco,
  233. sizeof(ce) - sizeof(RECTL),
  234. (ULONG*) &ce);
  235. ce.c = cIntersect(prclOpaque, ce.arcl, ce.c);
  236. if (ce.c != 0)
  237. {
  238. ppdev->pfnFillSolid(ppdev,
  239. ce.c,
  240. &ce.arcl[0],
  241. 0xf0f0,
  242. rbc,
  243. NULL);
  244. }
  245. } while (bMore);
  246. }
  247. }
  248. // If there is an opaque rectangle then it will be bigger than the
  249. // background rectangle. We want to test with whichever is bigger.
  250. prclBounds = prclOpaque;
  251. if (prclBounds == NULL)
  252. {
  253. prclBounds = &pstro->rclBkGround;
  254. }
  255. if ((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL))
  256. {
  257. // I'm not entirely sure why, but GDI will occasionally send
  258. // us TextOut's where the opaquing rectangle does not intersect
  259. // with the clip object bounds -- meaning that the text out
  260. // should have already been trivially rejected. We will do so
  261. // here because the blt code usually assumes that all trivial
  262. // rejections will have already been performed, and we will be
  263. // passing this call on to the blt code:
  264. if ((pco->rclBounds.top >= pstro->rclBkGround.bottom) ||
  265. (pco->rclBounds.left >= pstro->rclBkGround.right) ||
  266. (pco->rclBounds.right <= pstro->rclBkGround.left) ||
  267. (pco->rclBounds.bottom <= pstro->rclBkGround.top))
  268. {
  269. // The entire operation was trivially rejected:
  270. return(TRUE);
  271. }
  272. }
  273. // See if the temporary buffer is big enough for the text; if
  274. // not, try to allocate enough memory. We round up to the
  275. // nearest dword multiple:
  276. lDelta = ((((pstro->rclBkGround.right + 31) & ~31) -
  277. (pstro->rclBkGround.left & ~31)) >> 3);
  278. ulBufferHeight = pstro->rclBkGround.bottom - pstro->rclBkGround.top;
  279. ulBufferBytes = lDelta * ulBufferHeight;
  280. if (((ULONG) lDelta > FIFTEEN_BITS) ||
  281. (ulBufferHeight > FIFTEEN_BITS))
  282. {
  283. // Fail if the math will have overflowed:
  284. return(FALSE);
  285. }
  286. // Use our temporary buffer if it's big enough, otherwise
  287. // allocate a buffer on the fly:
  288. if (ulBufferBytes >= TMP_BUFFER_SIZE)
  289. {
  290. // The textout is so big that I doubt this allocation will
  291. // cost a significant amount in performance:
  292. bTmpAlloc = TRUE;
  293. pvTmp = EngAllocUserMem(ulBufferBytes, ALLOC_TAG);
  294. if (pvTmp == NULL)
  295. return(FALSE);
  296. }
  297. else
  298. {
  299. bTmpAlloc = FALSE;
  300. pvTmp = ppdev->pvTmpBuffer;
  301. }
  302. psoTmp = ppdev->psoText;
  303. // Adjust 'lDelta' and 'pvScan0' of our temporary 1bpp surface object
  304. // so that when GDI starts drawing the text, it will begin in the
  305. // first dword
  306. psoTmp->pvScan0 = (BYTE*) pvTmp - (pstro->rclBkGround.top * lDelta)
  307. - ((pstro->rclBkGround.left & ~31) >> 3);
  308. psoTmp->lDelta = lDelta;
  309. ASSERTDD(((ULONG_PTR)psoTmp->pvScan0 &3)==0,"pvScan0 must be dword aligned");
  310. ASSERTDD((lDelta & 3) == 0, "lDelta must be dword aligned");
  311. // Get GDI to draw the text for us into a 1bpp buffer:
  312. boFore.iSolidColor = 1;
  313. boOpaque.iSolidColor = 0;
  314. bRet = EngTextOut(psoTmp,
  315. pstro,
  316. pfo,
  317. pco,
  318. NULL,
  319. &pstro->rclBkGround,
  320. &boFore,
  321. &boOpaque,
  322. NULL,
  323. 0x0d0d);
  324. if (bRet)
  325. {
  326. // Transparently blt the 1bpp buffer to the screen:
  327. xlc.iForeColor = pboFore->iSolidColor;
  328. xlc.iBackColor = pboOpaque->iSolidColor;
  329. xlo.pulXlate = (ULONG*) &xlc;
  330. prclClip = &pstro->rclBkGround;
  331. // Rop 'aacc' works out to a transparent blt, while 'cccc' works
  332. // out to an opaque blt:
  333. rop4 = (prclOpaque != NULL) ? 0xcccc : 0xaacc;
  334. if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL))
  335. {
  336. Output_Text:
  337. ppdev->pfnXfer1bpp(ppdev,
  338. 1,
  339. prclClip,
  340. rop4,
  341. psoTmp,
  342. (POINTL*) &pstro->rclBkGround,
  343. &pstro->rclBkGround,
  344. &xlo);
  345. }
  346. else if (pco->iDComplexity == DC_RECT)
  347. {
  348. if (bIntersect(&pco->rclBounds, &pstro->rclBkGround, &rclClip))
  349. {
  350. prclClip = &rclClip;
  351. // Save some code size by jumping to the common
  352. // functions calls:
  353. goto Output_Text;
  354. }
  355. }
  356. else // pco->iDComplexity == DC_COMPLEX
  357. {
  358. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  359. do
  360. {
  361. bMore = CLIPOBJ_bEnum(pco,
  362. sizeof(ce) - sizeof(RECTL),
  363. (ULONG*) &ce);
  364. ce.c = cIntersect(&pstro->rclBkGround, ce.arcl, ce.c);
  365. if (ce.c != 0)
  366. {
  367. ppdev->pfnXfer1bpp(ppdev,
  368. ce.c,
  369. &ce.arcl[0],
  370. rop4,
  371. psoTmp,
  372. (POINTL*) &pstro->rclBkGround,
  373. &pstro->rclBkGround,
  374. &xlo);
  375. }
  376. } while (bMore);
  377. }
  378. }
  379. // Free up any memory we allocated for the temp buffer:
  380. if (bTmpAlloc)
  381. {
  382. EngFreeUserMem(pvTmp);
  383. }
  384. return(TRUE);
  385. }
  386. /******************************Public*Routine******************************\
  387. * VOID vMmGeneralText
  388. *
  389. * Handles any strings that need to be clipped, using the 'glyph
  390. * expansion' method.
  391. *
  392. \**************************************************************************/
  393. VOID vMmGeneralText(
  394. PDEV* ppdev,
  395. STROBJ* pstro,
  396. CLIPOBJ* pco)
  397. {
  398. BYTE* pjMmBase;
  399. BOOL bMoreGlyphs;
  400. ULONG cGlyphOriginal;
  401. ULONG cGlyph;
  402. GLYPHPOS* pgpOriginal;
  403. GLYPHPOS* pgp;
  404. GLYPHBITS* pgb;
  405. POINTL ptlOrigin;
  406. BOOL bMore;
  407. CLIPENUM ce;
  408. RECTL* prclClip;
  409. ULONG ulCharInc;
  410. LONG cxGlyph;
  411. LONG cyGlyph;
  412. BYTE* pjGlyph;
  413. LONG cj;
  414. LONG cw;
  415. LONG xLeft;
  416. LONG yTop;
  417. LONG xRight;
  418. LONG yBottom;
  419. LONG xBias;
  420. LONG lDelta;
  421. LONG cx;
  422. LONG cy;
  423. BYTE iDComplexity;
  424. ASSERTDD(pco != NULL, "Don't expect NULL clip objects here");
  425. pjMmBase = ppdev->pjMmBase;
  426. do {
  427. if (pstro->pgp != NULL)
  428. {
  429. // There's only the one batch of glyphs, so save ourselves
  430. // a call:
  431. pgpOriginal = pstro->pgp;
  432. cGlyphOriginal = pstro->cGlyphs;
  433. bMoreGlyphs = FALSE;
  434. }
  435. else
  436. {
  437. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  438. }
  439. if (cGlyphOriginal > 0)
  440. {
  441. ulCharInc = pstro->ulCharInc;
  442. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  443. if (iDComplexity != DC_COMPLEX)
  444. {
  445. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  446. // DC_RECT, but the last time I checked, those two calls took
  447. // more than 150 instructions to go through GDI. Since
  448. // 'rclBounds' already contains the DC_RECT clip rectangle,
  449. // and since it's such a common case, we'll special case it:
  450. bMore = FALSE;
  451. ce.c = 1;
  452. if (iDComplexity == DC_TRIVIAL)
  453. prclClip = &grclMax;
  454. else
  455. prclClip = &pco->rclBounds;
  456. goto SingleRectangle;
  457. }
  458. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  459. do {
  460. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  461. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  462. {
  463. SingleRectangle:
  464. pgp = pgpOriginal;
  465. cGlyph = cGlyphOriginal;
  466. pgb = pgp->pgdf->pgb;
  467. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  468. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  469. // Loop through all the glyphs for this rectangle:
  470. while (TRUE)
  471. {
  472. cxGlyph = pgb->sizlBitmap.cx;
  473. cyGlyph = pgb->sizlBitmap.cy;
  474. pjGlyph = pgb->aj;
  475. if ((prclClip->left <= ptlOrigin.x) &&
  476. (prclClip->top <= ptlOrigin.y) &&
  477. (prclClip->right >= ptlOrigin.x + cxGlyph) &&
  478. (prclClip->bottom >= ptlOrigin.y + cyGlyph))
  479. {
  480. //-----------------------------------------------------
  481. // Unclipped glyph
  482. IO_FIFO_WAIT(ppdev, 4);
  483. MM_CUR_X(ppdev, pjMmBase, ptlOrigin.x);
  484. MM_CUR_Y(ppdev, pjMmBase, ptlOrigin.y);
  485. MM_MAJ_AXIS_PCNT(ppdev, pjMmBase, cxGlyph - 1);
  486. MM_MIN_AXIS_PCNT(ppdev, pjMmBase, cyGlyph - 1);
  487. IO_GP_WAIT(ppdev);
  488. if (cxGlyph <= 8)
  489. {
  490. //-----------------------------------------------------
  491. // 1 to 8 pels in width
  492. MM_CMD(ppdev, pjMmBase,
  493. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  494. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  495. WRITE | BYTE_SWAP | BUS_SIZE_16));
  496. CHECK_DATA_READY(ppdev);
  497. MM_TRANSFER_BYTE_THIN(ppdev, pjMmBase, pjGlyph, cyGlyph);
  498. CHECK_DATA_COMPLETE(ppdev);
  499. }
  500. else if (cxGlyph <= 16)
  501. {
  502. //-----------------------------------------------------
  503. // 9 to 16 pels in width
  504. MM_CMD(ppdev, pjMmBase,
  505. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  506. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  507. WRITE | BYTE_SWAP | BUS_SIZE_16));
  508. CHECK_DATA_READY(ppdev);
  509. MM_TRANSFER_WORD_ALIGNED(ppdev, pjMmBase, pjGlyph, cyGlyph);
  510. CHECK_DATA_COMPLETE(ppdev);
  511. }
  512. else
  513. {
  514. lDelta = (cxGlyph + 7) >> 3;
  515. if (!(lDelta & 1))
  516. {
  517. //-----------------------------------------------------
  518. // Even number of bytes in width
  519. MM_CMD(ppdev, pjMmBase,
  520. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  521. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  522. WRITE | BYTE_SWAP | BUS_SIZE_16));
  523. CHECK_DATA_READY(ppdev);
  524. MM_TRANSFER_WORD_ALIGNED(ppdev, pjMmBase, pjGlyph,
  525. ((lDelta * cyGlyph) >> 1));
  526. CHECK_DATA_COMPLETE(ppdev);
  527. }
  528. else
  529. {
  530. //-----------------------------------------------------
  531. // Odd number of bytes in width
  532. // We revert to byte transfers instead of word transfers
  533. // because word transfers would cause us to do unaligned
  534. // reads for every second scan, which could cause us to
  535. // read past the end of the glyph bitmap, and access
  536. // violate.
  537. MM_CMD(ppdev, pjMmBase,
  538. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  539. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  540. WRITE | BYTE_SWAP | BUS_SIZE_16));
  541. CHECK_DATA_READY(ppdev);
  542. MM_TRANSFER_WORD_ODD(ppdev, pjMmBase, pjGlyph, lDelta,
  543. cyGlyph);
  544. CHECK_DATA_COMPLETE(ppdev);
  545. }
  546. }
  547. }
  548. else
  549. {
  550. //-----------------------------------------------------
  551. // Clipped glyph
  552. // Find the intersection of the glyph rectangle
  553. // and the clip rectangle:
  554. xLeft = max(prclClip->left, ptlOrigin.x);
  555. yTop = max(prclClip->top, ptlOrigin.y);
  556. xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
  557. yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
  558. // Check for trivial rejection:
  559. if (((cx = xRight - xLeft) > 0) &&
  560. ((cy = yBottom - yTop) > 0))
  561. {
  562. IO_FIFO_WAIT(ppdev, 5);
  563. xBias = (xLeft - ptlOrigin.x) & 7;
  564. if (xBias != 0)
  565. {
  566. // 'xBias' is the bit position in the monochrome glyph
  567. // bitmap of the first pixel to be lit, relative to
  568. // the start of the byte. That is, if 'xBias' is 2,
  569. // then the first unclipped pixel is represented by bit
  570. // 2 of the corresponding bitmap byte.
  571. //
  572. // Normally, the accelerator expects bit 0 to be the
  573. // first lit byte. We use the scissors so that the
  574. // first 'xBias' bits of the byte will not be displayed.
  575. //
  576. // (What we're doing is simply aligning the monochrome
  577. // blt using the hardware clipping.)
  578. MM_SCISSORS_L(ppdev, pjMmBase, xLeft);
  579. xLeft -= xBias;
  580. cx += xBias;
  581. }
  582. MM_CUR_X(ppdev, pjMmBase, xLeft);
  583. MM_CUR_Y(ppdev, pjMmBase, yTop);
  584. MM_MAJ_AXIS_PCNT(ppdev, pjMmBase, cx - 1);
  585. MM_MIN_AXIS_PCNT(ppdev, pjMmBase, cy - 1);
  586. lDelta = (cxGlyph + 7) >> 3;
  587. pjGlyph += (yTop - ptlOrigin.y) * lDelta
  588. + ((xLeft - ptlOrigin.x) >> 3);
  589. cj = (cx + 7) >> 3;
  590. IO_GP_WAIT(ppdev);
  591. MM_CMD(ppdev, pjMmBase,
  592. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  593. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  594. WRITE | BYTE_SWAP | BUS_SIZE_16));
  595. CHECK_DATA_READY(ppdev);
  596. // We use byte transfers because I don't expect we'll be
  597. // asked to clip many large glyphs where it would be
  598. // worth the overhead of setting up for word transfers:
  599. do {
  600. MM_TRANSFER_BYTE(ppdev, pjMmBase, pjGlyph, cj);
  601. pjGlyph += lDelta;
  602. } while (--cy != 0);
  603. CHECK_DATA_COMPLETE(ppdev);
  604. if (xBias != 0)
  605. {
  606. // Reset the scissors if we used it:
  607. IO_FIFO_WAIT(ppdev, 1);
  608. MM_ABS_SCISSORS_L(ppdev, pjMmBase, 0);
  609. }
  610. }
  611. }
  612. if (--cGlyph == 0)
  613. break;
  614. // Get ready for next glyph:
  615. pgp++;
  616. pgb = pgp->pgdf->pgb;
  617. if (ulCharInc == 0)
  618. {
  619. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  620. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  621. }
  622. else
  623. {
  624. ptlOrigin.x += ulCharInc;
  625. }
  626. }
  627. }
  628. } while (bMore);
  629. }
  630. } while (bMoreGlyphs);
  631. }
  632. /******************************Public*Routine******************************\
  633. * CACHEDFONT* pcfAllocateCachedFont()
  634. *
  635. * Initializes our font data structure.
  636. *
  637. \**************************************************************************/
  638. CACHEDFONT* pcfAllocateCachedFont(
  639. PDEV* ppdev)
  640. {
  641. CACHEDFONT* pcf;
  642. CACHEDGLYPH** ppcg;
  643. LONG i;
  644. pcf = EngAllocMem(FL_ZERO_MEMORY, sizeof(CACHEDFONT), ALLOC_TAG);
  645. if (pcf != NULL)
  646. {
  647. // Note that we rely on FL_ZERO_MEMORY to zero 'pgaChain' and
  648. // 'cjAlloc':
  649. pcf->cgSentinel.hg = HGLYPH_SENTINEL;
  650. // Initialize the hash table entries to all point to our sentinel:
  651. for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
  652. {
  653. *ppcg = &pcf->cgSentinel;
  654. }
  655. }
  656. return(pcf);
  657. }
  658. /******************************Public*Routine******************************\
  659. * VOID vFreeCachedFont()
  660. *
  661. * Frees all memory associated with the cache we kept for this font.
  662. *
  663. \**************************************************************************/
  664. VOID vFreeCachedFont(
  665. CACHEDFONT* pcf)
  666. {
  667. GLYPHALLOC* pga;
  668. GLYPHALLOC* pgaNext;
  669. pga = pcf->pgaChain;
  670. while (pga != NULL)
  671. {
  672. pgaNext = pga->pgaNext;
  673. EngFreeMem(pga);
  674. pga = pgaNext;
  675. }
  676. EngFreeMem(pcf);
  677. }
  678. /******************************Public*Routine******************************\
  679. * VOID vTrimAndBitpackGlyph
  680. *
  681. * This routine takes a GDI byte-aligned glyphbits definition, trims off
  682. * any unused pixels on the sides, and creates a bit-packed result that
  683. * is a natural for the S3's monochrome expansion capabilities.
  684. * "Bit-packed" is where a small monochrome bitmap is packed with no
  685. * unused bits between strides. So if GDI gives us a 16x16 bitmap to
  686. * represent '.' that really only has a 2x2 array of lit pixels, we would
  687. * trim the result to give a single byte value of 0xf0.
  688. *
  689. * Use this routine if your monochrome expansion hardware can do bit-packed
  690. * expansion (this is the fastest method). If your hardware requires byte-,
  691. * word-, or dword-alignment on monochrome expansions, use
  692. * vTrimAndPackGlyph().
  693. *
  694. * (This driver doesn't use this routine only because the hardware can't do
  695. * bit-packing!)
  696. *
  697. \**************************************************************************/
  698. VOID vTrimAndBitpackGlyph(
  699. BYTE* pjBuf, // Note: Routine may touch preceding byte!
  700. BYTE* pjGlyph,
  701. LONG* pcxGlyph,
  702. LONG* pcyGlyph,
  703. POINTL* pptlOrigin,
  704. LONG* pcj) // For returning the count of bytes of the result
  705. {
  706. LONG cxGlyph;
  707. LONG cyGlyph;
  708. POINTL ptlOrigin;
  709. LONG cAlign;
  710. LONG lDelta;
  711. BYTE* pj;
  712. BYTE jBit;
  713. LONG cjSrcWidth;
  714. LONG lSrcSkip;
  715. LONG lDstSkip;
  716. LONG cRem;
  717. BYTE* pjSrc;
  718. BYTE* pjDst;
  719. LONG i;
  720. LONG j;
  721. BYTE jSrc;
  722. ///////////////////////////////////////////////////////////////
  723. // Trim the glyph
  724. cyGlyph = *pcyGlyph;
  725. cxGlyph = *pcxGlyph;
  726. ptlOrigin = *pptlOrigin;
  727. cAlign = 0;
  728. lDelta = (cxGlyph + 7) >> 3;
  729. // Trim off any zero rows at the bottom of the glyph:
  730. pj = pjGlyph + cyGlyph * lDelta; // One past last byte in glyph
  731. while (cyGlyph > 0)
  732. {
  733. i = lDelta;
  734. do {
  735. if (*(--pj) != 0)
  736. goto Done_Bottom_Trim;
  737. } while (--i != 0);
  738. // The entire last row has no lit pixels, so simply skip it:
  739. cyGlyph--;
  740. }
  741. ASSERTDD(cyGlyph == 0, "cyGlyph should only be zero here");
  742. // We found a space character. Set both dimensions to zero, so
  743. // that it's easy to special-case later:
  744. cxGlyph = 0;
  745. Done_Bottom_Trim:
  746. // If cxGlyph != 0, we know that the glyph has at least one non-zero
  747. // row and column. By exploiting this knowledge, we can simplify our
  748. // end-of-loop tests, because we don't have to check to see if we've
  749. // decremented either 'cyGlyph' or 'cxGlyph' to zero:
  750. if (cxGlyph != 0)
  751. {
  752. // Trim off any zero rows at the top of the glyph:
  753. pj = pjGlyph; // First byte in glyph
  754. while (TRUE)
  755. {
  756. i = lDelta;
  757. do {
  758. if (*(pj++) != 0)
  759. goto Done_Top_Trim;
  760. } while (--i != 0);
  761. // The entire first row has no lit pixels, so simply skip it:
  762. cyGlyph--;
  763. ptlOrigin.y++;
  764. pjGlyph = pj;
  765. }
  766. Done_Top_Trim:
  767. // Trim off any zero columns at the right edge of the glyph:
  768. while (TRUE)
  769. {
  770. j = cxGlyph - 1;
  771. pj = pjGlyph + (j >> 3); // Last byte in first row of glyph
  772. jBit = gajBit[j & 0x7];
  773. i = cyGlyph;
  774. do {
  775. if ((*pj & jBit) != 0)
  776. goto Done_Right_Trim;
  777. pj += lDelta;
  778. } while (--i != 0);
  779. // The entire last column has no lit pixels, so simply skip it:
  780. cxGlyph--;
  781. }
  782. Done_Right_Trim:
  783. // Trim off any zero columns at the left edge of the glyph:
  784. while (TRUE)
  785. {
  786. pj = pjGlyph; // First byte in first row of glyph
  787. jBit = gajBit[cAlign];
  788. i = cyGlyph;
  789. do {
  790. if ((*pj & jBit) != 0)
  791. goto Done_Left_Trim;
  792. pj += lDelta;
  793. } while (--i != 0);
  794. // The entire first column has no lit pixels, so simply skip it:
  795. ptlOrigin.x++;
  796. cxGlyph--;
  797. cAlign++;
  798. if (cAlign >= 8)
  799. {
  800. cAlign = 0;
  801. pjGlyph++;
  802. }
  803. }
  804. }
  805. Done_Left_Trim:
  806. ///////////////////////////////////////////////////////////////
  807. // Pack the glyph
  808. cjSrcWidth = (cxGlyph + cAlign + 7) >> 3;
  809. lSrcSkip = lDelta - cjSrcWidth;
  810. lDstSkip = ((cxGlyph + 7) >> 3) - cjSrcWidth - 1;
  811. cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
  812. pjSrc = pjGlyph;
  813. pjDst = pjBuf;
  814. // Zero the buffer, because we're going to 'or' stuff into it:
  815. memset(pjBuf, 0, (cxGlyph * cyGlyph + 7) >> 3);
  816. // cAlign used to indicate which bit in the first byte of the unpacked
  817. // glyph was the first non-zero pixel column. Now, we flip it to
  818. // indicate which bit in the packed byte will receive the next non-zero
  819. // glyph bit:
  820. cAlign = (-cAlign) & 0x7;
  821. if (cAlign > 0)
  822. {
  823. // It would be bad if our trimming calculations were wrong, because
  824. // we assume any bits to the left of the 'cAlign' bit will be zero.
  825. // As a result of this decrement, we will 'or' those zero bits into
  826. // whatever byte precedes the glyph bits array:
  827. pjDst--;
  828. ASSERTDD((*pjSrc >> cAlign) == 0, "Trimmed off too many bits");
  829. }
  830. for (i = cyGlyph; i != 0; i--)
  831. {
  832. for (j = cjSrcWidth; j != 0; j--)
  833. {
  834. // Note that we may modify a byte past the end of our
  835. // destination buffer, which is why we reserved an
  836. // extra byte:
  837. jSrc = *pjSrc;
  838. *(pjDst) |= (jSrc >> (cAlign));
  839. *(pjDst + 1) |= (jSrc << (8 - cAlign));
  840. pjSrc++;
  841. pjDst++;
  842. }
  843. pjSrc += lSrcSkip;
  844. pjDst += lDstSkip;
  845. cAlign += cRem;
  846. if (cAlign >= 8)
  847. {
  848. cAlign -= 8;
  849. pjDst++;
  850. }
  851. }
  852. ///////////////////////////////////////////////////////////////
  853. // Return results
  854. *pcxGlyph = cxGlyph;
  855. *pcyGlyph = cyGlyph;
  856. *pptlOrigin = ptlOrigin;
  857. *pcj = ((cxGlyph * cyGlyph) + 7) >> 3;
  858. }
  859. /******************************Public*Routine******************************\
  860. * VOID vTrimAndPackGlyph
  861. *
  862. * This routine takes a GDI byte-aligned glyphbits definition, trims off
  863. * any unused pixels on the sides, and creates a word-algined result that
  864. * is a natural for the S3's monochrome expansion capabilities.
  865. * So if GDI gives us a 16x16 bitmap to represent '.' that really only
  866. * has a 2x2 array of lit pixels, we would trim the result to give 2 words
  867. * of 0xc000 and 0xc000.
  868. *
  869. * Use this routine if your monochrome expansion hardware requires byte-,
  870. * word-, or dword-alignment on monochrome expansions. If your hardware
  871. * can do bit-packed expansions, please use vTrimAndBitpackGlyph(), since
  872. * it will be faster.
  873. *
  874. \**************************************************************************/
  875. VOID vTrimAndPackGlyph(
  876. PDEV* ppdev,
  877. BYTE* pjBuf, // Note: Routine may touch preceding byte!
  878. BYTE* pjGlyph,
  879. LONG* pcxGlyph,
  880. LONG* pcyGlyph,
  881. POINTL* pptlOrigin,
  882. LONG* pcj) // For returning the count of bytes of the result
  883. {
  884. LONG cxGlyph;
  885. LONG cyGlyph;
  886. POINTL ptlOrigin;
  887. LONG cAlign;
  888. LONG lDelta;
  889. BYTE* pj;
  890. BYTE jBit;
  891. LONG cjSrcWidth;
  892. LONG lSrcSkip;
  893. LONG lDstSkip;
  894. LONG lDstDelta;
  895. BYTE* pjSrc;
  896. BYTE* pjDst;
  897. LONG i;
  898. LONG j;
  899. BYTE jSrc;
  900. ///////////////////////////////////////////////////////////////
  901. // Trim the glyph
  902. cyGlyph = *pcyGlyph;
  903. cxGlyph = *pcxGlyph;
  904. ptlOrigin = *pptlOrigin;
  905. cAlign = 0;
  906. // let [x] denote the least integer greater than or equal to x
  907. // Set lDelta to be [cxGlyph/8]. This is the number of bytes occupied
  908. // by the pixels in the horizontal direction of the monochrome glyph.
  909. lDelta = (cxGlyph + 7) >> 3;
  910. // Trim off any zero rows at the bottom of the glyph:
  911. pj = pjGlyph + cyGlyph * lDelta; // One past last byte in glyph
  912. while (cyGlyph > 0)
  913. {
  914. i = lDelta;
  915. do {
  916. if (*(--pj) != 0)
  917. goto Done_Bottom_Trim;
  918. } while (--i != 0);
  919. // The entire last row has no lit pixels, so simply skip it:
  920. cyGlyph--;
  921. }
  922. ASSERTDD(cyGlyph == 0, "cyGlyph should only be zero here");
  923. // We found a space character. Set both dimensions to zero, so
  924. // that it's easy to special-case later:
  925. cxGlyph = 0;
  926. Done_Bottom_Trim:
  927. // If cxGlyph != 0, we know that the glyph has at least one non-zero
  928. // row and column. By exploiting this knowledge, we can simplify our
  929. // end-of-loop tests, because we don't have to check to see if we've
  930. // decremented either 'cyGlyph' or 'cxGlyph' to zero:
  931. if (cxGlyph != 0)
  932. {
  933. // Trim off any zero rows at the top of the glyph:
  934. pj = pjGlyph; // First byte in glyph
  935. while (TRUE)
  936. {
  937. i = lDelta;
  938. do {
  939. if (*(pj++) != 0)
  940. goto Done_Top_Trim;
  941. } while (--i != 0);
  942. // The entire first row has no lit pixels, so simply skip it:
  943. cyGlyph--;
  944. ptlOrigin.y++;
  945. pjGlyph = pj;
  946. }
  947. Done_Top_Trim:
  948. // Trim off any zero columns at the right edge of the glyph:
  949. while (TRUE)
  950. {
  951. j = cxGlyph - 1;
  952. pj = pjGlyph + (j >> 3); // Last byte in first row of glyph
  953. jBit = gajBit[j & 0x7];
  954. i = cyGlyph;
  955. do {
  956. if ((*pj & jBit) != 0)
  957. goto Done_Right_Trim;
  958. pj += lDelta;
  959. } while (--i != 0);
  960. // The entire last column has no lit pixels, so simply skip it:
  961. cxGlyph--;
  962. }
  963. Done_Right_Trim:
  964. // Trim off any zero columns at the left edge of the glyph:
  965. while (TRUE)
  966. {
  967. pj = pjGlyph; // First byte in first row of glyph
  968. jBit = gajBit[cAlign];
  969. i = cyGlyph;
  970. do {
  971. if ((*pj & jBit) != 0)
  972. goto Done_Left_Trim;
  973. pj += lDelta;
  974. } while (--i != 0);
  975. // The entire first column has no lit pixels, so simply skip it:
  976. ptlOrigin.x++;
  977. cxGlyph--;
  978. cAlign++;
  979. if (cAlign >= 8)
  980. {
  981. cAlign = 0;
  982. pjGlyph++;
  983. }
  984. }
  985. }
  986. Done_Left_Trim:
  987. ///////////////////////////////////////////////////////////////
  988. // Pack the glyph
  989. // byte count of cell size (trimmed width + blank left columns).
  990. cjSrcWidth = (cxGlyph + cAlign + 7) >> 3;
  991. // difference between cell width and trimmed glyph width.
  992. lSrcSkip = lDelta - cjSrcWidth;
  993. // trimmed glyph width in bytes.
  994. lDstDelta = (cxGlyph + 7) >> 3;
  995. // Make the glyphs 'word-packed' (i.e., every scan is word aligned)
  996. // unless in 24bpp mode, in which case we have to use 32 bit bus size,
  997. // which in turn requires dword packing.
  998. if (ppdev->iBitmapFormat == BMF_24BPP)
  999. lDstDelta = (lDstDelta + 3) & ~3;
  1000. else
  1001. lDstDelta = (lDstDelta + 1) & ~1;
  1002. lDstSkip = lDstDelta - cjSrcWidth;
  1003. pjSrc = pjGlyph; // Start of trimmed glyph, not including empty left columns.
  1004. pjDst = pjBuf;
  1005. // Zero the first byte of the buffer, because we're going to 'or' stuff
  1006. // into it:
  1007. *pjDst = 0;
  1008. // cAlign used to indicate which bit in the first byte of the unpacked
  1009. // glyph was the first non-zero pixel column. Now, we flip it to
  1010. // indicate which bit in the packed byte will receive the next non-zero
  1011. // glyph bit:
  1012. cAlign = (-cAlign) & 0x7;
  1013. if (cAlign > 0)
  1014. {
  1015. // It would be bad if our trimming calculations were wrong, because
  1016. // we assume any bits to the left of the 'cAlign' bit will be zero.
  1017. // As a result of this decrement, we will 'or' those zero bits into
  1018. // whatever byte precedes the glyph bits array:
  1019. pjDst--;
  1020. ASSERTDD((*pjSrc >> cAlign) == 0, "Trimmed off too many bits");
  1021. }
  1022. for (i = cyGlyph; i != 0; i--)
  1023. {
  1024. for (j = cjSrcWidth; j != 0; j--)
  1025. {
  1026. // Note that we may modify a byte past the end of our
  1027. // destination buffer, which is why we reserved an
  1028. // extra byte:
  1029. jSrc = *pjSrc;
  1030. *(pjDst) |= (jSrc >> (cAlign));
  1031. *(pjDst + 1) = (jSrc << (8 - cAlign));
  1032. pjSrc++;
  1033. pjDst++;
  1034. }
  1035. pjSrc += lSrcSkip;
  1036. pjDst += lDstSkip;
  1037. }
  1038. ///////////////////////////////////////////////////////////////
  1039. // Return results
  1040. *pcxGlyph = cxGlyph;
  1041. *pcyGlyph = cyGlyph;
  1042. *pptlOrigin = ptlOrigin;
  1043. *pcj = lDstDelta * cyGlyph;
  1044. }
  1045. /******************************Public*Routine******************************\
  1046. * LONG cjPutGlyphInCache
  1047. *
  1048. * Figures out where to be a glyph in off-screen memory, copies it
  1049. * there, and fills in any other data we'll need to display the glyph.
  1050. *
  1051. * This routine is rather device-specific, and will have to be extensively
  1052. * modified for other display adapters.
  1053. *
  1054. * Returns the number of bytes taken by the cached glyph bits.
  1055. *
  1056. \**************************************************************************/
  1057. LONG cjPutGlyphInCache(
  1058. PDEV* ppdev,
  1059. CACHEDGLYPH* pcg,
  1060. GLYPHBITS* pgb)
  1061. {
  1062. BYTE* pjGlyph;
  1063. LONG cxGlyph;
  1064. LONG cyGlyph;
  1065. POINTL ptlOrigin;
  1066. BYTE* pjSrc;
  1067. ULONG* pulDst;
  1068. LONG i;
  1069. LONG cPels;
  1070. ULONG ulGlyphThis;
  1071. ULONG ulGlyphNext;
  1072. ULONG ul;
  1073. ULONG ulStart;
  1074. LONG cj;
  1075. pjGlyph = pgb->aj;
  1076. cyGlyph = pgb->sizlBitmap.cy;
  1077. cxGlyph = pgb->sizlBitmap.cx;
  1078. ptlOrigin = pgb->ptlOrigin;
  1079. vTrimAndPackGlyph(ppdev, (BYTE*) &pcg->ad, pjGlyph, &cxGlyph, &cyGlyph,
  1080. &ptlOrigin, &cj);
  1081. ///////////////////////////////////////////////////////////////
  1082. // Initialize the glyph fields
  1083. pcg->ptlOrigin = ptlOrigin;
  1084. pcg->cxLessOne = cxGlyph - 1;
  1085. pcg->cyLessOne = cyGlyph - 1;
  1086. pcg->cxcyLessOne = PACKXY(cxGlyph - 1, cyGlyph - 1);
  1087. pcg->cw = (cj + 1) >> 1;
  1088. pcg->cd = (cj + 3) >> 2;
  1089. return(cj);
  1090. }
  1091. /******************************Public*Routine******************************\
  1092. * CACHEDGLYPH* pcgNew()
  1093. *
  1094. * Creates a new CACHEDGLYPH structure for keeping track of the glyph in
  1095. * off-screen memory. bPutGlyphInCache is called to actually put the glyph
  1096. * in off-screen memory.
  1097. *
  1098. * This routine should be reasonably device-independent, as bPutGlyphInCache
  1099. * will contain most of the code that will have to be modified for other
  1100. * display adapters.
  1101. *
  1102. \**************************************************************************/
  1103. CACHEDGLYPH* pcgNew(
  1104. PDEV* ppdev,
  1105. CACHEDFONT* pcf,
  1106. GLYPHPOS* pgp)
  1107. {
  1108. GLYPHBITS* pgb;
  1109. GLYPHALLOC* pga;
  1110. CACHEDGLYPH* pcg;
  1111. LONG cjCachedGlyph;
  1112. HGLYPH hg;
  1113. LONG iHash;
  1114. CACHEDGLYPH* pcgFind;
  1115. LONG cjGlyphRow;
  1116. LONG cj;
  1117. // First, calculate the amount of storage we'll need for this glyph:
  1118. pgb = pgp->pgdf->pgb;
  1119. // The glyphs are 'word-packed':
  1120. cjGlyphRow = ((pgb->sizlBitmap.cx + 15) & ~15) >> 3;
  1121. cjCachedGlyph = sizeof(CACHEDGLYPH) + (pgb->sizlBitmap.cy * cjGlyphRow);
  1122. // Reserve an extra byte at the end for temporary usage by our pack
  1123. // routine:
  1124. cjCachedGlyph++;
  1125. if (cjCachedGlyph > pcf->cjAlloc)
  1126. {
  1127. // Have to allocate a new glyph allocation structure:
  1128. pga = EngAllocMem(FL_ZERO_MEMORY, GLYPH_ALLOC_SIZE, ALLOC_TAG);
  1129. if (pga == NULL)
  1130. {
  1131. // It's safe to return at this time because we haven't
  1132. // fatally altered any of our data structures:
  1133. return(NULL);
  1134. }
  1135. // Add this allocation to the front of the allocation linked list,
  1136. // so that we can free it later:
  1137. pga->pgaNext = pcf->pgaChain;
  1138. pcf->pgaChain = pga;
  1139. // Now we've got a chunk of memory where we can store our cached
  1140. // glyphs:
  1141. pcf->pcgNew = &pga->acg[0];
  1142. pcf->cjAlloc = GLYPH_ALLOC_SIZE - (sizeof(*pga) - sizeof(pga->acg[0]));
  1143. // It would be bad if we let in any glyphs that would be bigger
  1144. // than our basic allocation size:
  1145. ASSERTDD(cjCachedGlyph <= GLYPH_ALLOC_SIZE, "Woah, this is one big glyph!");
  1146. }
  1147. pcg = pcf->pcgNew;
  1148. ///////////////////////////////////////////////////////////////
  1149. // Insert the glyph, in-order, into the list hanging off our hash
  1150. // bucket:
  1151. hg = pgp->hg;
  1152. pcg->hg = hg;
  1153. iHash = GLYPH_HASH_FUNC(hg);
  1154. pcgFind = pcf->apcg[iHash];
  1155. if (pcgFind->hg > hg)
  1156. {
  1157. pcf->apcg[iHash] = pcg;
  1158. pcg->pcgNext = pcgFind;
  1159. }
  1160. else
  1161. {
  1162. // The sentinel will ensure that we never fall off the end of
  1163. // this list:
  1164. while (pcgFind->pcgNext->hg < hg)
  1165. pcgFind = pcgFind->pcgNext;
  1166. // 'pcgFind' now points to the entry to the entry after which
  1167. // we want to insert our new node:
  1168. pcg->pcgNext = pcgFind->pcgNext;
  1169. pcgFind->pcgNext = pcg;
  1170. }
  1171. cj = cjPutGlyphInCache(ppdev, pcg, pgp->pgdf->pgb);
  1172. ///////////////////////////////////////////////////////////////
  1173. // We now know the size taken up by the packed and trimmed glyph;
  1174. // adjust the pointer to the next glyph accordingly. We only need
  1175. // to ensure 'dword' alignment:
  1176. cjCachedGlyph = sizeof(CACHEDGLYPH) + ((cj + 7) & ~7);
  1177. pcf->pcgNew = (CACHEDGLYPH*) ((BYTE*) pcg + cjCachedGlyph);
  1178. pcf->cjAlloc -= cjCachedGlyph;
  1179. return(pcg);
  1180. }
  1181. /******************************Public*Routine******************************\
  1182. * BOOL bMmCachedProportionalText
  1183. *
  1184. * Draws proportionally spaced glyphs via glyph caching.
  1185. *
  1186. \**************************************************************************/
  1187. BOOL bMmCachedProportionalText(
  1188. PDEV* ppdev,
  1189. CACHEDFONT* pcf,
  1190. GLYPHPOS* pgp,
  1191. LONG cGlyph)
  1192. {
  1193. BYTE* pjMmBase;
  1194. LONG xOffset;
  1195. LONG yOffset;
  1196. HGLYPH hg;
  1197. CACHEDGLYPH* pcg;
  1198. LONG cyLessOne;
  1199. LONG x;
  1200. LONG y;
  1201. pjMmBase = ppdev->pjMmBase;
  1202. xOffset = ppdev->xOffset;
  1203. yOffset = ppdev->yOffset;
  1204. // Ensure that there is enough room in the FIFO for the
  1205. // coordinate and dimensions of the first glyph, so that we
  1206. // don't accidentally hold the bus for a long to while a
  1207. // previous big operation, such as a screen-to-screen blt,
  1208. // is done.
  1209. IO_FIFO_WAIT(ppdev, 4);
  1210. do {
  1211. hg = pgp->hg;
  1212. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1213. while (pcg->hg < hg)
  1214. pcg = pcg->pcgNext; // Traverse collision list, if any
  1215. if (pcg->hg > hg)
  1216. {
  1217. // This will hopefully not be the common case (that is,
  1218. // we will have a high cache hit rate), so if I were
  1219. // writing this in Asm I would have this out-of-line
  1220. // to avoid the jump around for the common case.
  1221. // But the Pentium has branch prediction, so what the
  1222. // heck.
  1223. pcg = pcgNew(ppdev, pcf, pgp);
  1224. if (pcg == NULL)
  1225. return(FALSE);
  1226. }
  1227. // Space glyphs are trimmed to a height of zero, and we don't
  1228. // even have to touch the hardware for them:
  1229. cyLessOne = pcg->cyLessOne;
  1230. if (cyLessOne >= 0)
  1231. {
  1232. x = pgp->ptl.x + pcg->ptlOrigin.x + xOffset;
  1233. y = pgp->ptl.y + pcg->ptlOrigin.y + yOffset;
  1234. DBG_FAKE_WAIT(ppdev, pjMmBase, 4); // For debug builds only
  1235. MM_MAJ_AXIS_PCNT(ppdev, pjMmBase, pcg->cxLessOne);
  1236. MM_MIN_AXIS_PCNT(ppdev, pjMmBase, cyLessOne);
  1237. MM_ABS_CUR_X(ppdev, pjMmBase, x);
  1238. MM_ABS_CUR_Y(ppdev, pjMmBase, y);
  1239. IO_GP_WAIT(ppdev);
  1240. MM_CMD(ppdev, pjMmBase,
  1241. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  1242. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  1243. WRITE | BYTE_SWAP | BUS_SIZE_16));
  1244. CHECK_DATA_READY(ppdev);
  1245. MM_TRANSFER_WORD_ALIGNED(ppdev, pjMmBase, &pcg->ad[0], pcg->cw);
  1246. CHECK_DATA_COMPLETE(ppdev);
  1247. }
  1248. } while (pgp++, --cGlyph != 0);
  1249. return(TRUE);
  1250. }
  1251. /******************************Public*Routine******************************\
  1252. * BOOL bMmCachedClippedText
  1253. *
  1254. * Draws clipped text via glyph caching.
  1255. *
  1256. \**************************************************************************/
  1257. BOOL bMmCachedClippedText(
  1258. PDEV* ppdev,
  1259. CACHEDFONT* pcf,
  1260. STROBJ* pstro,
  1261. CLIPOBJ* pco)
  1262. {
  1263. BOOL bRet;
  1264. BYTE* pjMmBase;
  1265. LONG xOffset;
  1266. LONG yOffset;
  1267. BOOL bMoreGlyphs;
  1268. ULONG cGlyphOriginal;
  1269. ULONG cGlyph;
  1270. BOOL bClippingSet;
  1271. GLYPHPOS* pgpOriginal;
  1272. GLYPHPOS* pgp;
  1273. LONG xGlyph;
  1274. LONG yGlyph;
  1275. LONG x;
  1276. LONG y;
  1277. LONG xRight;
  1278. LONG cyLessOne;
  1279. BOOL bMore;
  1280. CLIPENUM ce;
  1281. RECTL* prclClip;
  1282. ULONG ulCharInc;
  1283. HGLYPH hg;
  1284. CACHEDGLYPH* pcg;
  1285. BYTE iDComplexity;
  1286. bRet = TRUE;
  1287. pjMmBase = ppdev->pjMmBase;
  1288. xOffset = ppdev->xOffset;
  1289. yOffset = ppdev->yOffset;
  1290. ulCharInc = pstro->ulCharInc;
  1291. // Ensure that there is enough room in the FIFO for the
  1292. // coordinate and dimensions of the first glyph, so that we
  1293. // don't accidentally hold the bus for a long to while a
  1294. // previous big operation, such as a screen-to-screen blt,
  1295. // is done.
  1296. IO_FIFO_WAIT(ppdev, 4);
  1297. do {
  1298. if (pstro->pgp != NULL)
  1299. {
  1300. // There's only the one batch of glyphs, so save ourselves
  1301. // a call:
  1302. pgpOriginal = pstro->pgp;
  1303. cGlyphOriginal = pstro->cGlyphs;
  1304. bMoreGlyphs = FALSE;
  1305. }
  1306. else
  1307. {
  1308. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  1309. }
  1310. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  1311. if (cGlyphOriginal > 0)
  1312. {
  1313. if (iDComplexity != DC_COMPLEX)
  1314. {
  1315. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  1316. // DC_RECT, but the last time I checked, those two calls took
  1317. // more than 150 instructions to go through GDI. Since
  1318. // 'rclBounds' already contains the DC_RECT clip rectangle,
  1319. // and since it's such a common case, we'll special case it:
  1320. bMore = FALSE;
  1321. ce.c = 1;
  1322. if (iDComplexity == DC_TRIVIAL)
  1323. prclClip = &grclMax;
  1324. else
  1325. prclClip = &pco->rclBounds;
  1326. goto SingleRectangle;
  1327. }
  1328. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  1329. do {
  1330. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  1331. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  1332. {
  1333. SingleRectangle:
  1334. // We don't always simply set the clipping rectangle here
  1335. // because it may actually end up that no text intersects
  1336. // this clip rectangle, so it would be for naught. This
  1337. // actually happens a lot when using NT's analog clock set
  1338. // to always-on-top, with a round shape:
  1339. bClippingSet = FALSE;
  1340. pgp = pgpOriginal;
  1341. cGlyph = cGlyphOriginal;
  1342. // We can't yet convert to absolute coordinates by adding
  1343. // in 'xOffset' or 'yOffset' here because we have yet to
  1344. // compare the coordinates to 'prclClip':
  1345. xGlyph = pgp->ptl.x;
  1346. yGlyph = pgp->ptl.y;
  1347. // Loop through all the glyphs for this rectangle:
  1348. while (TRUE)
  1349. {
  1350. hg = pgp->hg;
  1351. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1352. while (pcg->hg < hg)
  1353. pcg = pcg->pcgNext;
  1354. if (pcg->hg > hg)
  1355. {
  1356. // This will hopefully not be the common case (that is,
  1357. // we will have a high cache hit rate), so if I were
  1358. // writing this in Asm I would have this out-of-line
  1359. // to avoid the jump around for the common case.
  1360. // But the Pentium has branch prediction, so what the
  1361. // heck.
  1362. pcg = pcgNew(ppdev, pcf, pgp);
  1363. if (pcg == NULL)
  1364. {
  1365. bRet = FALSE;
  1366. goto AllDone;
  1367. }
  1368. }
  1369. // Space glyphs are trimmed to a height of zero, and we don't
  1370. // even have to touch the hardware for them:
  1371. cyLessOne = pcg->cyLessOne;
  1372. if (cyLessOne >= 0)
  1373. {
  1374. y = pcg->ptlOrigin.y + yGlyph;
  1375. x = pcg->ptlOrigin.x + xGlyph;
  1376. xRight = pcg->cxLessOne + x;
  1377. // Do trivial rejection:
  1378. if ((prclClip->right > x) &&
  1379. (prclClip->bottom > y) &&
  1380. (prclClip->left <= xRight) &&
  1381. (prclClip->top <= y + cyLessOne))
  1382. {
  1383. // Lazily set the hardware clipping:
  1384. if ((iDComplexity != DC_TRIVIAL) && (!bClippingSet))
  1385. {
  1386. bClippingSet = TRUE;
  1387. vSetClipping(ppdev, prclClip);
  1388. // Wait here for same reason we do IO_FIFO_WAIT(4) above...
  1389. IO_FIFO_WAIT(ppdev, 4);
  1390. }
  1391. DBG_FAKE_WAIT(ppdev, pjMmBase, 4); // For debug builds only
  1392. MM_MAJ_AXIS_PCNT(ppdev, pjMmBase, pcg->cxLessOne);
  1393. MM_MIN_AXIS_PCNT(ppdev, pjMmBase, cyLessOne);
  1394. MM_ABS_CUR_X(ppdev, pjMmBase, xOffset + x);
  1395. MM_ABS_CUR_Y(ppdev, pjMmBase, yOffset + y);
  1396. IO_GP_WAIT(ppdev);
  1397. MM_CMD(ppdev, pjMmBase,
  1398. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  1399. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  1400. WRITE | BYTE_SWAP | BUS_SIZE_16));
  1401. CHECK_DATA_READY(ppdev);
  1402. MM_TRANSFER_WORD_ALIGNED(ppdev, pjMmBase, &pcg->ad[0], pcg->cw);
  1403. CHECK_DATA_COMPLETE(ppdev);
  1404. }
  1405. }
  1406. if (--cGlyph == 0)
  1407. break;
  1408. // Get ready for next glyph:
  1409. pgp++;
  1410. if (ulCharInc == 0)
  1411. {
  1412. xGlyph = pgp->ptl.x;
  1413. yGlyph = pgp->ptl.y;
  1414. }
  1415. else
  1416. {
  1417. xGlyph += ulCharInc;
  1418. }
  1419. }
  1420. }
  1421. } while (bMore);
  1422. }
  1423. } while (bMoreGlyphs);
  1424. AllDone:
  1425. if (iDComplexity != DC_TRIVIAL)
  1426. {
  1427. vResetClipping(ppdev);
  1428. }
  1429. return(bRet);
  1430. }
  1431. /******************************Public*Routine******************************\
  1432. * BOOL bMmTextOut
  1433. *
  1434. * Outputs text using the 'buffer expansion' method. The CPU draws to a
  1435. * 1bpp buffer, and the result is colour-expanded to the screen using the
  1436. * hardware.
  1437. *
  1438. * Note that this is x86 only ('vFastText', which draws the glyphs to the
  1439. * 1bpp buffer, is writen in Asm).
  1440. *
  1441. * If you're just getting your driver working, this is the fastest way to
  1442. * bring up working accelerated text. All you have to do is write the
  1443. * 'Xfer1bpp' function that's also used by the blt code. This
  1444. * 'bBufferExpansion' routine shouldn't need to be modified at all.
  1445. *
  1446. \**************************************************************************/
  1447. BOOL bMmTextOut(
  1448. SURFOBJ* pso,
  1449. STROBJ* pstro,
  1450. FONTOBJ* pfo,
  1451. CLIPOBJ* pco,
  1452. RECTL* prclOpaque,
  1453. BRUSHOBJ* pboFore,
  1454. BRUSHOBJ* pboOpaque)
  1455. {
  1456. PDEV* ppdev;
  1457. DSURF* pdsurf;
  1458. BYTE* pjMmBase;
  1459. BOOL bGlyphExpand;
  1460. BOOL bTextPerfectFit;
  1461. ULONG cGlyph;
  1462. BOOL bMoreGlyphs;
  1463. GLYPHPOS* pgp;
  1464. GLYPHBITS* pgb;
  1465. BYTE* pjGlyph;
  1466. LONG cyGlyph;
  1467. POINTL ptlOrigin;
  1468. LONG ulCharInc;
  1469. BYTE iDComplexity;
  1470. LONG lDelta;
  1471. LONG cw;
  1472. RECTL rclOpaque;
  1473. CACHEDFONT* pcf;
  1474. ppdev = (PDEV*) pso->dhpdev;
  1475. pjMmBase = ppdev->pjMmBase;
  1476. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  1477. if (prclOpaque != NULL)
  1478. {
  1479. ////////////////////////////////////////////////////////////
  1480. // Opaque Initialization
  1481. ////////////////////////////////////////////////////////////
  1482. if (iDComplexity == DC_TRIVIAL)
  1483. {
  1484. DrawOpaqueRect:
  1485. IO_FIFO_WAIT(ppdev, 8);
  1486. MM_FRGD_COLOR(ppdev, pjMmBase, pboOpaque->iSolidColor);
  1487. MM_PIX_CNTL(ppdev, pjMmBase, ALL_ONES);
  1488. MM_FRGD_MIX(ppdev, pjMmBase, FOREGROUND_COLOR | OVERPAINT);
  1489. MM_CUR_X(ppdev, pjMmBase, prclOpaque->left);
  1490. MM_CUR_Y(ppdev, pjMmBase, prclOpaque->top);
  1491. MM_MAJ_AXIS_PCNT(ppdev, pjMmBase,
  1492. prclOpaque->right - prclOpaque->left - 1);
  1493. MM_MIN_AXIS_PCNT(ppdev, pjMmBase,
  1494. prclOpaque->bottom - prclOpaque->top - 1);
  1495. MM_CMD(ppdev, pjMmBase, RECTANGLE_FILL | DRAWING_DIR_TBLRXM |
  1496. DRAW | DIR_TYPE_XY |
  1497. LAST_PIXEL_ON | MULTIPLE_PIXELS |
  1498. WRITE);
  1499. }
  1500. else if (iDComplexity == DC_RECT)
  1501. {
  1502. if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
  1503. {
  1504. prclOpaque = &rclOpaque;
  1505. goto DrawOpaqueRect;
  1506. }
  1507. }
  1508. else
  1509. {
  1510. vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
  1511. }
  1512. // If we paint the glyphs in 'opaque' mode, we may not actually
  1513. // have to draw the opaquing rectangle up-front -- the process
  1514. // of laying down all the glyphs will automatically cover all
  1515. // of the pixels in the opaquing rectangle.
  1516. //
  1517. // The condition that must be satisfied is that the text must
  1518. // fit 'perfectly' such that the entire background rectangle is
  1519. // covered, and none of the glyphs overlap (if the glyphs
  1520. // overlap, such as for italics, they have to be drawn in
  1521. // transparent mode after the opaquing rectangle is cleared).
  1522. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  1523. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  1524. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  1525. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  1526. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  1527. if (bTextPerfectFit)
  1528. {
  1529. // If the glyphs don't overlap, we can lay the glyphs down
  1530. // in 'opaque' mode, which on the S3 I've found to be faster
  1531. // than opaque mode:
  1532. IO_FIFO_WAIT(ppdev, 7);
  1533. MM_PIX_CNTL(ppdev, pjMmBase, CPU_DATA);
  1534. MM_FRGD_MIX(ppdev, pjMmBase, FOREGROUND_COLOR | OVERPAINT);
  1535. MM_BKGD_MIX(ppdev, pjMmBase, BACKGROUND_COLOR | OVERPAINT);
  1536. MM_FRGD_COLOR(ppdev, pjMmBase, pboFore->iSolidColor);
  1537. MM_BKGD_COLOR(ppdev, pjMmBase, pboOpaque->iSolidColor);
  1538. goto SkipTransparentInitialization;
  1539. }
  1540. }
  1541. ////////////////////////////////////////////////////////////
  1542. // Transparent Initialization
  1543. ////////////////////////////////////////////////////////////
  1544. // Initialize the hardware for transparent text:
  1545. IO_FIFO_WAIT(ppdev, 4);
  1546. MM_PIX_CNTL(ppdev, pjMmBase, CPU_DATA);
  1547. MM_FRGD_MIX(ppdev, pjMmBase, FOREGROUND_COLOR | OVERPAINT);
  1548. MM_BKGD_MIX(ppdev, pjMmBase, BACKGROUND_COLOR | LEAVE_ALONE);
  1549. MM_FRGD_COLOR(ppdev, pjMmBase, pboFore->iSolidColor);
  1550. SkipTransparentInitialization:
  1551. if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
  1552. ((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
  1553. {
  1554. pcf = (CACHEDFONT*) pfo->pvConsumer;
  1555. if (pcf == NULL)
  1556. {
  1557. pcf = pcfAllocateCachedFont(ppdev);
  1558. if (pcf == NULL)
  1559. return(FALSE);
  1560. pfo->pvConsumer = pcf;
  1561. }
  1562. // Use our glyph cache:
  1563. if ((iDComplexity == DC_TRIVIAL) && (pstro->ulCharInc == 0))
  1564. {
  1565. do {
  1566. if (pstro->pgp != NULL)
  1567. {
  1568. // There's only the one batch of glyphs, so save ourselves
  1569. // a call:
  1570. pgp = pstro->pgp;
  1571. cGlyph = pstro->cGlyphs;
  1572. bMoreGlyphs = FALSE;
  1573. }
  1574. else
  1575. {
  1576. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  1577. }
  1578. if (cGlyph > 0)
  1579. {
  1580. if (!bMmCachedProportionalText(ppdev, pcf, pgp, cGlyph))
  1581. return(FALSE);
  1582. }
  1583. } while (bMoreGlyphs);
  1584. }
  1585. else
  1586. {
  1587. if (!bMmCachedClippedText(ppdev, pcf, pstro, pco))
  1588. return(FALSE);
  1589. }
  1590. }
  1591. else
  1592. {
  1593. DISPDBG((4, "Text too big to cache: %li x %li",
  1594. pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
  1595. vMmGeneralText(ppdev, pstro, pco);
  1596. }
  1597. return(TRUE);
  1598. }
  1599. /******************************Public*Routine******************************\
  1600. * BOOL bNwCachedProportionalText
  1601. *
  1602. * Draws proportionally spaced glyphs via glyph caching.
  1603. *
  1604. \**************************************************************************/
  1605. BOOL bNwCachedProportionalText(
  1606. PDEV* ppdev,
  1607. CACHEDFONT* pcf,
  1608. GLYPHPOS* pgp,
  1609. LONG cGlyph)
  1610. {
  1611. BYTE* pjMmBase;
  1612. LONG xOffset;
  1613. LONG yOffset;
  1614. HGLYPH hg;
  1615. CACHEDGLYPH* pcg;
  1616. LONG cxcyLessOne;
  1617. LONG x;
  1618. LONG y;
  1619. USHORT busmode = BUS_SIZE_16;
  1620. pjMmBase = ppdev->pjMmBase;
  1621. xOffset = ppdev->xOffset;
  1622. yOffset = ppdev->yOffset;
  1623. // Ensure that there is enough room in the FIFO for the
  1624. // coordinate and dimensions of the first glyph, so that we
  1625. // don't accidentally hold the bus for a long to while a
  1626. // previous big operation, such as a screen-to-screen blt,
  1627. // is done.
  1628. NW_FIFO_WAIT(ppdev, pjMmBase, 2);
  1629. if (ppdev->iBitmapFormat == BMF_24BPP)
  1630. busmode = BUS_SIZE_32;
  1631. do {
  1632. hg = pgp->hg;
  1633. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1634. while (pcg->hg < hg)
  1635. pcg = pcg->pcgNext; // Traverse collision list, if any
  1636. if (pcg->hg > hg)
  1637. {
  1638. // This will hopefully not be the common case (that is,
  1639. // we will have a high cache hit rate), so if I were
  1640. // writing this in Asm I would have this out-of-line
  1641. // to avoid the jump around for the common case.
  1642. // But the Pentium has branch prediction, so what the
  1643. // heck.
  1644. pcg = pcgNew(ppdev, pcf, pgp);
  1645. if (pcg == NULL)
  1646. return(FALSE);
  1647. }
  1648. // Space glyphs are trimmed to a height of zero, and we don't
  1649. // even have to touch the hardware for them:
  1650. cxcyLessOne = pcg->cxcyLessOne;
  1651. if (cxcyLessOne >= 0)
  1652. {
  1653. x = pgp->ptl.x + pcg->ptlOrigin.x + xOffset;
  1654. y = pgp->ptl.y + pcg->ptlOrigin.y + yOffset;
  1655. DBG_FAKE_WAIT(ppdev, pjMmBase, 2); // For debug builds only
  1656. NW_ABS_CURXY_FAST(ppdev, pjMmBase, x, y);
  1657. NW_ALT_PCNT_PACKED(ppdev, pjMmBase, cxcyLessOne);
  1658. NW_GP_WAIT(ppdev, pjMmBase);
  1659. NW_ALT_CMD(ppdev, pjMmBase,
  1660. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  1661. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  1662. WRITE | BYTE_SWAP | busmode));
  1663. CHECK_DATA_READY(ppdev);
  1664. #if defined(_X86_)
  1665. memcpy(pjMmBase, &pcg->ad[0], pcg->cd << 2);
  1666. #else
  1667. // Non-x86 platforms may be required to call the HAL to
  1668. // the I/O, or to do memory barriers:
  1669. MM_TRANSFER_DWORD_ALIGNED(ppdev, pjMmBase, &pcg->ad[0], pcg->cd);
  1670. #endif
  1671. CHECK_DATA_COMPLETE(ppdev);
  1672. }
  1673. } while (pgp++, --cGlyph != 0);
  1674. return(TRUE);
  1675. }
  1676. /******************************Public*Routine******************************\
  1677. * BOOL bNwCachedClippedText
  1678. *
  1679. * Draws clipped text via glyph caching.
  1680. *
  1681. \**************************************************************************/
  1682. BOOL bNwCachedClippedText(
  1683. PDEV* ppdev,
  1684. CACHEDFONT* pcf,
  1685. STROBJ* pstro,
  1686. CLIPOBJ* pco)
  1687. {
  1688. BOOL bRet;
  1689. BYTE* pjMmBase;
  1690. LONG xOffset;
  1691. LONG yOffset;
  1692. BOOL bMoreGlyphs;
  1693. ULONG cGlyphOriginal;
  1694. ULONG cGlyph;
  1695. BOOL bClippingSet;
  1696. GLYPHPOS* pgpOriginal;
  1697. GLYPHPOS* pgp;
  1698. LONG xGlyph;
  1699. LONG yGlyph;
  1700. LONG x;
  1701. LONG y;
  1702. LONG xRight;
  1703. LONG cyLessOne;
  1704. BOOL bMore;
  1705. CLIPENUM ce;
  1706. RECTL* prclClip;
  1707. ULONG ulCharInc;
  1708. HGLYPH hg;
  1709. CACHEDGLYPH* pcg;
  1710. BYTE iDComplexity;
  1711. USHORT busmode = BUS_SIZE_16;
  1712. bRet = TRUE;
  1713. pjMmBase = ppdev->pjMmBase;
  1714. xOffset = ppdev->xOffset;
  1715. yOffset = ppdev->yOffset;
  1716. ulCharInc = pstro->ulCharInc;
  1717. // Ensure that there is enough room in the FIFO for the
  1718. // coordinate and dimensions of the first glyph, so that we
  1719. // don't accidentally hold the bus for a long to while a
  1720. // previous big operation, such as a screen-to-screen blt,
  1721. // is done.
  1722. NW_FIFO_WAIT(ppdev, pjMmBase, 2);
  1723. if (ppdev->iBitmapFormat == BMF_24BPP)
  1724. busmode = BUS_SIZE_32;
  1725. do {
  1726. if (pstro->pgp != NULL)
  1727. {
  1728. // There's only the one batch of glyphs, so save ourselves
  1729. // a call:
  1730. pgpOriginal = pstro->pgp;
  1731. cGlyphOriginal = pstro->cGlyphs;
  1732. bMoreGlyphs = FALSE;
  1733. }
  1734. else
  1735. {
  1736. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  1737. }
  1738. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  1739. if (cGlyphOriginal > 0)
  1740. {
  1741. if (iDComplexity != DC_COMPLEX)
  1742. {
  1743. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  1744. // DC_RECT, but the last time I checked, those two calls took
  1745. // more than 150 instructions to go through GDI. Since
  1746. // 'rclBounds' already contains the DC_RECT clip rectangle,
  1747. // and since it's such a common case, we'll special case it:
  1748. bMore = FALSE;
  1749. ce.c = 1;
  1750. if (iDComplexity == DC_TRIVIAL)
  1751. prclClip = &grclMax;
  1752. else
  1753. prclClip = &pco->rclBounds;
  1754. goto SingleRectangle;
  1755. }
  1756. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  1757. do {
  1758. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  1759. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  1760. {
  1761. SingleRectangle:
  1762. // We don't always simply set the clipping rectangle here
  1763. // because it may actually end up that no text intersects
  1764. // this clip rectangle, so it would be for naught. This
  1765. // actually happens a lot when using NT's analog clock set
  1766. // to always-on-top, with a round shape:
  1767. bClippingSet = FALSE;
  1768. pgp = pgpOriginal;
  1769. cGlyph = cGlyphOriginal;
  1770. // We can't yet convert to absolute coordinates by adding
  1771. // in 'xOffset' or 'yOffset' here because we have yet to
  1772. // compare the coordinates to 'prclClip':
  1773. xGlyph = pgp->ptl.x;
  1774. yGlyph = pgp->ptl.y;
  1775. // Loop through all the glyphs for this rectangle:
  1776. while (TRUE)
  1777. {
  1778. hg = pgp->hg;
  1779. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1780. while (pcg->hg < hg)
  1781. pcg = pcg->pcgNext;
  1782. if (pcg->hg > hg)
  1783. {
  1784. // This will hopefully not be the common case (that is,
  1785. // we will have a high cache hit rate), so if I were
  1786. // writing this in Asm I would have this out-of-line
  1787. // to avoid the jump around for the common case.
  1788. // But the Pentium has branch prediction, so what the
  1789. // heck.
  1790. pcg = pcgNew(ppdev, pcf, pgp);
  1791. if (pcg == NULL)
  1792. {
  1793. bRet = FALSE;
  1794. goto AllDone;
  1795. }
  1796. }
  1797. // Space glyphs are trimmed to a height of zero, and we don't
  1798. // even have to touch the hardware for them:
  1799. cyLessOne = pcg->cyLessOne;
  1800. if (cyLessOne >= 0)
  1801. {
  1802. y = pcg->ptlOrigin.y + yGlyph;
  1803. x = pcg->ptlOrigin.x + xGlyph;
  1804. xRight = pcg->cxLessOne + x;
  1805. // Do trivial rejection:
  1806. if ((prclClip->right > x) &&
  1807. (prclClip->bottom > y) &&
  1808. (prclClip->left <= xRight) &&
  1809. (prclClip->top <= y + cyLessOne))
  1810. {
  1811. // Lazily set the hardware clipping:
  1812. if ((iDComplexity != DC_TRIVIAL) && (!bClippingSet))
  1813. {
  1814. bClippingSet = TRUE;
  1815. vSetClipping(ppdev, prclClip);
  1816. // Wait here for same reason we do NW_FIFO_WAIT(2) above...
  1817. NW_FIFO_WAIT(ppdev, pjMmBase, 2);
  1818. }
  1819. DBG_FAKE_WAIT(ppdev, pjMmBase, 2); // For debug builds only
  1820. NW_ABS_CURXY(ppdev, pjMmBase, xOffset + x, yOffset + y);
  1821. NW_ALT_PCNT_PACKED(ppdev, pjMmBase, pcg->cxcyLessOne);
  1822. NW_GP_WAIT(ppdev, pjMmBase);
  1823. NW_ALT_CMD(ppdev, pjMmBase,
  1824. (RECTANGLE_FILL | WAIT | DRAWING_DIR_TBLRXM |
  1825. DRAW | LAST_PIXEL_ON | MULTIPLE_PIXELS |
  1826. WRITE | BYTE_SWAP | busmode));
  1827. CHECK_DATA_READY(ppdev);
  1828. MM_TRANSFER_DWORD_ALIGNED(ppdev, pjMmBase, &pcg->ad[0], pcg->cd);
  1829. CHECK_DATA_COMPLETE(ppdev);
  1830. }
  1831. }
  1832. if (--cGlyph == 0)
  1833. break;
  1834. // Get ready for next glyph:
  1835. pgp++;
  1836. if (ulCharInc == 0)
  1837. {
  1838. xGlyph = pgp->ptl.x;
  1839. yGlyph = pgp->ptl.y;
  1840. }
  1841. else
  1842. {
  1843. xGlyph += ulCharInc;
  1844. }
  1845. }
  1846. }
  1847. } while (bMore);
  1848. }
  1849. } while (bMoreGlyphs);
  1850. AllDone:
  1851. if (iDComplexity != DC_TRIVIAL)
  1852. {
  1853. vResetClipping(ppdev);
  1854. }
  1855. return(bRet);
  1856. }
  1857. /******************************Public*Routine******************************\
  1858. * BOOL bNwTextOut
  1859. *
  1860. * Outputs text using the 'buffer expansion' method. The CPU draws to a
  1861. * 1bpp buffer, and the result is colour-expanded to the screen using the
  1862. * hardware.
  1863. *
  1864. * Note that this is x86 only ('vFastText', which draws the glyphs to the
  1865. * 1bpp buffer, is writen in Asm).
  1866. *
  1867. * If you're just getting your driver working, this is the fastest way to
  1868. * bring up working accelerated text. All you have to do is write the
  1869. * 'Xfer1bpp' function that's also used by the blt code. This
  1870. * 'bBufferExpansion' routine shouldn't need to be modified at all.
  1871. *
  1872. \**************************************************************************/
  1873. BOOL bNwTextOut(
  1874. SURFOBJ* pso,
  1875. STROBJ* pstro,
  1876. FONTOBJ* pfo,
  1877. CLIPOBJ* pco,
  1878. RECTL* prclOpaque,
  1879. BRUSHOBJ* pboFore,
  1880. BRUSHOBJ* pboOpaque)
  1881. {
  1882. PDEV* ppdev;
  1883. DSURF* pdsurf;
  1884. BYTE* pjMmBase;
  1885. BOOL bGlyphExpand;
  1886. BOOL bTextPerfectFit;
  1887. ULONG cGlyph;
  1888. BOOL bMoreGlyphs;
  1889. GLYPHPOS* pgp;
  1890. GLYPHBITS* pgb;
  1891. BYTE* pjGlyph;
  1892. LONG cyGlyph;
  1893. POINTL ptlOrigin;
  1894. LONG ulCharInc;
  1895. BYTE iDComplexity;
  1896. LONG lDelta;
  1897. LONG cw;
  1898. RECTL rclOpaque;
  1899. CACHEDFONT* pcf;
  1900. LONG xOffset;
  1901. LONG yOffset;
  1902. ppdev = (PDEV*) pso->dhpdev;
  1903. pjMmBase = ppdev->pjMmBase;
  1904. xOffset = ppdev->xOffset;
  1905. yOffset = ppdev->yOffset;
  1906. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  1907. if (prclOpaque != NULL)
  1908. {
  1909. ////////////////////////////////////////////////////////////
  1910. // Opaque Initialization
  1911. ////////////////////////////////////////////////////////////
  1912. if (iDComplexity == DC_TRIVIAL)
  1913. {
  1914. DrawOpaqueRect:
  1915. NW_FIFO_WAIT(ppdev, pjMmBase, 6);
  1916. NW_FRGD_COLOR(ppdev, pjMmBase, pboOpaque->iSolidColor);
  1917. MM_PIX_CNTL(ppdev, pjMmBase, ALL_ONES);
  1918. MM_FRGD_MIX(ppdev, pjMmBase, FOREGROUND_COLOR | OVERPAINT);
  1919. NW_ABS_CURXY_FAST(ppdev, pjMmBase, prclOpaque->left + xOffset,
  1920. prclOpaque->top + yOffset);
  1921. NW_ALT_PCNT(ppdev, pjMmBase,
  1922. prclOpaque->right - prclOpaque->left - 1,
  1923. prclOpaque->bottom - prclOpaque->top - 1);
  1924. NW_ALT_CMD(ppdev, pjMmBase, RECTANGLE_FILL | DRAWING_DIR_TBLRXM |
  1925. DRAW | DIR_TYPE_XY |
  1926. LAST_PIXEL_ON | MULTIPLE_PIXELS |
  1927. WRITE);
  1928. }
  1929. else if (iDComplexity == DC_RECT)
  1930. {
  1931. if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
  1932. {
  1933. prclOpaque = &rclOpaque;
  1934. goto DrawOpaqueRect;
  1935. }
  1936. }
  1937. else
  1938. {
  1939. vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
  1940. }
  1941. // If we paint the glyphs in 'opaque' mode, we may not actually
  1942. // have to draw the opaquing rectangle up-front -- the process
  1943. // of laying down all the glyphs will automatically cover all
  1944. // of the pixels in the opaquing rectangle.
  1945. //
  1946. // The condition that must be satisfied is that the text must
  1947. // fit 'perfectly' such that the entire background rectangle is
  1948. // covered, and none of the glyphs overlap (if the glyphs
  1949. // overlap, such as for italics, they have to be drawn in
  1950. // transparent mode after the opaquing rectangle is cleared).
  1951. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  1952. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  1953. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  1954. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  1955. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  1956. if (bTextPerfectFit)
  1957. {
  1958. // If the glyphs don't overlap, we can lay the glyphs down
  1959. // in 'opaque' mode, which on the S3 I've found to be faster
  1960. // than opaque mode:
  1961. NW_FIFO_WAIT(ppdev, pjMmBase, 4);
  1962. MM_PIX_CNTL(ppdev, pjMmBase, CPU_DATA);
  1963. NW_ALT_MIX(ppdev, pjMmBase, FOREGROUND_COLOR | OVERPAINT,
  1964. BACKGROUND_COLOR | OVERPAINT);
  1965. NW_FRGD_COLOR(ppdev, pjMmBase, pboFore->iSolidColor);
  1966. NW_BKGD_COLOR(ppdev, pjMmBase, pboOpaque->iSolidColor);
  1967. goto SkipTransparentInitialization;
  1968. }
  1969. }
  1970. ////////////////////////////////////////////////////////////
  1971. // Transparent Initialization
  1972. ////////////////////////////////////////////////////////////
  1973. // Initialize the hardware for transparent text:
  1974. NW_FIFO_WAIT(ppdev, pjMmBase, 3);
  1975. MM_PIX_CNTL(ppdev, pjMmBase, CPU_DATA);
  1976. NW_ALT_MIX(ppdev, pjMmBase, FOREGROUND_COLOR | OVERPAINT,
  1977. BACKGROUND_COLOR | LEAVE_ALONE);
  1978. NW_FRGD_COLOR(ppdev, pjMmBase, pboFore->iSolidColor);
  1979. SkipTransparentInitialization:
  1980. if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
  1981. ((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
  1982. {
  1983. pcf = (CACHEDFONT*) pfo->pvConsumer;
  1984. if (pcf == NULL)
  1985. {
  1986. pcf = pcfAllocateCachedFont(ppdev);
  1987. if (pcf == NULL)
  1988. return(FALSE);
  1989. pfo->pvConsumer = pcf;
  1990. }
  1991. // Use our glyph cache:
  1992. if ((iDComplexity == DC_TRIVIAL) && (pstro->ulCharInc == 0))
  1993. {
  1994. do {
  1995. if (pstro->pgp != NULL)
  1996. {
  1997. // There's only the one batch of glyphs, so save ourselves
  1998. // a call:
  1999. pgp = pstro->pgp;
  2000. cGlyph = pstro->cGlyphs;
  2001. bMoreGlyphs = FALSE;
  2002. }
  2003. else
  2004. {
  2005. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  2006. }
  2007. if (cGlyph > 0)
  2008. {
  2009. if (!bNwCachedProportionalText(ppdev, pcf, pgp, cGlyph))
  2010. return(FALSE);
  2011. }
  2012. } while (bMoreGlyphs);
  2013. }
  2014. else
  2015. {
  2016. if (!bNwCachedClippedText(ppdev, pcf, pstro, pco))
  2017. return(FALSE);
  2018. }
  2019. }
  2020. else
  2021. {
  2022. DISPDBG((4, "Text too big to cache: %li x %li",
  2023. pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
  2024. // Can't do large glyphs via accelerator at 24bpp:
  2025. if (ppdev->iBitmapFormat == BMF_24BPP)
  2026. {
  2027. BANK bnk;
  2028. BOOL b = TRUE;
  2029. vBankStart(ppdev,
  2030. (prclOpaque!= NULL) ? prclOpaque : &pstro->rclBkGround,
  2031. pco,
  2032. &bnk);
  2033. do {
  2034. b &= EngTextOut(bnk.pso,
  2035. pstro,
  2036. pfo,
  2037. bnk.pco,
  2038. NULL,
  2039. prclOpaque,
  2040. pboFore,
  2041. pboOpaque,
  2042. NULL,
  2043. 0x0d0d);
  2044. } while (bBankEnum(&bnk));
  2045. return b;
  2046. }
  2047. vMmGeneralText(ppdev, pstro, pco);
  2048. }
  2049. return(TRUE);
  2050. }
  2051. /******************************Public*Routine******************************\
  2052. * BOOL DrvTextOut
  2053. *
  2054. * Calls the appropriate text drawing routine.
  2055. *
  2056. \**************************************************************************/
  2057. BOOL DrvTextOut(
  2058. SURFOBJ* pso,
  2059. STROBJ* pstro,
  2060. FONTOBJ* pfo,
  2061. CLIPOBJ* pco,
  2062. RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
  2063. // to fill these extra rectangles (it is used
  2064. // largely for underlines). It's not a big
  2065. // performance win (GDI will call our DrvBitBlt
  2066. // to draw the extra rectangles).
  2067. RECTL* prclOpaque,
  2068. BRUSHOBJ* pboFore,
  2069. BRUSHOBJ* pboOpaque,
  2070. POINTL* pptlBrush, // Always unused, unless GCAPS_ARBRUSHOPAQUE set
  2071. MIX mix) // Always a copy mix -- 0x0d0d
  2072. {
  2073. PDEV* ppdev;
  2074. DSURF* pdsurf;
  2075. pdsurf = (DSURF*) pso->dhsurf;
  2076. ppdev = (PDEV*) pso->dhpdev;
  2077. ASSERTDD(!(pdsurf->dt & DT_DIB), "Didn't expect DT_DIB");
  2078. ppdev->xOffset = pdsurf->x;
  2079. ppdev->yOffset = pdsurf->y;
  2080. // There seems to be a problem with 24 bpp accelerated large text
  2081. // on s3 diamond 968 so for now, punt to GDI
  2082. // The DDI spec says we'll only ever get foreground and background
  2083. // mixes of R2_COPYPEN:
  2084. ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
  2085. return(ppdev->pfnTextOut(pso, pstro, pfo, pco, prclOpaque, pboFore,
  2086. pboOpaque));
  2087. }
  2088. /******************************Public*Routine******************************\
  2089. * BOOL bEnableText
  2090. *
  2091. * Performs the necessary setup for the text drawing subcomponent.
  2092. *
  2093. \**************************************************************************/
  2094. BOOL bEnableText(
  2095. PDEV* ppdev)
  2096. {
  2097. SIZEL sizl;
  2098. HBITMAP hbm;
  2099. if (ppdev->pfnTextOut == bIoTextOut)
  2100. {
  2101. // We need to allocate a temporary 1bpp surface object if we're
  2102. // going to have GDI draw the glyphs for us:
  2103. sizl.cx = ppdev->cxMemory;
  2104. sizl.cy = ppdev->cyMemory;
  2105. // We will be mucking with the surface's 'pvScan0' value, so we
  2106. // simply must pass in a non-NULL 'pvBits' value to EngCreateBitmap:
  2107. hbm = EngCreateBitmap(sizl, sizl.cx, BMF_1BPP, 0, ppdev->pvTmpBuffer);
  2108. if (hbm == 0)
  2109. return(FALSE);
  2110. ppdev->psoText = EngLockSurface((HSURF) hbm);
  2111. if (ppdev->psoText == NULL)
  2112. {
  2113. EngDeleteSurface((HSURF) hbm);
  2114. return(FALSE);
  2115. }
  2116. }
  2117. return(TRUE);
  2118. }
  2119. /******************************Public*Routine******************************\
  2120. * VOID vDisableText
  2121. *
  2122. * Performs the necessary clean-up for the text drawing subcomponent.
  2123. *
  2124. \**************************************************************************/
  2125. VOID vDisableText(PDEV* ppdev)
  2126. {
  2127. HSURF hsurf;
  2128. SURFOBJ* psoText;
  2129. // Here we free any stuff allocated in 'bEnableText'.
  2130. psoText = ppdev->psoText;
  2131. if (psoText != NULL)
  2132. {
  2133. hsurf = psoText->hsurf;
  2134. EngUnlockSurface(psoText);
  2135. EngDeleteSurface(hsurf);
  2136. }
  2137. }
  2138. /******************************Public*Routine******************************\
  2139. * VOID vAssertModeText
  2140. *
  2141. * Disables or re-enables the text drawing subcomponent in preparation for
  2142. * full-screen entry/exit.
  2143. *
  2144. \**************************************************************************/
  2145. VOID vAssertModeText(
  2146. PDEV* ppdev,
  2147. BOOL bEnable)
  2148. {
  2149. // If we were to do off-screen glyph caching, we would probably want
  2150. // to invalidate our cache here, because it will get destroyed when
  2151. // we switch to full-screen.
  2152. }
  2153. /******************************Public*Routine******************************\
  2154. * VOID DrvDestroyFont
  2155. *
  2156. * Note: Don't forget to export this call in 'enable.c', otherwise you'll
  2157. * get some pretty big memory leaks!
  2158. *
  2159. * We're being notified that the given font is being deallocated; clean up
  2160. * anything we've stashed in the 'pvConsumer' field of the 'pfo'.
  2161. *
  2162. \**************************************************************************/
  2163. VOID DrvDestroyFont(
  2164. FONTOBJ* pfo)
  2165. {
  2166. CACHEDFONT* pcf;
  2167. pcf = pfo->pvConsumer;
  2168. if (pcf != NULL)
  2169. {
  2170. vFreeCachedFont(pcf);
  2171. pfo->pvConsumer = NULL;
  2172. }
  2173. }