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.

2216 lines
64 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: textout.c
  3. *
  4. * We cache off-screen glyphs linearly in off-screen memory.
  5. *
  6. * Copyright (c) 1992-1996 Microsoft Corporation
  7. * Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd.
  8. \**************************************************************************/
  9. #include "precomp.h"
  10. //////////////////////////////////////////////////////////////////////////
  11. BYTE gajBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
  12. // Converts bit index to set bit
  13. RECTL grclMax = { 0, 0, 0x10000, 0x10000 };
  14. // Maximal clip rectangle for trivial clipping
  15. // Array used for getting the mirror image of bytes:
  16. BYTE gajFlip[] =
  17. {
  18. 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
  19. 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
  20. 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
  21. 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
  22. 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
  23. 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
  24. 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
  25. 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
  26. 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
  27. 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
  28. 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
  29. 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
  30. 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
  31. 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
  32. 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
  33. 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
  34. 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
  35. 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
  36. 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
  37. 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
  38. 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
  39. 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
  40. 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
  41. 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
  42. 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
  43. 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
  44. 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
  45. 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
  46. 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
  47. 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
  48. 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
  49. 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
  50. };
  51. /******************************Public*Routine******************************\
  52. * VOID vClipSolid
  53. *
  54. * Fills the specified rectangle with the specified colour, honouring
  55. * the requested clipping.
  56. *
  57. \**************************************************************************/
  58. VOID vClipSolid(
  59. PDEV* ppdev,
  60. RECTL* prcl,
  61. ULONG iColor,
  62. CLIPOBJ* pco)
  63. {
  64. BOOL bMore; // Flag for clip enumeration
  65. CLIPENUM ce; // Clip enumeration object
  66. LONG c; // Count of non-empty rectangles
  67. RBRUSH_COLOR rbc; // For passing colour to vFillSolid
  68. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  69. // Scan through all the clip rectangles, looking for intersects
  70. // of fill areas with region rectangles:
  71. rbc.iSolidColor = iColor;
  72. do {
  73. // Get a batch of region rectangles:
  74. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*) &ce);
  75. c = cIntersect(prcl, ce.arcl, ce.c);
  76. if (c != 0)
  77. ppdev->pfnFillSolid(ppdev, c, ce.arcl, 0xf0f0, rbc, NULL);
  78. } while (bMore);
  79. }
  80. /******************************Public*Routine******************************\
  81. * VOID vExpandGlyph
  82. *
  83. \**************************************************************************/
  84. VOID vExpandGlyph(
  85. PDEV* ppdev,
  86. BYTE* pj, // Can be unaligned
  87. LONG lSkip,
  88. LONG cj,
  89. LONG cy,
  90. BOOL bHwBug)
  91. {
  92. BYTE* pjBase;
  93. ULONG* pulDma;
  94. LONG cFifo;
  95. LONG cd;
  96. ULONG UNALIGNED* pulSrc;
  97. LONG cEdgeCases;
  98. LONG i;
  99. ULONG ul;
  100. ASSERTDD((bHwBug == 1) || (bHwBug == 0), "Expect binary bHwBug");
  101. pjBase = ppdev->pjBase;
  102. pulDma = (ULONG*) (pjBase + DMAWND);
  103. cd = cj >> 2;
  104. pulSrc = (ULONG UNALIGNED*) pj;
  105. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  106. BLT_WRITE_ON(ppdev, pjBase);
  107. // Make sure we have room for very first write that accounts for
  108. // the hardware bug:
  109. cFifo = FIFOSIZE - 1;
  110. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  111. // If we have to work around the hardware bug, we usually have to have
  112. // two FIFO entries open for the work-around write, and for the last
  113. // edge write:
  114. cEdgeCases = 1 + bHwBug;
  115. switch (cj & 3)
  116. {
  117. case 0:
  118. cEdgeCases = bHwBug; // No last edge write
  119. do {
  120. if (bHwBug)
  121. CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
  122. for (i = cd; i != 0; i--)
  123. {
  124. if (--cFifo < 0)
  125. {
  126. cFifo = FIFOSIZE - 1;
  127. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  128. }
  129. CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
  130. }
  131. if ((cFifo -= cEdgeCases) < 0)
  132. {
  133. cFifo = FIFOSIZE - 1;
  134. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  135. }
  136. pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip);
  137. } while (--cy != 0);
  138. break;
  139. case 1:
  140. do {
  141. if (bHwBug)
  142. CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
  143. for (i = cd; i != 0; i--)
  144. {
  145. if (--cFifo < 0)
  146. {
  147. cFifo = FIFOSIZE - 1;
  148. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  149. }
  150. CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
  151. }
  152. if ((cFifo -= cEdgeCases) < 0)
  153. {
  154. cFifo = FIFOSIZE - 2;
  155. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  156. }
  157. CP_WRITE_DMA(ppdev, pulDma, *((BYTE*) pulSrc));
  158. pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip + 1);
  159. } while (--cy != 0);
  160. break;
  161. case 2:
  162. do {
  163. if (bHwBug)
  164. CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
  165. for (i = cd; i != 0; i--)
  166. {
  167. if (--cFifo < 0)
  168. {
  169. cFifo = FIFOSIZE - 1;
  170. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  171. }
  172. CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
  173. }
  174. if ((cFifo -= cEdgeCases) < 0)
  175. {
  176. cFifo = FIFOSIZE - 2;
  177. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  178. }
  179. CP_WRITE_DMA(ppdev, pulDma, *((WORD UNALIGNED *) pulSrc));
  180. pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip + 2);
  181. } while (--cy != 0);
  182. break;
  183. case 3:
  184. do {
  185. if (bHwBug)
  186. CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
  187. for (i = cd; i != 0; i--)
  188. {
  189. if (--cFifo < 0)
  190. {
  191. cFifo = FIFOSIZE - 1;
  192. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  193. }
  194. CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
  195. }
  196. if ((cFifo -= cEdgeCases) < 0)
  197. {
  198. cFifo = FIFOSIZE - 2;
  199. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  200. }
  201. ul = *((WORD UNALIGNED *) pulSrc) | (*(((BYTE*) pulSrc) + 2) << 16);
  202. CP_WRITE_DMA(ppdev, pulDma, ul);
  203. pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip + 3);
  204. } while (--cy != 0);
  205. break;
  206. }
  207. BLT_WRITE_OFF(ppdev, pjBase);
  208. }
  209. /******************************Public*Routine******************************\
  210. * VOID vMgaGeneralText
  211. *
  212. \**************************************************************************/
  213. VOID vMgaGeneralText(
  214. PDEV* ppdev,
  215. STROBJ* pstro,
  216. CLIPOBJ* pco)
  217. {
  218. BYTE* pjBase;
  219. LONG xOffset;
  220. LONG yOffset;
  221. BYTE iDComplexity;
  222. BOOL bMoreGlyphs;
  223. ULONG cGlyphOriginal;
  224. ULONG cGlyph;
  225. GLYPHPOS* pgpOriginal;
  226. GLYPHPOS* pgp;
  227. GLYPHBITS* pgb;
  228. POINTL ptlOrigin;
  229. BOOL bMore;
  230. CLIPENUM ce;
  231. RECTL* prclClip;
  232. ULONG ulCharInc;
  233. LONG cxGlyph;
  234. LONG cyGlyph;
  235. LONG cx;
  236. LONG cy;
  237. LONG xLeft;
  238. LONG yTop;
  239. LONG xRight;
  240. LONG yBottom;
  241. LONG lDelta;
  242. LONG cj;
  243. BYTE* pjGlyph;
  244. BOOL bHwBug;
  245. LONG xAlign;
  246. pjBase = ppdev->pjBase;
  247. xOffset = ppdev->xOffset;
  248. yOffset = ppdev->yOffset;
  249. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  250. do {
  251. if (pstro->pgp != NULL)
  252. {
  253. // There's only the one batch of glyphs, so save ourselves
  254. // a call:
  255. pgpOriginal = pstro->pgp;
  256. cGlyphOriginal = pstro->cGlyphs;
  257. bMoreGlyphs = FALSE;
  258. }
  259. else
  260. {
  261. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  262. }
  263. if (cGlyphOriginal > 0)
  264. {
  265. ulCharInc = pstro->ulCharInc;
  266. if (iDComplexity != DC_COMPLEX)
  267. {
  268. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  269. // DC_RECT, but the last time I checked, those two calls took
  270. // more than 150 instructions to go through GDI. Since
  271. // 'rclBounds' already contains the DC_RECT clip rectangle,
  272. // and since it's such a common case, we'll special case it:
  273. bMore = FALSE;
  274. ce.c = 1;
  275. if (iDComplexity == DC_TRIVIAL)
  276. prclClip = &grclMax;
  277. else
  278. prclClip = &pco->rclBounds;
  279. goto SingleRectangle;
  280. }
  281. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  282. do {
  283. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  284. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  285. {
  286. SingleRectangle:
  287. pgp = pgpOriginal;
  288. cGlyph = cGlyphOriginal;
  289. pgb = pgp->pgdf->pgb;
  290. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  291. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  292. // Loop through all the glyphs for this rectangle:
  293. while (TRUE)
  294. {
  295. cxGlyph = pgb->sizlBitmap.cx;
  296. cyGlyph = pgb->sizlBitmap.cy;
  297. pjGlyph = pgb->aj;
  298. if ((prclClip->left <= ptlOrigin.x) &&
  299. (prclClip->top <= ptlOrigin.y) &&
  300. (prclClip->right >= ptlOrigin.x + cxGlyph) &&
  301. (prclClip->bottom >= ptlOrigin.y + cyGlyph))
  302. {
  303. //-----------------------------------------------------
  304. // Unclipped glyph
  305. CHECK_FIFO_SPACE(pjBase, 7);
  306. CP_WRITE(pjBase, DWG_LEN, cyGlyph);
  307. CP_WRITE(pjBase, DWG_YDST, yOffset + ptlOrigin.y);
  308. CP_WRITE(pjBase, DWG_FXLEFT, xOffset + ptlOrigin.x);
  309. CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + ptlOrigin.x + cxGlyph - 1);
  310. bHwBug = (cxGlyph >= 128);
  311. if (!bHwBug)
  312. {
  313. CP_WRITE(pjBase, DWG_SHIFT, 0);
  314. CP_WRITE(pjBase, DWG_AR3, 0);
  315. CP_START(pjBase, DWG_AR0, cxGlyph - 1);
  316. }
  317. else
  318. {
  319. CP_WRITE(pjBase, DWG_AR3, 8);
  320. CP_WRITE(pjBase, DWG_AR0, cxGlyph + 31);
  321. CP_START(pjBase, DWG_SHIFT, (24 << 16));
  322. }
  323. vExpandGlyph(ppdev, pjGlyph, 0, (cxGlyph + 7) >> 3, cyGlyph, bHwBug);
  324. }
  325. else
  326. {
  327. //-----------------------------------------------------
  328. // Clipped glyph
  329. // Find the intersection of the glyph rectangle
  330. // and the clip rectangle:
  331. xLeft = max(prclClip->left, ptlOrigin.x);
  332. yTop = max(prclClip->top, ptlOrigin.y);
  333. xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
  334. yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
  335. // Check for trivial rejection:
  336. if (((cx = xRight - xLeft) > 0) &&
  337. ((cy = yBottom - yTop) > 0))
  338. {
  339. CHECK_FIFO_SPACE(pjBase, 7);
  340. CP_WRITE(pjBase, DWG_LEN, cy);
  341. CP_WRITE(pjBase, DWG_YDST, yOffset + yTop);
  342. CP_WRITE(pjBase, DWG_FXLEFT, xOffset + xLeft);
  343. CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + xRight - 1);
  344. xAlign = (xLeft - ptlOrigin.x) & 31;
  345. bHwBug = (cx >= 128) && (xAlign <= 15);
  346. if (!bHwBug)
  347. {
  348. CP_WRITE(pjBase, DWG_SHIFT, 0);
  349. CP_WRITE(pjBase, DWG_AR3, xAlign);
  350. CP_START(pjBase, DWG_AR0, xAlign + cx - 1);
  351. }
  352. else
  353. {
  354. CP_WRITE(pjBase, DWG_AR3, xAlign + 8);
  355. CP_WRITE(pjBase, DWG_AR0, xAlign + cx + 31);
  356. CP_START(pjBase, DWG_SHIFT, (24 << 16));
  357. }
  358. lDelta = (cxGlyph + 7) >> 3;
  359. pjGlyph += (yTop - ptlOrigin.y) * lDelta
  360. + (((xLeft - ptlOrigin.x) >> 3) & ~3);
  361. cj = (xAlign + cx + 7) >> 3;
  362. vExpandGlyph(ppdev, pjGlyph, lDelta - cj, cj, cy, bHwBug);
  363. }
  364. }
  365. if (--cGlyph == 0)
  366. break;
  367. // Get ready for next glyph:
  368. pgp++;
  369. pgb = pgp->pgdf->pgb;
  370. if (ulCharInc == 0)
  371. {
  372. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  373. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  374. }
  375. else
  376. {
  377. ptlOrigin.x += ulCharInc;
  378. }
  379. }
  380. }
  381. } while (bMore);
  382. }
  383. } while (bMoreGlyphs);
  384. }
  385. /******************************Public*Routine******************************\
  386. * VOID vMilGeneralText
  387. *
  388. \**************************************************************************/
  389. VOID vMilGeneralText(
  390. PDEV* ppdev,
  391. STROBJ* pstro,
  392. CLIPOBJ* pco)
  393. {
  394. BYTE* pjBase;
  395. LONG xOffset;
  396. LONG yOffset;
  397. BYTE iDComplexity;
  398. BOOL bMoreGlyphs;
  399. ULONG cGlyphOriginal;
  400. ULONG cGlyph;
  401. GLYPHPOS* pgpOriginal;
  402. GLYPHPOS* pgp;
  403. GLYPHBITS* pgb;
  404. POINTL ptlOrigin;
  405. BOOL bMore;
  406. CLIPENUM ce;
  407. RECTL* prclClip;
  408. ULONG ulCharInc;
  409. LONG cxGlyph;
  410. LONG cyGlyph;
  411. LONG cx;
  412. LONG cy;
  413. LONG xLeft;
  414. LONG yTop;
  415. LONG xRight;
  416. LONG yBottom;
  417. LONG lDelta;
  418. LONG cj;
  419. BYTE* pjGlyph;
  420. BOOL bHwBug;
  421. LONG xAlign;
  422. BOOL bClipSet;
  423. pjBase = ppdev->pjBase;
  424. xOffset = ppdev->xOffset;
  425. yOffset = ppdev->yOffset;
  426. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  427. bClipSet = FALSE;
  428. do {
  429. if (pstro->pgp != NULL)
  430. {
  431. // There's only the one batch of glyphs, so save ourselves
  432. // a call:
  433. pgpOriginal = pstro->pgp;
  434. cGlyphOriginal = pstro->cGlyphs;
  435. bMoreGlyphs = FALSE;
  436. }
  437. else
  438. {
  439. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  440. }
  441. if (cGlyphOriginal > 0)
  442. {
  443. ulCharInc = pstro->ulCharInc;
  444. if (iDComplexity != DC_COMPLEX)
  445. {
  446. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  447. // DC_RECT, but the last time I checked, those two calls took
  448. // more than 150 instructions to go through GDI. Since
  449. // 'rclBounds' already contains the DC_RECT clip rectangle,
  450. // and since it's such a common case, we'll special case it:
  451. bMore = FALSE;
  452. ce.c = 1;
  453. if (iDComplexity == DC_TRIVIAL)
  454. prclClip = &grclMax;
  455. else
  456. prclClip = &pco->rclBounds;
  457. goto SingleRectangle;
  458. }
  459. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  460. do {
  461. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  462. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  463. {
  464. SingleRectangle:
  465. pgp = pgpOriginal;
  466. cGlyph = cGlyphOriginal;
  467. pgb = pgp->pgdf->pgb;
  468. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  469. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  470. // Loop through all the glyphs for this rectangle:
  471. while (TRUE)
  472. {
  473. cxGlyph = pgb->sizlBitmap.cx;
  474. cyGlyph = pgb->sizlBitmap.cy;
  475. pjGlyph = pgb->aj;
  476. if ((prclClip->left <= ptlOrigin.x) &&
  477. (prclClip->top <= ptlOrigin.y) &&
  478. (prclClip->right >= ptlOrigin.x + cxGlyph) &&
  479. (prclClip->bottom >= ptlOrigin.y + cyGlyph))
  480. {
  481. //-----------------------------------------------------
  482. // Unclipped glyph
  483. if (bClipSet)
  484. {
  485. // A clipped glyph was just drawn.
  486. CHECK_FIFO_SPACE(pjBase, 2);
  487. CP_WRITE(pjBase, DWG_CXLEFT, 0);
  488. CP_WRITE(pjBase, DWG_CXRIGHT, (ppdev->cxMemory - 1));
  489. bClipSet = FALSE;
  490. }
  491. CHECK_FIFO_SPACE(pjBase, 4);
  492. CP_WRITE(pjBase, DWG_FXBNDRY,
  493. ((xOffset + ptlOrigin.x + cxGlyph - 1) << bfxright_SHIFT) |
  494. ((xOffset + ptlOrigin.x) & bfxleft_MASK));
  495. // ylength_MASK not is needed since coordinates are within range
  496. CP_WRITE(pjBase, DWG_YDSTLEN,
  497. ((yOffset + ptlOrigin.y) << yval_SHIFT) |
  498. (cyGlyph));
  499. CP_WRITE(pjBase, DWG_AR3, 0);
  500. CP_START(pjBase, DWG_AR0, (cxGlyph - 1));
  501. vExpandGlyph(ppdev, pjGlyph, 0, (cxGlyph + 7) >> 3, cyGlyph, FALSE);
  502. }
  503. else
  504. {
  505. //-----------------------------------------------------
  506. // Clipped glyph
  507. // Find the intersection of the glyph rectangle
  508. // and the clip rectangle:
  509. xLeft = max(prclClip->left, ptlOrigin.x);
  510. yTop = max(prclClip->top, ptlOrigin.y);
  511. xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
  512. yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
  513. // Check for trivial rejection:
  514. if (((cx = xRight - xLeft) > 0) &&
  515. ((cy = yBottom - yTop) > 0))
  516. {
  517. // We have to set the clipping rectangle.
  518. CHECK_FIFO_SPACE(pjBase, 6);
  519. CP_WRITE(pjBase, DWG_CXLEFT, (xOffset + xLeft));
  520. CP_WRITE(pjBase, DWG_CXRIGHT, (xOffset + xRight - 1));
  521. bClipSet = TRUE;
  522. xAlign = (xLeft - ptlOrigin.x) & 0x7;
  523. xLeft -= xAlign;
  524. cx += xAlign;
  525. CP_WRITE(pjBase, DWG_FXBNDRY,
  526. ((xOffset + xRight - 1) << bfxright_SHIFT) |
  527. ((xOffset + xLeft) & bfxleft_MASK));
  528. // ylength_MASK not is needed since coordinates are within range
  529. CP_WRITE(pjBase, DWG_YDSTLEN,
  530. ((yOffset + yTop) << yval_SHIFT) |
  531. (cy));
  532. CP_WRITE(pjBase, DWG_AR3, 0);
  533. CP_START(pjBase, DWG_AR0, (cx - 1));
  534. // Send the bits to the DMA window.
  535. lDelta = (cxGlyph + 7) >> 3;
  536. pjGlyph += (yTop - ptlOrigin.y) * lDelta
  537. + ((xLeft - ptlOrigin.x) >> 3);
  538. cj = (cx + 7) >> 3;
  539. vExpandGlyph(ppdev, pjGlyph, lDelta - cj, cj, cy, FALSE);
  540. }
  541. }
  542. if (--cGlyph == 0)
  543. break;
  544. // Get ready for next glyph:
  545. pgp++;
  546. pgb = pgp->pgdf->pgb;
  547. if (ulCharInc == 0)
  548. {
  549. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  550. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  551. }
  552. else
  553. {
  554. ptlOrigin.x += ulCharInc;
  555. }
  556. }
  557. }
  558. } while (bMore);
  559. }
  560. } while (bMoreGlyphs);
  561. if (bClipSet)
  562. {
  563. // Clear the clipping registers.
  564. CHECK_FIFO_SPACE(pjBase, 2);
  565. CP_WRITE(pjBase, DWG_CXLEFT, 0);
  566. CP_WRITE(pjBase, DWG_CXRIGHT, (ppdev->cxMemory - 1));
  567. }
  568. }
  569. /******************************Public*Routine******************************\
  570. * CACHEDFONT* pcfAllocateCachedFont()
  571. *
  572. * Initializes our font data structure.
  573. *
  574. \**************************************************************************/
  575. CACHEDFONT* pcfAllocateCachedFont(
  576. PDEV* ppdev)
  577. {
  578. CACHEDFONT* pcf;
  579. CACHEDGLYPH** ppcg;
  580. LONG i;
  581. pcf = EngAllocMem(FL_ZERO_MEMORY, sizeof(CACHEDFONT), ALLOC_TAG);
  582. if (pcf != NULL)
  583. {
  584. // Insert this node into the doubly-linked cached-font list hanging
  585. // off the PDEV:
  586. pcf->pcfNext = ppdev->cfSentinel.pcfNext;
  587. pcf->pcfPrev = &ppdev->cfSentinel;
  588. ppdev->cfSentinel.pcfNext = pcf;
  589. pcf->pcfNext->pcfPrev = pcf;
  590. // Note that we rely on FL_ZERO_MEMORY to zero 'pgaChain' and
  591. // 'cjAlloc':
  592. pcf->cgSentinel.hg = HGLYPH_SENTINEL;
  593. // Initialize the hash table entries to all point to our sentinel:
  594. for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
  595. {
  596. *ppcg = &pcf->cgSentinel;
  597. }
  598. }
  599. return(pcf);
  600. }
  601. /******************************Public*Routine******************************\
  602. * VOID vFreeCachedFont()
  603. *
  604. * Frees all memory associated with the cache we kept for this font.
  605. *
  606. \**************************************************************************/
  607. VOID vFreeCachedFont(
  608. CACHEDFONT* pcf)
  609. {
  610. GLYPHALLOC* pga;
  611. GLYPHALLOC* pgaNext;
  612. // Remove this node from our cached-font linked-list:
  613. pcf->pcfPrev->pcfNext = pcf->pcfNext;
  614. pcf->pcfNext->pcfPrev = pcf->pcfPrev;
  615. // Free all glyph position allocations associated with this font:
  616. pga = pcf->pgaChain;
  617. while (pga != NULL)
  618. {
  619. pgaNext = pga->pgaNext;
  620. EngFreeMem(pga);
  621. pga = pgaNext;
  622. }
  623. EngFreeMem(pcf);
  624. }
  625. /******************************Public*Routine******************************\
  626. * VOID vBlowGlyphCache()
  627. *
  628. \**************************************************************************/
  629. VOID vBlowGlyphCache(
  630. PDEV* ppdev)
  631. {
  632. CACHEDFONT* pcfSentinel;
  633. CACHEDFONT* pcf;
  634. GLYPHALLOC* pga;
  635. GLYPHALLOC* pgaNext;
  636. CACHEDGLYPH** ppcg;
  637. LONG i;
  638. ASSERTDD(ppdev->flStatus & STAT_GLYPH_CACHE, "No glyph cache to be blown");
  639. // Reset our current glyph variables:
  640. ppdev->ulGlyphCurrent = ppdev->ulGlyphStart;
  641. ///////////////////////////////////////////////////////////////////
  642. // Now invalidate all active cached fonts:
  643. pcfSentinel = &ppdev->cfSentinel;
  644. for (pcf = pcfSentinel->pcfNext; pcf != pcfSentinel; pcf = pcf->pcfNext)
  645. {
  646. // Reset all the hash table entries to point to the cached-font
  647. // sentinel. This effectively resets the cache for this font:
  648. for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
  649. {
  650. *ppcg = &pcf->cgSentinel;
  651. }
  652. // We may as well free all glyph position allocations for this font:
  653. pga = pcf->pgaChain;
  654. while (pga != NULL)
  655. {
  656. pgaNext = pga->pgaNext;
  657. EngFreeMem(pga);
  658. pga = pgaNext;
  659. }
  660. pcf->pgaChain = NULL;
  661. pcf->cjAlloc = 0;
  662. }
  663. }
  664. /******************************Public*Routine******************************\
  665. * VOID vTrimAndPackGlyph
  666. *
  667. \**************************************************************************/
  668. VOID vTrimAndPackGlyph(
  669. BYTE* pjBuf, // Note: Routine may touch preceding byte!
  670. BYTE* pjGlyph,
  671. LONG* pcxGlyph,
  672. LONG* pcyGlyph,
  673. POINTL* pptlOrigin)
  674. {
  675. LONG cxGlyph;
  676. LONG cyGlyph;
  677. POINTL ptlOrigin;
  678. LONG cAlign;
  679. LONG lDelta;
  680. BYTE* pj;
  681. BYTE jBit;
  682. LONG cjSrcWidth;
  683. LONG lSrcSkip;
  684. LONG lDstSkip;
  685. LONG cRem;
  686. BYTE* pjSrc;
  687. BYTE* pjDst;
  688. LONG i;
  689. LONG j;
  690. BYTE jSrc;
  691. ///////////////////////////////////////////////////////////////
  692. // Trim the glyph
  693. cyGlyph = *pcyGlyph;
  694. cxGlyph = *pcxGlyph;
  695. ptlOrigin = *pptlOrigin;
  696. cAlign = 0;
  697. lDelta = (cxGlyph + 7) >> 3;
  698. // Trim off any zero rows at the bottom of the glyph:
  699. pj = pjGlyph + cyGlyph * lDelta; // One past last byte in glyph
  700. while (cyGlyph > 0)
  701. {
  702. i = lDelta;
  703. do {
  704. if (*(--pj) != 0)
  705. goto Done_Bottom_Trim;
  706. } while (--i != 0);
  707. // The entire last row has no lit pixels, so simply skip it:
  708. cyGlyph--;
  709. }
  710. ASSERTDD(cyGlyph == 0, "cyGlyph should only be zero here");
  711. // We found a space character. Set both dimensions to zero, so
  712. // that it's easy to special-case later:
  713. cxGlyph = 0;
  714. Done_Bottom_Trim:
  715. // If cxGlyph != 0, we know that the glyph has at least one non-zero
  716. // row and column. By exploiting this knowledge, we can simplify our
  717. // end-of-loop tests, because we don't have to check to see if we've
  718. // decremented either 'cyGlyph' or 'cxGlyph' to zero:
  719. if (cxGlyph != 0)
  720. {
  721. // Trim off any zero rows at the top of the glyph:
  722. pj = pjGlyph; // First byte in glyph
  723. while (TRUE)
  724. {
  725. i = lDelta;
  726. do {
  727. if (*(pj++) != 0)
  728. goto Done_Top_Trim;
  729. } while (--i != 0);
  730. // The entire first row has no lit pixels, so simply skip it:
  731. cyGlyph--;
  732. ptlOrigin.y++;
  733. pjGlyph = pj;
  734. }
  735. Done_Top_Trim:
  736. // Trim off any zero columns at the right edge of the glyph:
  737. while (TRUE)
  738. {
  739. j = cxGlyph - 1;
  740. pj = pjGlyph + (j >> 3); // Last byte in first row of glyph
  741. jBit = gajBit[j & 0x7];
  742. i = cyGlyph;
  743. do {
  744. if ((*pj & jBit) != 0)
  745. goto Done_Right_Trim;
  746. pj += lDelta;
  747. } while (--i != 0);
  748. // The entire last column has no lit pixels, so simply skip it:
  749. cxGlyph--;
  750. }
  751. Done_Right_Trim:
  752. // Trim off any zero columns at the left edge of the glyph:
  753. while (TRUE)
  754. {
  755. pj = pjGlyph; // First byte in first row of glyph
  756. jBit = gajBit[cAlign];
  757. i = cyGlyph;
  758. do {
  759. if ((*pj & jBit) != 0)
  760. goto Done_Left_Trim;
  761. pj += lDelta;
  762. } while (--i != 0);
  763. // The entire first column has no lit pixels, so simply skip it:
  764. ptlOrigin.x++;
  765. cxGlyph--;
  766. cAlign++;
  767. if (cAlign >= 8)
  768. {
  769. cAlign = 0;
  770. pjGlyph++;
  771. }
  772. }
  773. }
  774. Done_Left_Trim:
  775. ///////////////////////////////////////////////////////////////
  776. // Pack the glyph
  777. cjSrcWidth = (cxGlyph + cAlign + 7) >> 3;
  778. lSrcSkip = lDelta - cjSrcWidth;
  779. lDstSkip = ((cxGlyph + 7) >> 3) - cjSrcWidth - 1;
  780. cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
  781. pjSrc = pjGlyph;
  782. pjDst = pjBuf;
  783. // Zero the buffer, because we're going to 'or' stuff into it:
  784. memset(pjBuf, 0, (cxGlyph * cyGlyph + 7) >> 3);
  785. // cAlign used to indicate which bit in the first byte of the unpacked
  786. // glyph was the first non-zero pixel column. Now, we flip it to
  787. // indicate which bit in the packed byte will receive the next non-zero
  788. // glyph bit:
  789. cAlign = (-cAlign) & 0x7;
  790. if (cAlign > 0)
  791. {
  792. // It would be bad if our trimming calculations were wrong, because
  793. // we assume any bits to the left of the 'cAlign' bit will be zero.
  794. // As a result of this decrement, we will 'or' those zero bits into
  795. // whatever byte precedes the glyph bits array:
  796. pjDst--;
  797. ASSERTDD((*pjSrc >> cAlign) == 0, "Trimmed off too many bits");
  798. }
  799. for (i = cyGlyph; i != 0; i--)
  800. {
  801. for (j = cjSrcWidth; j != 0; j--)
  802. {
  803. // Note that we may modify a byte past the end of our
  804. // destination buffer, which is why we reserved an
  805. // extra byte:
  806. jSrc = *pjSrc;
  807. *(pjDst) |= (jSrc >> (cAlign));
  808. *(pjDst + 1) |= (jSrc << (8 - cAlign));
  809. pjSrc++;
  810. pjDst++;
  811. }
  812. pjSrc += lSrcSkip;
  813. pjDst += lDstSkip;
  814. cAlign += cRem;
  815. if (cAlign >= 8)
  816. {
  817. cAlign -= 8;
  818. pjDst++;
  819. }
  820. }
  821. ///////////////////////////////////////////////////////////////
  822. // Return results
  823. *pcxGlyph = cxGlyph;
  824. *pcyGlyph = cyGlyph;
  825. *pptlOrigin = ptlOrigin;
  826. }
  827. /******************************Public*Routine******************************\
  828. * VOID vPackGlyph
  829. *
  830. \**************************************************************************/
  831. VOID vPackGlyph(
  832. BYTE* pjBuf,
  833. BYTE* pjGlyph,
  834. LONG cxGlyph,
  835. LONG cyGlyph)
  836. {
  837. LONG cjSrcWidth;
  838. BYTE jSrc;
  839. BYTE* pjSrc;
  840. BYTE* pjDst;
  841. LONG cAlign;
  842. LONG i;
  843. LONG j;
  844. LONG cRem;
  845. ///////////////////////////////////////////////////////////////
  846. // Pack the glyph:
  847. cjSrcWidth = (cxGlyph + 7) >> 3;
  848. cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
  849. cAlign = 0;
  850. pjSrc = pjGlyph;
  851. pjDst = pjBuf;
  852. *pjDst = 0; // Have to zero very first byte
  853. i = cyGlyph;
  854. do {
  855. j = cjSrcWidth;
  856. do {
  857. jSrc = *pjSrc;
  858. *(pjDst) |= (jSrc >> (cAlign));
  859. // Note that we may modify a byte past the end of our
  860. // destination buffer, which is why we reserved an
  861. // extra byte:
  862. *(pjDst + 1) = (jSrc << (8 - cAlign));
  863. pjSrc++;
  864. pjDst++;
  865. } while (--j != 0);
  866. pjDst--;
  867. cAlign += cRem;
  868. if (cAlign >= 8)
  869. {
  870. cAlign -= 8;
  871. pjDst++;
  872. }
  873. } while (--i != 0);
  874. }
  875. /******************************Public*Routine******************************\
  876. * BOOL bPutGlyphInCache
  877. *
  878. * Figures out where to be a glyph in off-screen memory, copies it
  879. * there, and fills in any other data we'll need to display the glyph.
  880. *
  881. * This routine is rather device-specific, and will have to be extensively
  882. * modified for other display adapters.
  883. *
  884. * Returns TRUE if successful; FALSE if there wasn't enough room in
  885. * off-screen memory.
  886. *
  887. \**************************************************************************/
  888. BOOL bPutGlyphInCache(
  889. PDEV* ppdev,
  890. CACHEDGLYPH* pcg,
  891. GLYPHBITS* pgb)
  892. {
  893. BYTE* pjBase;
  894. BYTE* pjGlyph;
  895. LONG cxGlyph;
  896. LONG cyGlyph;
  897. POINTL ptlOrigin;
  898. BYTE* pjSrc;
  899. ULONG* pulSrc;
  900. ULONG* pulDst;
  901. LONG i;
  902. LONG cPels;
  903. ULONG ulGlyphThis;
  904. ULONG ulGlyphNext;
  905. ULONG ul;
  906. ULONG ulStart;
  907. BYTE ajBuf[MAX_GLYPH_SIZE + 4]; // Leave room at end for scratch space
  908. pjBase = ppdev->pjBase;
  909. pjGlyph = pgb->aj;
  910. cyGlyph = pgb->sizlBitmap.cy;
  911. cxGlyph = pgb->sizlBitmap.cx;
  912. ptlOrigin = pgb->ptlOrigin;
  913. vTrimAndPackGlyph(&ajBuf[0], pjGlyph, &cxGlyph, &cyGlyph, &ptlOrigin);
  914. ASSERTDD(((cyGlyph * cxGlyph + 7) / 8 + 1) <= sizeof(ajBuf),
  915. "Overran end of temporary glyph storage");
  916. ///////////////////////////////////////////////////////////////
  917. // Find spot for glyph in off-screen memory
  918. cPels = cyGlyph * cxGlyph; // Note that this may be zero
  919. ulGlyphThis = ppdev->ulGlyphCurrent;
  920. ulGlyphNext = ulGlyphThis + ((cPels + 31) & ~31); // Dword aligned
  921. if (ulGlyphNext >= ppdev->ulGlyphEnd)
  922. {
  923. // There's isn't enough free room in the off-screen cache for another
  924. // glyph. Let the caller know that it should call 'vBlowGlyphCache'
  925. // to free up space.
  926. //
  927. // First, make sure that this glyph will fit in the cache when it's
  928. // empty, too:
  929. ASSERTDD(ppdev->ulGlyphStart + cPels < ppdev->ulGlyphEnd,
  930. "Glyph can't fit in empty cache -- where's the higher-level check?");
  931. return(FALSE);
  932. }
  933. // Remember where the next glyph goes:
  934. ppdev->ulGlyphCurrent = ulGlyphNext;
  935. ///////////////////////////////////////////////////////////////
  936. // Initialize the glyph fields
  937. // Note that cxLessOne and ulLinearEnd will be invalid for a
  938. // 'space' character, so the rendering routine had better watch
  939. // for a height of zero:
  940. pcg->ptlOrigin = ptlOrigin;
  941. pcg->cy = cyGlyph;
  942. pcg->cxLessOne = cxGlyph - 1;
  943. pcg->ulLinearStart = ulGlyphThis;
  944. pcg->ulLinearEnd = ulGlyphThis + cPels - 1;
  945. ///////////////////////////////////////////////////////////////
  946. // Download the glyph
  947. ulStart = ulGlyphThis >> 3;
  948. // Copy the bit flipped glyph to off-screen:
  949. if (ppdev->ulBoardId == MGA_STORM)
  950. {
  951. pulSrc = (ULONG*) ajBuf;
  952. pulDst = (ULONG*) (ppdev->pjScreen + ulStart);
  953. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  954. START_DIRECT_ACCESS_STORM(ppdev, pjBase);
  955. for (i = (cPels + 31) >> 5; i != 0; i--)
  956. {
  957. *pulDst++ = *pulSrc++;
  958. }
  959. END_DIRECT_ACCESS_STORM(ppdev, pjBase);
  960. }
  961. else
  962. {
  963. pjSrc = ajBuf;
  964. pulDst = (ULONG*) (ppdev->pjBase + SRCWND + (ulStart & 31));
  965. if (ppdev->iBitmapFormat != BMF_8BPP)
  966. {
  967. // We have to set the plane write mask even when using direct
  968. // access. It doesn't matter at 8bpp:
  969. CHECK_FIFO_SPACE(pjBase, 1);
  970. CP_WRITE(pjBase, DWG_PLNWT, plnwt_ALL);
  971. }
  972. CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
  973. WAIT_NOT_BUSY(pjBase);
  974. CP_WRITE(pjBase, HST_DSTPAGE, ulStart);
  975. START_DIRECT_ACCESS_MGA_NO_WAIT(ppdev, pjBase);
  976. for (i = (cPels + 31) >> 5; i != 0; i--)
  977. {
  978. ul = gajFlip[*pjSrc++];
  979. ul |= gajFlip[*pjSrc++] << 8;
  980. ul |= gajFlip[*pjSrc++] << 16;
  981. ul |= gajFlip[*pjSrc++] << 24;
  982. // The '0' specifies a zero offset from pointer 'pulDst':
  983. CP_WRITE_DIRECT(pulDst, 0, ul);
  984. pulDst++;
  985. }
  986. END_DIRECT_ACCESS_MGA(ppdev, pjBase);
  987. if (ppdev->iBitmapFormat != BMF_8BPP)
  988. {
  989. // Restore the plane write mask:
  990. CHECK_FIFO_SPACE(pjBase, 1);
  991. CP_WRITE(pjBase, DWG_PLNWT, ppdev->ulPlnWt);
  992. }
  993. }
  994. return(TRUE);
  995. }
  996. /******************************Public*Routine******************************\
  997. * CACHEDGLYPH* pcgNew()
  998. *
  999. * Creates a new CACHEDGLYPH structure for keeping track of the glyph in
  1000. * off-screen memory. bPutGlyphInCache is called to actually put the glyph
  1001. * in off-screen memory.
  1002. *
  1003. * This routine should be reasonably device-independent, as bPutGlyphInCache
  1004. * will contain most of the code that will have to be modified for other
  1005. * display adapters.
  1006. *
  1007. \**************************************************************************/
  1008. CACHEDGLYPH* pcgNew(
  1009. PDEV* ppdev,
  1010. CACHEDFONT* pcf,
  1011. GLYPHPOS* pgp)
  1012. {
  1013. GLYPHALLOC* pga;
  1014. CACHEDGLYPH* pcg;
  1015. LONG cjCachedGlyph;
  1016. HGLYPH hg;
  1017. LONG iHash;
  1018. CACHEDGLYPH* pcgFind;
  1019. Restart:
  1020. // First, calculate the amount of storage we'll need for this glyph:
  1021. cjCachedGlyph = sizeof(CACHEDGLYPH);
  1022. if (cjCachedGlyph > pcf->cjAlloc)
  1023. {
  1024. // Have to allocate a new glyph allocation structure:
  1025. pga = EngAllocMem(FL_ZERO_MEMORY, GLYPH_ALLOC_SIZE, ALLOC_TAG);
  1026. if (pga == NULL)
  1027. {
  1028. // It's safe to return at this time because we haven't
  1029. // fatally altered any of our data structures:
  1030. return(NULL);
  1031. }
  1032. // Add this allocation to the front of the allocation linked list,
  1033. // so that we can free it later:
  1034. pga->pgaNext = pcf->pgaChain;
  1035. pcf->pgaChain = pga;
  1036. // Now we've got a chunk of memory where we can store our cached
  1037. // glyphs:
  1038. pcf->pcgNew = &pga->acg[0];
  1039. pcf->cjAlloc = GLYPH_ALLOC_SIZE - (sizeof(*pga) - sizeof(pga->acg[0]));
  1040. }
  1041. pcg = pcf->pcgNew;
  1042. // We only need to ensure 'dword' alignment of the next structure:
  1043. pcf->pcgNew = (CACHEDGLYPH*) ((BYTE*) pcg + cjCachedGlyph);
  1044. pcf->cjAlloc -= cjCachedGlyph;
  1045. ///////////////////////////////////////////////////////////////
  1046. // Insert the glyph, in-order, into the list hanging off our hash
  1047. // bucket:
  1048. hg = pgp->hg;
  1049. pcg->hg = hg;
  1050. iHash = GLYPH_HASH_FUNC(hg);
  1051. pcgFind = pcf->apcg[iHash];
  1052. if (pcgFind->hg > hg)
  1053. {
  1054. pcf->apcg[iHash] = pcg;
  1055. pcg->pcgNext = pcgFind;
  1056. }
  1057. else
  1058. {
  1059. // The sentinel will ensure that we never fall off the end of
  1060. // this list:
  1061. while (pcgFind->pcgNext->hg < hg)
  1062. pcgFind = pcgFind->pcgNext;
  1063. // 'pcgFind' now points to the entry to the entry after which
  1064. // we want to insert our new node:
  1065. pcg->pcgNext = pcgFind->pcgNext;
  1066. pcgFind->pcgNext = pcg;
  1067. }
  1068. ///////////////////////////////////////////////////////////////
  1069. // Download the glyph into off-screen memory:
  1070. if (!bPutGlyphInCache(ppdev, pcg, pgp->pgdf->pgb))
  1071. {
  1072. // If there was no more room in off-screen memory, blow the
  1073. // glyph cache and start over. Note that this assumes that
  1074. // the glyph will fit in the cache when the cache is completely
  1075. // empty.
  1076. vBlowGlyphCache(ppdev);
  1077. goto Restart;
  1078. }
  1079. return(pcg);
  1080. }
  1081. /******************************Public*Routine******************************\
  1082. * BOOL bMgaCachedProportionalText
  1083. *
  1084. * Draws proportionally spaced glyphs via glyph caching for the MGA.
  1085. *
  1086. \**************************************************************************/
  1087. BOOL bMgaCachedProportionalText(
  1088. PDEV* ppdev,
  1089. CACHEDFONT* pcf,
  1090. GLYPHPOS* pgp,
  1091. LONG cGlyph)
  1092. {
  1093. BYTE* pjBase;
  1094. LONG xOffset;
  1095. LONG yOffset;
  1096. CHAR cFifo;
  1097. HGLYPH hg;
  1098. CACHEDGLYPH* pcg;
  1099. LONG cy;
  1100. LONG x;
  1101. LONG y;
  1102. pjBase = ppdev->pjBase;
  1103. xOffset = ppdev->xOffset;
  1104. yOffset = ppdev->yOffset;
  1105. cFifo = 0;
  1106. do {
  1107. hg = pgp->hg;
  1108. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1109. while (pcg->hg < hg)
  1110. pcg = pcg->pcgNext; // Traverse collision list, if any
  1111. if (pcg->hg > hg)
  1112. {
  1113. // This will hopefully not be the common case (that is,
  1114. // we will have a high cache hit rate), so if I were
  1115. // writing this in Asm I would have this out-of-line
  1116. // to avoid the jump around for the common case.
  1117. // But the Pentium has branch prediction, so what the
  1118. // heck.
  1119. pcg = pcgNew(ppdev, pcf, pgp);
  1120. if (pcg == NULL)
  1121. return(FALSE);
  1122. cFifo = 0; // Have to reset count
  1123. }
  1124. // Space glyphs are trimmed to a height of zero, and we don't
  1125. // even have to touch the hardware for them:
  1126. cy = pcg->cy;
  1127. if (cy != 0)
  1128. {
  1129. x = pgp->ptl.x + pcg->ptlOrigin.x + xOffset;
  1130. y = pgp->ptl.y + pcg->ptlOrigin.y + yOffset;
  1131. // We get a little tricky here and try to amortize the cost of
  1132. // the read for checking the FIFO count on the MGA. Doing so
  1133. // gave us a 6% and 14% win on 21pt and 16pt text, respectively,
  1134. // on a P90:
  1135. cFifo -= 6;
  1136. if (cFifo < 0)
  1137. {
  1138. do {
  1139. cFifo = GET_FIFO_SPACE(pjBase) - 6;
  1140. } while (cFifo < 0);
  1141. }
  1142. CP_WRITE(pjBase, DWG_LEN, cy);
  1143. CP_WRITE(pjBase, DWG_YDST, y);
  1144. CP_WRITE(pjBase, DWG_FXLEFT, x);
  1145. CP_WRITE(pjBase, DWG_FXRIGHT, x + pcg->cxLessOne);
  1146. CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
  1147. CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
  1148. }
  1149. } while (pgp++, --cGlyph != 0);
  1150. return(TRUE);
  1151. }
  1152. /******************************Public*Routine******************************\
  1153. * BOOL bMilCachedProportionalText
  1154. *
  1155. * Draws proportionally spaced glyphs via glyph caching for the Millennium.
  1156. *
  1157. \**************************************************************************/
  1158. BOOL bMilCachedProportionalText(
  1159. PDEV* ppdev,
  1160. CACHEDFONT* pcf,
  1161. GLYPHPOS* pgp,
  1162. LONG cGlyph)
  1163. {
  1164. BYTE* pjBase;
  1165. LONG xOffset;
  1166. LONG yOffset;
  1167. CHAR cFifo;
  1168. HGLYPH hg;
  1169. CACHEDGLYPH* pcg;
  1170. LONG cy;
  1171. LONG x;
  1172. LONG y;
  1173. pjBase = ppdev->pjBase;
  1174. xOffset = ppdev->xOffset;
  1175. yOffset = ppdev->yOffset;
  1176. cFifo = 0;
  1177. do {
  1178. hg = pgp->hg;
  1179. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1180. while (pcg->hg < hg)
  1181. pcg = pcg->pcgNext; // Traverse collision list, if any
  1182. if (pcg->hg > hg)
  1183. {
  1184. // This will hopefully not be the common case (that is,
  1185. // we will have a high cache hit rate), so if I were
  1186. // writing this in Asm I would have this out-of-line
  1187. // to avoid the jump around for the common case.
  1188. // But the Pentium has branch prediction, so what the
  1189. // heck.
  1190. pcg = pcgNew(ppdev, pcf, pgp);
  1191. if (pcg == NULL)
  1192. return(FALSE);
  1193. cFifo = 0; // Have to reset count
  1194. }
  1195. // Space glyphs are trimmed to a height of zero, and we don't
  1196. // even have to touch the hardware for them:
  1197. cy = pcg->cy;
  1198. if (cy != 0)
  1199. {
  1200. x = pgp->ptl.x + pcg->ptlOrigin.x + xOffset;
  1201. y = pgp->ptl.y + pcg->ptlOrigin.y + yOffset;
  1202. cFifo -= 4;
  1203. if (cFifo < 0)
  1204. {
  1205. do {
  1206. cFifo = GET_FIFO_SPACE(pjBase) - 4;
  1207. } while (cFifo < 0);
  1208. }
  1209. CP_WRITE(pjBase, DWG_YDSTLEN, (y << yval_SHIFT) | cy);
  1210. CP_WRITE(pjBase, DWG_FXBNDRY, ((x + pcg->cxLessOne) << bfxright_SHIFT) |
  1211. x);
  1212. CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
  1213. CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
  1214. }
  1215. } while (pgp++, --cGlyph != 0);
  1216. return(TRUE);
  1217. }
  1218. /******************************Public*Routine******************************\
  1219. * BOOL bCachedFixedText
  1220. *
  1221. * Draws fixed spaced glyphs via glyph caching.
  1222. *
  1223. \**************************************************************************/
  1224. BOOL bCachedFixedText(
  1225. PDEV* ppdev,
  1226. CACHEDFONT* pcf,
  1227. GLYPHPOS* pgp,
  1228. LONG cGlyph,
  1229. ULONG ulCharInc)
  1230. {
  1231. BYTE* pjBase;
  1232. LONG xGlyph;
  1233. LONG yGlyph;
  1234. CHAR cFifo;
  1235. HGLYPH hg;
  1236. CACHEDGLYPH* pcg;
  1237. LONG cy;
  1238. LONG x;
  1239. LONG y;
  1240. pjBase = ppdev->pjBase;
  1241. xGlyph = ppdev->xOffset + pgp->ptl.x;
  1242. yGlyph = ppdev->yOffset + pgp->ptl.y;
  1243. cFifo = 0;
  1244. do {
  1245. hg = pgp->hg;
  1246. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1247. while (pcg->hg < hg)
  1248. pcg = pcg->pcgNext; // Traverse collision list, if any
  1249. if (pcg->hg > hg)
  1250. {
  1251. // This will hopefully not be the common case (that is,
  1252. // we will have a high cache hit rate), so if I were
  1253. // writing this in Asm I would have this out-of-line
  1254. // to avoid the jump around for the common case.
  1255. // But the Pentium has branch prediction, so what the
  1256. // heck.
  1257. pcg = pcgNew(ppdev, pcf, pgp);
  1258. if (pcg == NULL)
  1259. return(FALSE);
  1260. cFifo = 0; // Have to reset count
  1261. }
  1262. // Space glyphs are trimmed to a height of zero, and we don't
  1263. // even have to touch the hardware for them:
  1264. cy = pcg->cy;
  1265. if (cy != 0)
  1266. {
  1267. x = xGlyph + pcg->ptlOrigin.x;
  1268. y = yGlyph + pcg->ptlOrigin.y;
  1269. cFifo -= 6;
  1270. if (cFifo < 0)
  1271. {
  1272. do {
  1273. cFifo = GET_FIFO_SPACE(pjBase) - 6;
  1274. } while (cFifo < 0);
  1275. }
  1276. CP_WRITE(pjBase, DWG_LEN, cy);
  1277. CP_WRITE(pjBase, DWG_YDST, y);
  1278. CP_WRITE(pjBase, DWG_FXLEFT, x);
  1279. CP_WRITE(pjBase, DWG_FXRIGHT, x + pcg->cxLessOne);
  1280. CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
  1281. CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
  1282. }
  1283. xGlyph += ulCharInc;
  1284. } while (pgp++, --cGlyph != 0);
  1285. return(TRUE);
  1286. }
  1287. /******************************Public*Routine******************************\
  1288. * BOOL bCachedClippedText
  1289. *
  1290. * Draws clipped text via glyph caching.
  1291. *
  1292. \**************************************************************************/
  1293. BOOL bCachedClippedText(
  1294. PDEV* ppdev,
  1295. CACHEDFONT* pcf,
  1296. STROBJ* pstro,
  1297. CLIPOBJ* pco)
  1298. {
  1299. BOOL bRet;
  1300. BYTE* pjBase;
  1301. LONG xOffset;
  1302. LONG yOffset;
  1303. CHAR cFifo;
  1304. BOOL bMoreGlyphs;
  1305. ULONG cGlyphOriginal;
  1306. ULONG cGlyph;
  1307. BOOL bClipSet;
  1308. GLYPHPOS* pgpOriginal;
  1309. GLYPHPOS* pgp;
  1310. LONG xGlyph;
  1311. LONG yGlyph;
  1312. LONG x;
  1313. LONG y;
  1314. LONG xRight;
  1315. LONG cy;
  1316. BOOL bMore;
  1317. CLIPENUM ce;
  1318. RECTL* prclClip;
  1319. ULONG ulCharInc;
  1320. HGLYPH hg;
  1321. CACHEDGLYPH* pcg;
  1322. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  1323. "Don't expect trivial clipping in this function");
  1324. bRet = TRUE;
  1325. pjBase = ppdev->pjBase;
  1326. xOffset = ppdev->xOffset;
  1327. yOffset = ppdev->yOffset;
  1328. ulCharInc = pstro->ulCharInc;
  1329. do {
  1330. if (pstro->pgp != NULL)
  1331. {
  1332. // There's only the one batch of glyphs, so save ourselves
  1333. // a call:
  1334. pgpOriginal = pstro->pgp;
  1335. cGlyphOriginal = pstro->cGlyphs;
  1336. bMoreGlyphs = FALSE;
  1337. }
  1338. else
  1339. {
  1340. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  1341. }
  1342. if (cGlyphOriginal > 0)
  1343. {
  1344. if (pco->iDComplexity == DC_RECT)
  1345. {
  1346. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  1347. // DC_RECT, but the last time I checked, those two calls took
  1348. // more than 150 instructions to go through GDI. Since
  1349. // 'rclBounds' already contains the DC_RECT clip rectangle,
  1350. // and since it's such a common case, we'll special case it:
  1351. bMore = FALSE;
  1352. ce.c = 1;
  1353. prclClip = &pco->rclBounds;
  1354. goto SingleRectangle;
  1355. }
  1356. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  1357. do {
  1358. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  1359. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  1360. {
  1361. SingleRectangle:
  1362. // We don't always simply set the clipping rectangle here
  1363. // because it may actually end up that no text intersects
  1364. // this clip rectangle, so it would be for naught. This
  1365. // actually happens a lot when using NT's analog clock set
  1366. // to always-on-top, with a round shape:
  1367. bClipSet = FALSE;
  1368. pgp = pgpOriginal;
  1369. cGlyph = cGlyphOriginal;
  1370. // We can't yet convert to absolute coordinates by adding
  1371. // in 'xOffset' or 'yOffset' here because we have yet to
  1372. // compare the coordinates to 'prclClip':
  1373. xGlyph = pgp->ptl.x;
  1374. yGlyph = pgp->ptl.y;
  1375. // Loop through all the glyphs for this rectangle:
  1376. while (TRUE)
  1377. {
  1378. hg = pgp->hg;
  1379. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  1380. while (pcg->hg < hg)
  1381. pcg = pcg->pcgNext;
  1382. if (pcg->hg > hg)
  1383. {
  1384. // This will hopefully not be the common case (that is,
  1385. // we will have a high cache hit rate), so if I were
  1386. // writing this in Asm I would have this out-of-line
  1387. // to avoid the jump around for the common case.
  1388. // But the Pentium has branch prediction, so what the
  1389. // heck.
  1390. pcg = pcgNew(ppdev, pcf, pgp);
  1391. if (pcg == NULL)
  1392. {
  1393. bRet = FALSE;
  1394. goto AllDone;
  1395. }
  1396. cFifo = 0; // Have to reset count
  1397. }
  1398. // Space glyphs are trimmed to a height of zero, and we don't
  1399. // even have to touch the hardware for them:
  1400. cy = pcg->cy;
  1401. if (cy != 0)
  1402. {
  1403. y = pcg->ptlOrigin.y + yGlyph;
  1404. x = pcg->ptlOrigin.x + xGlyph;
  1405. xRight = pcg->cxLessOne + x;
  1406. // Do trivial rejection:
  1407. if ((prclClip->right > x) &&
  1408. (prclClip->bottom > y) &&
  1409. (prclClip->left <= xRight) &&
  1410. (prclClip->top < y + cy))
  1411. {
  1412. // Lazily set the hardware clipping:
  1413. if (!bClipSet)
  1414. {
  1415. bClipSet = TRUE;
  1416. vSetClipping(ppdev, prclClip);
  1417. cFifo = 0; // Have to initialize count
  1418. }
  1419. cFifo -= 6;
  1420. if (cFifo < 0)
  1421. {
  1422. do {
  1423. cFifo = GET_FIFO_SPACE(pjBase) - 6;
  1424. } while (cFifo < 0);
  1425. }
  1426. CP_WRITE(pjBase, DWG_LEN, cy);
  1427. CP_WRITE(pjBase, DWG_YDST, yOffset + y);
  1428. CP_WRITE(pjBase, DWG_FXLEFT, xOffset + x);
  1429. CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + xRight);
  1430. CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
  1431. CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
  1432. }
  1433. }
  1434. if (--cGlyph == 0)
  1435. break;
  1436. // Get ready for next glyph:
  1437. pgp++;
  1438. if (ulCharInc == 0)
  1439. {
  1440. xGlyph = pgp->ptl.x;
  1441. yGlyph = pgp->ptl.y;
  1442. }
  1443. else
  1444. {
  1445. xGlyph += ulCharInc;
  1446. }
  1447. }
  1448. }
  1449. } while (bMore);
  1450. }
  1451. } while (bMoreGlyphs);
  1452. AllDone:
  1453. vResetClipping(ppdev);
  1454. return(bRet);
  1455. }
  1456. /******************************Public*Routine******************************\
  1457. * BOOL DrvTextOut
  1458. *
  1459. \**************************************************************************/
  1460. BOOL DrvTextOut(
  1461. SURFOBJ* pso,
  1462. STROBJ* pstro,
  1463. FONTOBJ* pfo,
  1464. CLIPOBJ* pco,
  1465. RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
  1466. // to fill these extra rectangles (it is used
  1467. // largely for underlines). It's not a big
  1468. // performance win (GDI will call our DrvBitBlt
  1469. // to draw the extra rectangles).
  1470. RECTL* prclOpaque,
  1471. BRUSHOBJ* pboFore,
  1472. BRUSHOBJ* pboOpaque,
  1473. POINTL* pptlBrush, // Always unused, unless GCAPS_ARBRUSHOPAQUE set
  1474. MIX mix) // Always a copy mix (0x0d0d)
  1475. {
  1476. PDEV* ppdev;
  1477. LONG xOffset;
  1478. LONG yOffset;
  1479. DSURF* pdsurf;
  1480. OH* poh;
  1481. BYTE* pjBase;
  1482. ULONG cGlyph;
  1483. BOOL bMoreGlyphs;
  1484. GLYPHPOS* pgp;
  1485. BYTE iDComplexity;
  1486. CACHEDFONT* pcf;
  1487. RECTL rclOpaque;
  1488. pdsurf = (DSURF*) pso->dhsurf;
  1489. if (pdsurf->dt != DT_DIB)
  1490. {
  1491. poh = pdsurf->poh;
  1492. ppdev = (PDEV*) pso->dhpdev;
  1493. xOffset = poh->x;
  1494. yOffset = poh->y;
  1495. ppdev->xOffset = xOffset;
  1496. ppdev->yOffset = yOffset;
  1497. // The DDI spec says we'll only ever get foreground and background
  1498. // mixes of R2_COPYPEN:
  1499. ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
  1500. pjBase = ppdev->pjBase;
  1501. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  1502. if (prclOpaque != NULL)
  1503. {
  1504. ////////////////////////////////////////////////////////////
  1505. // Opaque Initialization
  1506. ////////////////////////////////////////////////////////////
  1507. if (iDComplexity == DC_TRIVIAL)
  1508. {
  1509. DrawOpaqueRect:
  1510. if (ppdev->ulBoardId == MGA_STORM)
  1511. {
  1512. CHECK_FIFO_SPACE(pjBase, 4);
  1513. if (ppdev->iBitmapFormat == BMF_24BPP)
  1514. {
  1515. CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + atype_RPL + blockm_OFF +
  1516. pattern_OFF + transc_BG_OPAQUE +
  1517. arzero_ZERO + sgnzero_ZERO + shftzero_ZERO +
  1518. solid_SOLID + bop_SRCCOPY);
  1519. }
  1520. else
  1521. {
  1522. CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + atype_RPL + blockm_ON +
  1523. pattern_OFF + transc_BG_OPAQUE +
  1524. arzero_ZERO + sgnzero_ZERO + shftzero_ZERO +
  1525. solid_SOLID + bop_SRCCOPY);
  1526. }
  1527. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, pboOpaque->iSolidColor));
  1528. ppdev->HopeFlags = (SIGN_CACHE | ARX_CACHE | PATTERN_CACHE);
  1529. CP_WRITE(pjBase, DWG_FXBNDRY,
  1530. (((prclOpaque->right + xOffset) << bfxright_SHIFT) |
  1531. ((prclOpaque->left + xOffset) & bfxleft_MASK)));
  1532. // ylength_MASK not is needed since coordinates are within range
  1533. CP_START(pjBase, DWG_YDSTLEN,
  1534. (((prclOpaque->top + yOffset ) << yval_SHIFT) |
  1535. ((prclOpaque->bottom - prclOpaque->top))));
  1536. }
  1537. else
  1538. {
  1539. CHECK_FIFO_SPACE(pjBase, 15);
  1540. CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + atype_RPL + blockm_ON +
  1541. pattern_OFF + transc_BG_OPAQUE +
  1542. bop_SRCCOPY);
  1543. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, pboOpaque->iSolidColor));
  1544. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  1545. {
  1546. CP_WRITE(pjBase, DWG_SGN, 0);
  1547. }
  1548. if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE)))
  1549. {
  1550. CP_WRITE(pjBase, DWG_AR1, 0);
  1551. CP_WRITE(pjBase, DWG_AR2, 0);
  1552. CP_WRITE(pjBase, DWG_AR4, 0);
  1553. CP_WRITE(pjBase, DWG_AR5, 0);
  1554. }
  1555. if (!(GET_CACHE_FLAGS(ppdev, PATTERN_CACHE)))
  1556. {
  1557. CP_WRITE(pjBase, DWG_SRC0, 0xFFFFFFFF);
  1558. CP_WRITE(pjBase, DWG_SRC1, 0xFFFFFFFF);
  1559. CP_WRITE(pjBase, DWG_SRC2, 0xFFFFFFFF);
  1560. CP_WRITE(pjBase, DWG_SRC3, 0xFFFFFFFF);
  1561. }
  1562. ppdev->HopeFlags = (SIGN_CACHE | ARX_CACHE | PATTERN_CACHE);
  1563. CP_WRITE(pjBase, DWG_FXLEFT, prclOpaque->left + xOffset);
  1564. CP_WRITE(pjBase, DWG_FXRIGHT, prclOpaque->right + xOffset);
  1565. CP_WRITE(pjBase, DWG_LEN, prclOpaque->bottom - prclOpaque->top);
  1566. CP_START(pjBase, DWG_YDST, prclOpaque->top + yOffset);
  1567. }
  1568. }
  1569. else if (iDComplexity == DC_RECT)
  1570. {
  1571. if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
  1572. {
  1573. prclOpaque = &rclOpaque;
  1574. goto DrawOpaqueRect;
  1575. }
  1576. }
  1577. else
  1578. {
  1579. vClipSolid(ppdev, prclOpaque, pboOpaque->iSolidColor, pco);
  1580. }
  1581. }
  1582. ////////////////////////////////////////////////////////////
  1583. // Transparent Initialization
  1584. ////////////////////////////////////////////////////////////
  1585. // Initialize the hardware for transparent text:
  1586. CHECK_FIFO_SPACE(pjBase, 4);
  1587. CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, pboFore->iSolidColor));
  1588. if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
  1589. {
  1590. CP_WRITE(pjBase, DWG_SGN, 0);
  1591. }
  1592. if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
  1593. ((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY) &&
  1594. (ppdev->flStatus & STAT_GLYPH_CACHE))
  1595. {
  1596. // Complete setup for transparent monochrome expansions from
  1597. // off-screen memory, using block mode if possible:
  1598. CP_WRITE(pjBase, DWG_DWGCTL, ppdev->ulTextControl);
  1599. CP_WRITE(pjBase, DWG_SHIFT, 0);
  1600. ppdev->HopeFlags = SIGN_CACHE;
  1601. pcf = (CACHEDFONT*) pfo->pvConsumer;
  1602. if (pcf == NULL)
  1603. {
  1604. pcf = pcfAllocateCachedFont(ppdev);
  1605. if (pcf == NULL)
  1606. return(FALSE);
  1607. pfo->pvConsumer = pcf;
  1608. }
  1609. // Use our glyph cache:
  1610. if (iDComplexity == DC_TRIVIAL)
  1611. {
  1612. do {
  1613. if (pstro->pgp != NULL)
  1614. {
  1615. // There's only the one batch of glyphs, so save ourselves
  1616. // a call:
  1617. pgp = pstro->pgp;
  1618. cGlyph = pstro->cGlyphs;
  1619. bMoreGlyphs = FALSE;
  1620. }
  1621. else
  1622. {
  1623. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  1624. }
  1625. if (cGlyph > 0)
  1626. {
  1627. if (pstro->ulCharInc == 0)
  1628. {
  1629. if (ppdev->ulBoardId == MGA_STORM)
  1630. {
  1631. if (!bMilCachedProportionalText(ppdev, pcf, pgp, cGlyph))
  1632. return(FALSE);
  1633. }
  1634. else
  1635. {
  1636. if (!bMgaCachedProportionalText(ppdev, pcf, pgp, cGlyph))
  1637. return(FALSE);
  1638. }
  1639. }
  1640. else
  1641. {
  1642. if (!bCachedFixedText(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
  1643. return(FALSE);
  1644. }
  1645. }
  1646. } while (bMoreGlyphs);
  1647. }
  1648. else
  1649. {
  1650. if (!bCachedClippedText(ppdev, pcf, pstro, pco))
  1651. return(FALSE);
  1652. }
  1653. }
  1654. else
  1655. {
  1656. DISPDBG((4, "Text too big to cache: %li x %li",
  1657. pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
  1658. // Complete setup for transparent monochrome expansions from the CPU:
  1659. CP_WRITE(pjBase, DWG_DWGCTL, (opcode_ILOAD + atype_RPL + blockm_OFF +
  1660. bop_SRCCOPY + trans_0 + bltmod_BMONO +
  1661. pattern_OFF + hbgr_SRC_WINDOWS +
  1662. transc_BG_TRANSP));
  1663. if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE)))
  1664. {
  1665. CP_WRITE(pjBase, DWG_AR5, 0);
  1666. }
  1667. ppdev->HopeFlags = SIGN_CACHE;
  1668. if (ppdev->ulBoardId == MGA_STORM)
  1669. {
  1670. vMilGeneralText(ppdev, pstro, pco);
  1671. }
  1672. else
  1673. {
  1674. vMgaGeneralText(ppdev, pstro, pco);
  1675. }
  1676. }
  1677. }
  1678. else
  1679. {
  1680. // We're drawing to a DFB we've converted to a DIB, so just call GDI
  1681. // to handle it:
  1682. return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra, prclOpaque,
  1683. pboFore, pboOpaque, pptlBrush, mix));
  1684. }
  1685. return(TRUE);
  1686. }
  1687. /******************************Public*Routine******************************\
  1688. * VOID DrvDestroyFont
  1689. *
  1690. * Note: Don't forget to export this call in 'enable.c', otherwise you'll
  1691. * get some pretty big memory leaks!
  1692. *
  1693. * We're being notified that the given font is being deallocated; clean up
  1694. * anything we've stashed in the 'pvConsumer' field of the 'pfo'.
  1695. *
  1696. \**************************************************************************/
  1697. VOID DrvDestroyFont(
  1698. FONTOBJ* pfo)
  1699. {
  1700. CACHEDFONT* pcf;
  1701. pcf = pfo->pvConsumer;
  1702. if (pcf != NULL)
  1703. {
  1704. vFreeCachedFont(pcf);
  1705. pfo->pvConsumer = NULL;
  1706. }
  1707. }
  1708. /******************************Public*Routine******************************\
  1709. * BOOL bEnableText
  1710. *
  1711. * Performs the necessary setup for the text drawing subcomponent.
  1712. *
  1713. \**************************************************************************/
  1714. BOOL bEnableText(
  1715. PDEV* ppdev)
  1716. {
  1717. OH* poh;
  1718. CACHEDFONT* pcfSentinel;
  1719. LONG cShift;
  1720. LONG cFactor;
  1721. if (ppdev->ulBoardId == MGA_STORM)
  1722. {
  1723. if (ppdev->iBitmapFormat == BMF_24BPP)
  1724. {
  1725. ppdev->ulTextControl = opcode_BITBLT + atype_RPL + blockm_OFF +
  1726. bop_SRCCOPY + trans_0 + bltmod_BMONOWF +
  1727. pattern_OFF + hbgr_SRC_EG3 +
  1728. transc_BG_TRANSP + linear_LINEAR_BITBLT;
  1729. }
  1730. else
  1731. {
  1732. ppdev->ulTextControl = opcode_BITBLT + atype_RPL + blockm_ON +
  1733. bop_SRCCOPY + trans_0 + bltmod_BMONOWF +
  1734. pattern_OFF + hbgr_SRC_EG3 +
  1735. transc_BG_TRANSP + linear_LINEAR_BITBLT;
  1736. }
  1737. }
  1738. else
  1739. {
  1740. ppdev->ulTextControl = opcode_BITBLT + atype_RPL + blockm_ON +
  1741. bop_SRCCOPY + trans_0 + bltmod_BMONO +
  1742. pattern_OFF + hbgr_SRC_EG3 +
  1743. transc_BG_TRANSP + linear_LINEAR_BITBLT;
  1744. }
  1745. poh = pohAllocate(ppdev,
  1746. NULL,
  1747. ppdev->cxMemory,
  1748. GLYPH_CACHE_HEIGHT / ppdev->cjPelSize,
  1749. FLOH_MAKE_PERMANENT);
  1750. if (poh != NULL)
  1751. {
  1752. ppdev->flStatus |= STAT_GLYPH_CACHE;
  1753. // Initialize our doubly-linked cached font list:
  1754. pcfSentinel = &ppdev->cfSentinel;
  1755. pcfSentinel->pcfNext = pcfSentinel;
  1756. pcfSentinel->pcfPrev = pcfSentinel;
  1757. // Setup the display adapter specific glyph data.
  1758. //
  1759. // The linear addresses are computed as bit addresses:
  1760. cFactor = ppdev->cjHwPel * 8;
  1761. ppdev->ulGlyphStart
  1762. = (ppdev->ulYDstOrg + poh->y * ppdev->cxMemory) * cFactor;
  1763. ppdev->ulGlyphCurrent = ppdev->ulGlyphStart;
  1764. ppdev->ulGlyphEnd
  1765. = (ppdev->ulYDstOrg + (poh->y + poh->cy) * ppdev->cxMemory) * cFactor;
  1766. }
  1767. return(TRUE);
  1768. }
  1769. /******************************Public*Routine******************************\
  1770. * VOID vDisableText
  1771. *
  1772. * Performs the necessary clean-up for the text drawing subcomponent.
  1773. *
  1774. \**************************************************************************/
  1775. VOID vDisableText(PDEV* ppdev)
  1776. {
  1777. // Here we free any stuff allocated in 'bEnableText'.
  1778. }
  1779. /******************************Public*Routine******************************\
  1780. * VOID vAssertModeText
  1781. *
  1782. * Disables or re-enables the text drawing subcomponent in preparation for
  1783. * full-screen entry/exit.
  1784. *
  1785. \**************************************************************************/
  1786. VOID vAssertModeText(
  1787. PDEV* ppdev,
  1788. BOOL bEnable)
  1789. {
  1790. // Our off-screen glyph cache will get destroyed when we switch to
  1791. // full-screen:
  1792. if (!bEnable)
  1793. {
  1794. if (ppdev->flStatus & STAT_GLYPH_CACHE)
  1795. {
  1796. vBlowGlyphCache(ppdev);
  1797. }
  1798. }
  1799. }