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.

1380 lines
41 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: textout.c
  3. *
  4. * Copyright (c) 1992-1995 Microsoft Corporation
  5. *
  6. \**************************************************************************/
  7. #include "precomp.h"
  8. //////////////////////////////////////////////////////////////////////////
  9. RECTL grclMax = { 0, 0, 0x10000, 0x10000 };
  10. // Maximal clip rectangle for trivial clipping
  11. #define GLYPH_CACHE_CX 32 // Maximal width of glyphs that we'll consider
  12. // caching
  13. #define GLYPH_CACHE_CY 32 // Maximum height of glyphs that we'll consider
  14. // caching
  15. #define GLYPH_ALLOC_SIZE 4000
  16. // Do all cached glyph memory allocations
  17. // in 4k chunks
  18. #define HGLYPH_SENTINEL ((ULONG) -1)
  19. // GDI will never give us a glyph with a
  20. // handle value of 0xffffffff, so we can
  21. // use this as a sentinel for the end of
  22. // our linked lists
  23. #define GLYPH_HASH_SIZE 256
  24. #define GLYPH_HASH_FUNC(x) ((x) & (GLYPH_HASH_SIZE - 1))
  25. typedef struct _CACHEDGLYPH CACHEDGLYPH;
  26. typedef struct _CACHEDGLYPH
  27. {
  28. CACHEDGLYPH* pcgNext; // Points to next glyph that was assigned
  29. // to the same hash table bucket
  30. HGLYPH hg; // Handles in the bucket-list are kept in
  31. // increasing order
  32. POINTL ptlOrigin; // Origin of glyph bits
  33. LONG xyWidth; // Width of the glyph in the high word
  34. ULONG* pdPixel1Rem;// Points to accelerator register used for
  35. // writing last partial dword of the glyph
  36. LONG cd; // Number of whole dwords in glyph
  37. ULONG ad[1]; // Start of glyph bits
  38. } CACHEDGLYPH; /* cg, pcg */
  39. typedef struct _GLYPHALLOC GLYPHALLOC;
  40. typedef struct _GLYPHALLOC
  41. {
  42. GLYPHALLOC* pgaNext; // Points to next glyph structure that
  43. // was allocated for this font
  44. CACHEDGLYPH acg[1]; // This array is a bit misleading, because
  45. // the CACHEDGLYPH structures are actually
  46. // variable sized
  47. } GLYPHAALLOC; /* ga, pga */
  48. typedef struct _CACHEDFONT
  49. {
  50. GLYPHALLOC* pgaChain; // Points to start of allocated memory list
  51. CACHEDGLYPH* pcgNew; // Points to where in the current glyph
  52. // allocation structure a new glyph should
  53. // be placed
  54. LONG cjAlloc; // Bytes remaining in current glyph allocation
  55. // structure
  56. CACHEDGLYPH cgSentinel; // Sentinel entry of the end of our bucket
  57. // lists, with a handle of HGLYPH_SENTINEL
  58. CACHEDGLYPH* apcg[GLYPH_HASH_SIZE];
  59. // Hash table for glyphs
  60. } CACHEDFONT; /* cf, pcf */
  61. /******************************Public*Routine******************************\
  62. * CACHEDFONT* pcfAllocateCachedFont()
  63. *
  64. * Initializes our font data structure.
  65. *
  66. \**************************************************************************/
  67. CACHEDFONT* pcfAllocateCachedFont(
  68. PDEV* ppdev)
  69. {
  70. CACHEDFONT* pcf;
  71. CACHEDGLYPH** ppcg;
  72. LONG i;
  73. pcf = EngAllocMem(FL_ZERO_MEMORY, sizeof(CACHEDFONT), ALLOC_TAG);
  74. if (pcf != NULL)
  75. {
  76. // Note that we rely on FL_ZERO_MEMORY to zero 'pgaChain' and
  77. // 'cjAlloc':
  78. pcf->cgSentinel.hg = HGLYPH_SENTINEL;
  79. // Initialize the hash table entries to all point to our sentinel:
  80. for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
  81. {
  82. *ppcg = &pcf->cgSentinel;
  83. }
  84. }
  85. return(pcf);
  86. }
  87. /******************************Public*Routine******************************\
  88. * VOID vFreeCachedFont()
  89. *
  90. * Frees all memory associated with the cache we kept for this font.
  91. *
  92. \**************************************************************************/
  93. VOID vFreeCachedFont(
  94. CACHEDFONT* pcf)
  95. {
  96. GLYPHALLOC* pga;
  97. GLYPHALLOC* pgaNext;
  98. pga = pcf->pgaChain;
  99. while (pga != NULL)
  100. {
  101. pgaNext = pga->pgaNext;
  102. EngFreeMem(pga);
  103. pga = pgaNext;
  104. }
  105. EngFreeMem(pcf);
  106. }
  107. /******************************Public*Routine******************************\
  108. * CACHEDGLYPH* pcgNew()
  109. *
  110. * Caches a new glyph.
  111. *
  112. \**************************************************************************/
  113. CACHEDGLYPH* pcgNew(
  114. PDEV* ppdev,
  115. CACHEDFONT* pcf,
  116. GLYPHPOS* pgp)
  117. {
  118. GLYPHBITS* pgb;
  119. GLYPHALLOC* pga;
  120. CACHEDGLYPH* pcg;
  121. LONG cjCachedGlyph;
  122. HGLYPH hg;
  123. LONG cyGlyph;
  124. LONG cxGlyph;
  125. POINTL ptlOrigin;
  126. LONG cjSrcWidth;
  127. BYTE jSrc;
  128. BYTE* pjSrc;
  129. BYTE* pjDst;
  130. LONG cAlign;
  131. LONG i;
  132. LONG j;
  133. LONG cTotal;
  134. LONG cRem;
  135. LONG cd;
  136. LONG iHash;
  137. CACHEDGLYPH* pcgFind;
  138. // First, calculate the amount of storage we'll need for this glyph:
  139. pgb = pgp->pgdf->pgb;
  140. cjCachedGlyph = sizeof(CACHEDGLYPH)
  141. + ((pgb->sizlBitmap.cx * pgb->sizlBitmap.cy + 7) >> 3);
  142. // Reserve an extra byte at the end for temporary usage by our pack
  143. // routine:
  144. cjCachedGlyph++;
  145. // We need to dword align it too:
  146. cjCachedGlyph = (cjCachedGlyph + 3) & ~3L;
  147. if (cjCachedGlyph > pcf->cjAlloc)
  148. {
  149. // Have to allocate a new glyph allocation structure:
  150. pga = EngAllocMem(FL_ZERO_MEMORY, GLYPH_ALLOC_SIZE, ALLOC_TAG);
  151. if (pga == NULL)
  152. {
  153. // It's safe to return at this time because we haven't
  154. // fatally altered any of our data structures:
  155. return(NULL);
  156. }
  157. // Add this allocation to the front of the allocation linked list,
  158. // so that we can free it later:
  159. pga->pgaNext = pcf->pgaChain;
  160. pcf->pgaChain = pga;
  161. // Now we've got a chunk of memory where we can store our cached
  162. // glyphs:
  163. pcf->pcgNew = &pga->acg[0];
  164. pcf->cjAlloc = GLYPH_ALLOC_SIZE - (sizeof(*pga) - sizeof(pga->acg[0]));
  165. // It would be bad if we let in any glyphs that would be bigger
  166. // than our basic allocation size:
  167. ASSERTDD(cjCachedGlyph <= GLYPH_ALLOC_SIZE, "Woah, this is one big glyph!");
  168. }
  169. pcg = pcf->pcgNew;
  170. // We only need to ensure 'dword' alignment of the next structure:
  171. pcf->pcgNew = (CACHEDGLYPH*) ((BYTE*) pcg + cjCachedGlyph);
  172. pcf->cjAlloc -= cjCachedGlyph;
  173. ASSERTDD((((ULONG_PTR) pcf->pcgNew) & 3) == 0, "pcgNew not aligned");
  174. ASSERTDD((BYTE*) pcf->pcgNew <= (BYTE*) pcf->pgaChain + GLYPH_ALLOC_SIZE,
  175. "Overrunning end of buffer");
  176. ///////////////////////////////////////////////////////////////
  177. // Pack the glyph:
  178. cyGlyph = pgb->sizlBitmap.cy;
  179. cxGlyph = pgb->sizlBitmap.cx;
  180. ptlOrigin = pgb->ptlOrigin;
  181. cjSrcWidth = (cxGlyph + 7) >> 3;
  182. cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
  183. cAlign = 0;
  184. pjSrc = pgb->aj;
  185. pjDst = (BYTE*) pcg->ad;
  186. *pjDst = 0; // Have to zero very first byte
  187. i = cyGlyph;
  188. do {
  189. j = cjSrcWidth;
  190. do {
  191. jSrc = *pjSrc;
  192. *(pjDst) |= (jSrc >> (cAlign));
  193. // Note that we may modify a byte past the end of our
  194. // destination buffer, which is why we reserved an
  195. // extra byte:
  196. *(pjDst + 1) = (jSrc << (8 - cAlign));
  197. pjSrc++;
  198. pjDst++;
  199. } while (--j != 0);
  200. pjDst--;
  201. cAlign += cRem;
  202. if (cAlign >= 8)
  203. {
  204. cAlign -= 8;
  205. pjDst++;
  206. }
  207. } while (--i != 0);
  208. ASSERTDD(pjDst <= (BYTE*) pcf->pcgNew, "Overran end of glyph");
  209. ///////////////////////////////////////////////////////////////
  210. // Initialize the glyph fields:
  211. hg = pgp->hg;
  212. pcg->hg = hg;
  213. pcg->ptlOrigin = ptlOrigin;
  214. pcg->xyWidth = cxGlyph << 16;
  215. cTotal = cxGlyph * cyGlyph;
  216. cd = (cTotal >> 5);
  217. cRem = (cTotal & 31) - 1;
  218. if (cRem < 0)
  219. {
  220. cd--;
  221. cRem = 31;
  222. ASSERTDD(cd >= 0, "Must leave at least one pixel left in glyph");
  223. }
  224. pcg->cd = cd;
  225. pcg->pdPixel1Rem
  226. = (ULONG*) CP_PIXEL1_REM_REGISTER(ppdev, ppdev->pjBase, cRem);
  227. ///////////////////////////////////////////////////////////////
  228. // Insert the glyph, in-order, into the list hanging off our hash
  229. // bucket:
  230. iHash = GLYPH_HASH_FUNC(hg);
  231. pcgFind = pcf->apcg[iHash];
  232. if (pcgFind->hg > hg)
  233. {
  234. pcf->apcg[iHash] = pcg;
  235. pcg->pcgNext = pcgFind;
  236. }
  237. else
  238. {
  239. // The sentinel will ensure that we never fall off the end of
  240. // this list:
  241. while (pcgFind->pcgNext->hg < hg)
  242. pcgFind = pcgFind->pcgNext;
  243. // 'pcgFind' now points to the entry to the entry after which
  244. // we want to insert our new node:
  245. pcg->pcgNext = pcgFind->pcgNext;
  246. pcgFind->pcgNext = pcg;
  247. }
  248. return(pcg);
  249. }
  250. /******************************Public*Routine******************************\
  251. * BOOL bCachedProportionalText
  252. *
  253. * Draws proportionally spaced glyphs via glyph caching.
  254. *
  255. \**************************************************************************/
  256. BOOL bCachedProportionalText(
  257. PDEV* ppdev,
  258. CACHEDFONT* pcf,
  259. GLYPHPOS* pgp,
  260. LONG cGlyph)
  261. {
  262. BYTE* pjBase;
  263. HGLYPH hg;
  264. CACHEDGLYPH* pcg;
  265. LONG xy;
  266. ULONG* pdPixel1Rem;
  267. LONG i;
  268. pjBase = ppdev->pjBase;
  269. CP_WOFFSET(ppdev, pjBase, ppdev->xOffset, ppdev->yOffset);
  270. // Wait for the opaquing rectangle to be finished drawing, so that
  271. // we don't hold the bus for a long time on our first write to
  272. // pixel1...
  273. CP_WAIT(ppdev, pjBase);
  274. do {
  275. hg = pgp->hg;
  276. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  277. while (pcg->hg < hg)
  278. pcg = pcg->pcgNext;
  279. if (pcg->hg > hg)
  280. {
  281. // This will hopefully not be the common case (that is,
  282. // we will have a high cache hit rate), so if I were
  283. // writing this in Asm I would have this out-of-line
  284. // to avoid the jump around for the common case.
  285. // But the Pentium has branch prediction, so what the
  286. // heck.
  287. pcg = pcgNew(ppdev, pcf, pgp);
  288. if (pcg == NULL)
  289. {
  290. CP_WOFFSET(ppdev, pjBase, 0, 0);
  291. return(FALSE);
  292. }
  293. }
  294. // The glyph's origin y-coordinate may often be negative, so we
  295. // can't compute this as follows:
  296. //
  297. // xy = (pgp->ptl.x << 16) | pgp->ptl.y;
  298. // xy += pcg->xyOrigin;
  299. xy = ((pgp->ptl.x + pcg->ptlOrigin.x) << 16) |
  300. (pgp->ptl.y + pcg->ptlOrigin.y);
  301. ASSERTDD((pgp->ptl.y + pcg->ptlOrigin.y) >= 0,
  302. "Can't have negative 'y' coordinates here");
  303. CP_WOFF_PACKED_XY0(ppdev, pjBase, xy);
  304. CP_WOFF_PACKED_XY1(ppdev, pjBase, xy);
  305. CP_WOFF_PACKED_XY2(ppdev, pjBase, xy + pcg->xyWidth);
  306. CP_START_PIXEL1(ppdev, pjBase);
  307. pdPixel1Rem = pcg->pdPixel1Rem;
  308. for (i = pcg->cd; i != 0; i--)
  309. {
  310. CP_PIXEL1(ppdev, pjBase, pcg->ad[0]);
  311. // Note that we didn't set 'pdSrc = &pcg->ad[0]' and
  312. // use that instead because by using and incrementing
  313. // 'pcg' directly, we avoid an extra 'lea' instruction:
  314. pcg = (CACHEDGLYPH*) ((ULONG*) pcg + 1);
  315. }
  316. CP_PIXEL1_VIA_REGISTER(ppdev, pdPixel1Rem, pcg->ad[0]);
  317. CP_END_PIXEL1(ppdev, pjBase);
  318. } while (pgp++, --cGlyph != 0);
  319. // I'm not sure why we have to reset the window offset when we're
  320. // done using it, but if we don't we get clipping problems on the
  321. // P9100. I suspect that the manual lies when it says that the
  322. // window offset register has no effect on clipping:
  323. CP_WOFFSET(ppdev, pjBase, 0, 0);
  324. return(TRUE);
  325. }
  326. /******************************Public*Routine******************************\
  327. * BOOL bCachedFixedText
  328. *
  329. * Draws fixed spaced glyphs via glyph caching.
  330. *
  331. \**************************************************************************/
  332. BOOL bCachedFixedText(
  333. PDEV* ppdev,
  334. CACHEDFONT* pcf,
  335. GLYPHPOS* pgp,
  336. LONG cGlyph,
  337. ULONG ulCharInc)
  338. {
  339. BYTE* pjBase;
  340. LONG xGlyph;
  341. LONG yGlyph;
  342. LONG xyGlyph;
  343. HGLYPH hg;
  344. CACHEDGLYPH* pcg;
  345. ULONG* pdPixel1Rem;
  346. LONG i;
  347. pjBase = ppdev->pjBase;
  348. // Convert to absolute coordinates:
  349. xGlyph = pgp->ptl.x + ppdev->xOffset;
  350. yGlyph = pgp->ptl.y + ppdev->yOffset;
  351. // Wait for the opaquing rectangle to be finished drawing, so that
  352. // we don't hold the bus for a long time on our first write to
  353. // pixel1...
  354. CP_WAIT(ppdev, pjBase);
  355. do {
  356. hg = pgp->hg;
  357. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  358. while (pcg->hg < hg)
  359. pcg = pcg->pcgNext;
  360. if (pcg->hg > hg)
  361. {
  362. // This will hopefully not be the common case (that is,
  363. // we will have a high cache hit rate), so if I were
  364. // writing this in Asm I would have this out-of-line
  365. // to avoid the jump around for the common case.
  366. // But the Pentium has branch prediction, so what the
  367. // heck.
  368. pcg = pcgNew(ppdev, pcf, pgp);
  369. if (pcg == NULL)
  370. return(FALSE);
  371. }
  372. xyGlyph = PACKXY(xGlyph + pcg->ptlOrigin.x,
  373. yGlyph + pcg->ptlOrigin.y);
  374. xGlyph += ulCharInc;
  375. CP_ABS_PACKED_XY0(ppdev, pjBase, xyGlyph);
  376. CP_ABS_PACKED_XY1(ppdev, pjBase, xyGlyph);
  377. CP_ABS_PACKED_XY2(ppdev, pjBase, xyGlyph + pcg->xyWidth);
  378. CP_START_PIXEL1(ppdev, pjBase);
  379. pdPixel1Rem = pcg->pdPixel1Rem;
  380. for (i = pcg->cd; i != 0; i--)
  381. {
  382. CP_PIXEL1(ppdev, pjBase, pcg->ad[0]);
  383. // Note that we didn't set 'pdSrc = &pcg->ad[0]' and
  384. // use that instead because by using and incrementing
  385. // 'pcg' directly, we avoid an extra 'lea' instruction:
  386. pcg = (CACHEDGLYPH*) ((ULONG*) pcg + 1);
  387. }
  388. CP_PIXEL1_VIA_REGISTER(ppdev, pdPixel1Rem, pcg->ad[0]);
  389. CP_END_PIXEL1(ppdev, pjBase);
  390. } while (pgp++, --cGlyph != 0);
  391. return(TRUE);
  392. }
  393. /******************************Public*Routine******************************\
  394. * BOOL bCachedClippedText
  395. *
  396. * Draws clipped text via glyph caching.
  397. *
  398. \**************************************************************************/
  399. BOOL bCachedClippedText(
  400. PDEV* ppdev,
  401. CACHEDFONT* pcf,
  402. STROBJ* pstro,
  403. CLIPOBJ* pco)
  404. {
  405. BYTE* pjBase;
  406. BOOL bRet;
  407. BOOL bMoreGlyphs;
  408. ULONG cGlyphOriginal;
  409. ULONG cGlyph;
  410. BOOL bClippingSet;
  411. GLYPHPOS* pgpOriginal;
  412. GLYPHPOS* pgp;
  413. GLYPHBITS* pgb;
  414. POINTL ptlOrigin;
  415. BOOL bMore;
  416. CLIPENUM ce;
  417. RECTL* prclClip;
  418. ULONG ulCharInc;
  419. LONG cxGlyph;
  420. LONG cyGlyph;
  421. ULONG* pulGlyph;
  422. LONG i;
  423. HGLYPH hg;
  424. CACHEDGLYPH* pcg;
  425. ULONG* pdPixel1Rem;
  426. LONG xyOrigin;
  427. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  428. "Don't expect trivial clipping in this function");
  429. bRet = TRUE;
  430. pjBase = ppdev->pjBase;
  431. ulCharInc = pstro->ulCharInc;
  432. CP_WOFFSET(ppdev, pjBase, ppdev->xOffset, ppdev->yOffset);
  433. do {
  434. if (pstro->pgp != NULL)
  435. {
  436. // There's only the one batch of glyphs, so save ourselves
  437. // a call:
  438. pgpOriginal = pstro->pgp;
  439. cGlyphOriginal = pstro->cGlyphs;
  440. bMoreGlyphs = FALSE;
  441. }
  442. else
  443. {
  444. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  445. }
  446. if (cGlyphOriginal > 0)
  447. {
  448. if (pco->iDComplexity == DC_RECT)
  449. {
  450. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  451. // DC_RECT, but the last time I checked, those two calls took
  452. // more than 150 instructions to go through GDI. Since
  453. // 'rclBounds' already contains the DC_RECT clip rectangle,
  454. // and since it's such a common case, we'll special case it:
  455. bMore = FALSE;
  456. ce.c = 1;
  457. prclClip = &pco->rclBounds;
  458. goto SingleRectangle;
  459. }
  460. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  461. do {
  462. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  463. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  464. {
  465. SingleRectangle:
  466. // We don't always simply set the clipping rectangle here
  467. // because it may actually end up that no text intersects
  468. // this clip rectangle, so it would be for naught. This
  469. // actually happens a lot when using NT's analog clock set
  470. // to always-on-top, with a round shape:
  471. bClippingSet = FALSE;
  472. pgp = pgpOriginal;
  473. cGlyph = cGlyphOriginal;
  474. pgb = pgp->pgdf->pgb;
  475. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  476. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  477. // Loop through all the glyphs for this rectangle:
  478. while (TRUE)
  479. {
  480. cxGlyph = pgb->sizlBitmap.cx;
  481. cyGlyph = pgb->sizlBitmap.cy;
  482. pulGlyph = (ULONG*) pgb->aj;
  483. // Do trivial rejection:
  484. if ((prclClip->right > ptlOrigin.x) &&
  485. (prclClip->bottom > ptlOrigin.y) &&
  486. (prclClip->left < ptlOrigin.x + cxGlyph) &&
  487. (prclClip->top < ptlOrigin.y + cyGlyph))
  488. {
  489. // Lazily set the hardware clipping:
  490. if (!bClippingSet)
  491. {
  492. bClippingSet = TRUE;
  493. CP_WAIT(ppdev, pjBase);
  494. CP_WMIN(ppdev, pjBase, prclClip->left, prclClip->top);
  495. CP_WMAX(ppdev, pjBase, prclClip->right - 1, prclClip->bottom - 1);
  496. }
  497. hg = pgp->hg;
  498. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  499. while (pcg->hg < hg)
  500. pcg = pcg->pcgNext;
  501. if (pcg->hg > hg)
  502. {
  503. // This will hopefully not be the common case (that is,
  504. // we will have a high cache hit rate), so if I were
  505. // writing this in Asm I would have this out-of-line
  506. // to avoid the jump around for the common case.
  507. // But the Pentium has branch prediction, so what the
  508. // heck.
  509. pcg = pcgNew(ppdev, pcf, pgp);
  510. if (pcg == NULL)
  511. {
  512. bRet = FALSE;
  513. goto AllDone;
  514. }
  515. }
  516. // Note that 'ptlOrigin.y' may be negative:
  517. xyOrigin = PACKXY(ptlOrigin.x, ptlOrigin.y);
  518. CP_WOFF_PACKED_XY0(ppdev, pjBase, xyOrigin);
  519. CP_WOFF_PACKED_XY1(ppdev, pjBase, xyOrigin);
  520. CP_WOFF_PACKED_XY2(ppdev, pjBase, xyOrigin + pcg->xyWidth);
  521. CP_START_PIXEL1(ppdev, pjBase);
  522. pdPixel1Rem = pcg->pdPixel1Rem;
  523. for (i = pcg->cd; i != 0; i--)
  524. {
  525. CP_PIXEL1(ppdev, pjBase, pcg->ad[0]);
  526. // Note that we didn't set 'pdSrc = &pcg->ad[0]' and
  527. // use that instead because by using and incrementing
  528. // 'pcg' directly, we avoid an extra 'lea' instruction:
  529. pcg = (CACHEDGLYPH*) ((ULONG*) pcg + 1);
  530. }
  531. CP_PIXEL1_VIA_REGISTER(ppdev, pdPixel1Rem, pcg->ad[0]);
  532. CP_END_PIXEL1(ppdev, pjBase);
  533. }
  534. if (--cGlyph == 0)
  535. break;
  536. // Get ready for next glyph:
  537. pgp++;
  538. if (ulCharInc == 0)
  539. {
  540. pgb = pgp->pgdf->pgb;
  541. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  542. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  543. }
  544. else
  545. {
  546. ptlOrigin.x += ulCharInc;
  547. }
  548. }
  549. }
  550. } while (bMore);
  551. }
  552. } while (bMoreGlyphs);
  553. AllDone:
  554. CP_WOFFSET(ppdev, pjBase, 0, 0);
  555. CP_WAIT(ppdev, pjBase);
  556. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  557. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  558. return(bRet);
  559. }
  560. /******************************Public*Routine******************************\
  561. * VOID vClipSolid
  562. *
  563. * Fills the specified rectangles with the specified colour, honouring
  564. * the requested clipping. No more than four rectangles should be passed in.
  565. * Intended for drawing the areas of the opaquing rectangle that extend
  566. * beyond the text box. The rectangles must be in left to right, top to
  567. * bottom order. Assumes there is at least one rectangle in the list.
  568. *
  569. \**************************************************************************/
  570. VOID vClipSolid(
  571. PDEV* ppdev,
  572. LONG crcl,
  573. RECTL* prcl,
  574. ULONG iColor,
  575. CLIPOBJ* pco)
  576. {
  577. BOOL bMore; // Flag for clip enumeration
  578. CLIPENUM ce; // Clip enumeration object
  579. ULONG i;
  580. ULONG j;
  581. RECTL arclTmp[4];
  582. ULONG crclTmp;
  583. RECTL* prclTmp;
  584. RECTL* prclClipTmp;
  585. LONG iLastBottom;
  586. RECTL* prclClip;
  587. RBRUSH_COLOR rbc;
  588. ASSERTDD((crcl > 0) && (crcl <= 4), "Expected 1 to 4 rectangles");
  589. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  590. "Expected a non-null clip object");
  591. rbc.iSolidColor = iColor;
  592. if (pco->iDComplexity == DC_RECT)
  593. {
  594. crcl = cIntersect(&pco->rclBounds, prcl, crcl);
  595. if (crcl != 0)
  596. {
  597. (ppdev->pfnFillSolid)(ppdev, crcl, prcl, 0xf0f0, rbc, NULL);
  598. }
  599. }
  600. else // iDComplexity == DC_COMPLEX
  601. {
  602. // Bottom of last rectangle to fill
  603. iLastBottom = prcl[crcl - 1].bottom;
  604. // Initialize the clip rectangle enumeration to right-down so we can
  605. // take advantage of the rectangle list being right-down:
  606. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  607. // Scan through all the clip rectangles, looking for intersects
  608. // of fill areas with region rectangles:
  609. do {
  610. // Get a batch of region rectangles:
  611. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
  612. // Clip the rect list to each region rect:
  613. for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
  614. {
  615. // Since the rectangles and the region enumeration are both
  616. // right-down, we can zip through the region until we reach
  617. // the first fill rect, and are done when we've passed the
  618. // last fill rect.
  619. if (prclClip->top >= iLastBottom)
  620. {
  621. // Past last fill rectangle; nothing left to do:
  622. return;
  623. }
  624. // Do intersection tests only if we've reached the top of
  625. // the first rectangle to fill:
  626. if (prclClip->bottom > prcl->top)
  627. {
  628. // We've reached the top Y scan of the first rect, so
  629. // it's worth bothering checking for intersection.
  630. // Generate a list of the rects clipped to this region
  631. // rect:
  632. prclTmp = prcl;
  633. prclClipTmp = arclTmp;
  634. for (i = crcl, crclTmp = 0; i-- != 0; prclTmp++)
  635. {
  636. // Intersect fill and clip rectangles
  637. if (bIntersect(prclTmp, prclClip, prclClipTmp))
  638. {
  639. // Add to list if anything's left to draw:
  640. crclTmp++;
  641. prclClipTmp++;
  642. }
  643. }
  644. // Draw the clipped rects
  645. if (crclTmp != 0)
  646. {
  647. (ppdev->pfnFillSolid)(ppdev, crclTmp, &arclTmp[0],
  648. 0xf0f0, rbc, NULL);
  649. }
  650. }
  651. }
  652. } while (bMore);
  653. }
  654. }
  655. /******************************Public*Routine******************************\
  656. * VOID vGeneralText
  657. *
  658. \**************************************************************************/
  659. VOID vGeneralText(
  660. PDEV* ppdev,
  661. STROBJ* pstro,
  662. CLIPOBJ* pco)
  663. {
  664. BYTE* pjBase;
  665. BYTE iDComplexity;
  666. BOOL bMoreGlyphs;
  667. ULONG cGlyphOriginal;
  668. ULONG cGlyph;
  669. GLYPHPOS* pgpOriginal;
  670. GLYPHPOS* pgp;
  671. GLYPHBITS* pgb;
  672. POINTL ptlOrigin;
  673. BOOL bMore;
  674. CLIPENUM ce;
  675. RECTL* prclClip;
  676. ULONG ulCharInc;
  677. LONG cxGlyph;
  678. LONG cyGlyph;
  679. LONG xBias;
  680. LONG cx;
  681. LONG cy;
  682. ULONG* pulGlyph;
  683. LONG cxXfer;
  684. LONG cBits;
  685. LONG xLeft;
  686. LONG yTop;
  687. LONG xRight;
  688. LONG yBottom;
  689. LONG lDelta;
  690. LONG cj;
  691. LONG i;
  692. BYTE* pjGlyph;
  693. pjBase = ppdev->pjBase;
  694. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  695. do {
  696. if (pstro->pgp != NULL)
  697. {
  698. // There's only the one batch of glyphs, so save ourselves
  699. // a call:
  700. pgpOriginal = pstro->pgp;
  701. cGlyphOriginal = pstro->cGlyphs;
  702. bMoreGlyphs = FALSE;
  703. }
  704. else
  705. {
  706. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
  707. }
  708. if (cGlyphOriginal > 0)
  709. {
  710. ulCharInc = pstro->ulCharInc;
  711. if (iDComplexity != DC_COMPLEX)
  712. {
  713. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  714. // DC_RECT, but the last time I checked, those two calls took
  715. // more than 150 instructions to go through GDI. Since
  716. // 'rclBounds' already contains the DC_RECT clip rectangle,
  717. // and since it's such a common case, we'll special case it:
  718. bMore = FALSE;
  719. ce.c = 1;
  720. if (iDComplexity == DC_TRIVIAL)
  721. prclClip = &grclMax;
  722. else
  723. prclClip = &pco->rclBounds;
  724. goto SingleRectangle;
  725. }
  726. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  727. do {
  728. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  729. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  730. {
  731. SingleRectangle:
  732. pgp = pgpOriginal;
  733. cGlyph = cGlyphOriginal;
  734. pgb = pgp->pgdf->pgb;
  735. ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
  736. ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
  737. // Loop through all the glyphs for this rectangle:
  738. while (TRUE)
  739. {
  740. cxGlyph = pgb->sizlBitmap.cx;
  741. cyGlyph = pgb->sizlBitmap.cy;
  742. pulGlyph = (ULONG*) pgb->aj;
  743. if ((prclClip->left <= ptlOrigin.x) &&
  744. (prclClip->top <= ptlOrigin.y) &&
  745. (prclClip->right >= ptlOrigin.x + cxGlyph) &&
  746. (prclClip->bottom >= ptlOrigin.y + cyGlyph))
  747. {
  748. //-----------------------------------------------------
  749. // Unclipped glyph
  750. cxXfer = (cxGlyph + 7) & ~7;
  751. cBits = (cyGlyph * cxXfer);
  752. CP_X0(ppdev, pjBase, ptlOrigin.x);
  753. CP_XY1(ppdev, pjBase, ptlOrigin.x, ptlOrigin.y);
  754. CP_X2(ppdev, pjBase, ptlOrigin.x + cxXfer);
  755. CP_WAIT(ppdev, pjBase);
  756. CP_WRIGHT(ppdev, pjBase, ptlOrigin.x + cxGlyph - 1);
  757. CP_START_PIXEL1(ppdev, pjBase);
  758. while (TRUE)
  759. {
  760. cBits -= 32;
  761. if (cBits <= 0)
  762. break;
  763. CP_PIXEL1(ppdev, pjBase, *pulGlyph);
  764. pulGlyph++;
  765. }
  766. // The 'count' for CP_PIXEL1_REM must be pre-decremented by
  767. // 1, which explains why this is '+31':
  768. cBits += 31;
  769. CP_PIXEL1_REM(ppdev, pjBase, cBits, *pulGlyph);
  770. CP_END_PIXEL1(ppdev, pjBase);
  771. }
  772. else
  773. {
  774. //-----------------------------------------------------
  775. // Clipped glyph
  776. // Find the intersection of the glyph rectangle
  777. // and the clip rectangle:
  778. xLeft = max(prclClip->left, ptlOrigin.x);
  779. yTop = max(prclClip->top, ptlOrigin.y);
  780. xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
  781. yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
  782. // Check for trivial rejection:
  783. if (((cx = xRight - xLeft) > 0) &&
  784. ((cy = yBottom - yTop) > 0))
  785. {
  786. CP_WAIT(ppdev, pjBase);
  787. CP_WRIGHT(ppdev, pjBase, xRight - 1);
  788. // Make the left edge byte-aligned in the source:
  789. xBias = (xLeft - ptlOrigin.x) & 7;
  790. if (xBias != 0)
  791. {
  792. // 'xBias' is the bit position in the monochrome glyph
  793. // bitmap of the first pixel to be lit, relative to
  794. // the start of the byte. That is, if 'xBias' is 2,
  795. // then the first unclipped pixel is represented by bit
  796. // 2 of the corresponding bitmap byte.
  797. //
  798. // Normally, the accelerator expects bit 0 to be the
  799. // first lit byte. We use the scissors so that the
  800. // first 'xBias' bits of the byte will not be displayed.
  801. //
  802. // (What we're doing is simply aligning the monochrome
  803. // blt using the hardware clipping.)
  804. CP_WLEFT(ppdev, pjBase, xLeft);
  805. xLeft -= xBias;
  806. cx += xBias;
  807. }
  808. // Make the right edge byte-aligned too:
  809. cx = (cx + 7) & ~7L;
  810. CP_X0(ppdev, pjBase, xLeft);
  811. CP_XY1(ppdev, pjBase, xLeft, yTop);
  812. CP_X2(ppdev, pjBase, xLeft + cx);
  813. CP_START_PIXEL1(ppdev, pjBase);
  814. lDelta = (cxGlyph + 7) >> 3;
  815. pjGlyph = (BYTE*) pulGlyph + (yTop - ptlOrigin.y) * lDelta
  816. + ((xLeft - ptlOrigin.x) >> 3);
  817. cj = cx >> 3;
  818. lDelta -= cj; // Make it into a true delta
  819. do {
  820. i = cj;
  821. do {
  822. CP_PIXEL1_REM(ppdev, pjBase, 7, *pjGlyph);
  823. pjGlyph++;
  824. } while (--i != 0);
  825. pjGlyph += lDelta;
  826. } while (--cy);
  827. CP_END_PIXEL1(ppdev, pjBase);
  828. if (xBias != 0)
  829. {
  830. CP_WAIT(ppdev, pjBase);
  831. CP_ABS_WMIN(ppdev, pjBase, 0, 0);
  832. }
  833. }
  834. }
  835. if (--cGlyph == 0)
  836. break;
  837. // Get ready for next glyph:
  838. pgp++;
  839. pgb = pgp->pgdf->pgb;
  840. if (ulCharInc == 0)
  841. {
  842. ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
  843. ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
  844. }
  845. else
  846. {
  847. ptlOrigin.x += ulCharInc;
  848. }
  849. }
  850. }
  851. } while (bMore);
  852. }
  853. } while (bMoreGlyphs);
  854. CP_WAIT(ppdev, pjBase);
  855. CP_ABS_WMAX(ppdev, pjBase, MAX_COORD, MAX_COORD);
  856. }
  857. /******************************Public*Routine******************************\
  858. * BOOL DrvTextOut
  859. *
  860. \**************************************************************************/
  861. BOOL DrvTextOut(
  862. SURFOBJ* pso,
  863. STROBJ* pstro,
  864. FONTOBJ* pfo,
  865. CLIPOBJ* pco,
  866. RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
  867. // to fill these extra rectangles (it is used
  868. // largely for underlines). It's not a big
  869. // performance win (GDI will call our DrvBitBlt
  870. // to draw the extra rectangles).
  871. RECTL* prclOpaque,
  872. BRUSHOBJ* pboFore,
  873. BRUSHOBJ* pboOpaque,
  874. POINTL* pptlBrush,
  875. MIX mix)
  876. {
  877. PDEV* ppdev;
  878. DSURF* pdsurf;
  879. OH* poh;
  880. BYTE* pjBase;
  881. ULONG cGlyph;
  882. BOOL bMoreGlyphs;
  883. GLYPHPOS* pgp;
  884. BYTE iDComplexity;
  885. CACHEDFONT* pcf;
  886. BOOL bTextPerfectFit;
  887. pdsurf = (DSURF*) pso->dhsurf;
  888. if (pdsurf->dt != DT_DIB)
  889. {
  890. poh = pdsurf->poh;
  891. ppdev = (PDEV*) pso->dhpdev;
  892. ppdev->xOffset = poh->x;
  893. ppdev->yOffset = poh->y;
  894. // The DDI spec says we'll only ever get foreground and background
  895. // mixes of R2_COPYPEN:
  896. ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
  897. pjBase = ppdev->pjBase;
  898. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  899. if (prclOpaque != NULL)
  900. {
  901. ////////////////////////////////////////////////////////////
  902. // Opaque Initialization
  903. ////////////////////////////////////////////////////////////
  904. // If we paint the glyphs in 'opaque' mode, we may not actually
  905. // have to draw the opaquing rectangle up-front -- the process
  906. // of laying down all the glyphs will automatically cover all
  907. // of the pixels in the opaquing rectangle.
  908. //
  909. // The condition that must be satisfied is that the text must
  910. // fit 'perfectly' such that the entire background rectangle is
  911. // covered, and none of the glyphs overlap (if the glyphs
  912. // overlap, such as for italics, they have to be drawn in
  913. // transparent mode after the opaquing rectangle is cleared).
  914. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  915. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  916. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  917. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  918. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  919. if (!(bTextPerfectFit) ||
  920. (pstro->rclBkGround.top > prclOpaque->top) ||
  921. (pstro->rclBkGround.left > prclOpaque->left) ||
  922. (pstro->rclBkGround.right < prclOpaque->right) ||
  923. (pstro->rclBkGround.bottom < prclOpaque->bottom))
  924. {
  925. if (iDComplexity == DC_TRIVIAL)
  926. {
  927. CP_METARECT(ppdev, pjBase, prclOpaque->left, prclOpaque->top);
  928. CP_METARECT(ppdev, pjBase, prclOpaque->right, prclOpaque->bottom);
  929. CP_WAIT(ppdev, pjBase);
  930. if (P9000(ppdev))
  931. {
  932. CP_BACKGROUND(ppdev, pjBase, pboOpaque->iSolidColor);
  933. CP_RASTER(ppdev, pjBase, P9000_B);
  934. }
  935. else
  936. {
  937. CP_COLOR0(ppdev, pjBase, pboOpaque->iSolidColor);
  938. CP_RASTER(ppdev, pjBase, P9100_P);
  939. }
  940. CP_START_QUAD(ppdev, pjBase);
  941. }
  942. else
  943. {
  944. vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
  945. }
  946. }
  947. if (bTextPerfectFit)
  948. {
  949. // If we have already drawn the opaquing rectangle (because
  950. // it was larger than the text rectangle), we could lay down
  951. // the glyphs in 'transparent' mode. But I've found the Weitek
  952. // to be a bit faster drawing in opaque mode, so we'll stick
  953. // with that:
  954. CP_WAIT(ppdev, pjBase);
  955. if (P9000(ppdev))
  956. {
  957. CP_BACKGROUND(ppdev, pjBase, pboOpaque->iSolidColor);
  958. CP_FOREGROUND(ppdev, pjBase, pboFore->iSolidColor);
  959. CP_RASTER(ppdev, pjBase, P9000_OPAQUE_EXPAND);
  960. }
  961. else
  962. {
  963. CP_COLOR0(ppdev, pjBase, pboOpaque->iSolidColor);
  964. CP_COLOR1(ppdev, pjBase, pboFore->iSolidColor);
  965. CP_RASTER(ppdev, pjBase, P9100_OPAQUE_EXPAND);
  966. }
  967. CP_ABS_Y3(ppdev, pjBase, 1);
  968. goto SkipTransparentInitialization;
  969. }
  970. }
  971. ////////////////////////////////////////////////////////////
  972. // Transparent Initialization
  973. ////////////////////////////////////////////////////////////
  974. // Initialize the hardware for transparent text:
  975. CP_WAIT(ppdev, pjBase);
  976. if (P9000(ppdev))
  977. {
  978. CP_FOREGROUND(ppdev, pjBase, pboFore->iSolidColor);
  979. CP_RASTER(ppdev, pjBase, P9000_TRANSPARENT_EXPAND);
  980. }
  981. else
  982. {
  983. CP_COLOR1(ppdev, pjBase, pboFore->iSolidColor);
  984. CP_RASTER(ppdev, pjBase, P9100_TRANSPARENT_EXPAND);
  985. }
  986. CP_ABS_Y3(ppdev, pjBase, 1);
  987. SkipTransparentInitialization:
  988. if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
  989. ((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
  990. {
  991. pcf = (CACHEDFONT*) pfo->pvConsumer;
  992. if (pcf == NULL)
  993. {
  994. pcf = pcfAllocateCachedFont(ppdev);
  995. if (pcf == NULL)
  996. return(FALSE);
  997. pfo->pvConsumer = pcf;
  998. }
  999. // Use our glyph cache:
  1000. if (iDComplexity == DC_TRIVIAL)
  1001. {
  1002. do {
  1003. if (pstro->pgp != NULL)
  1004. {
  1005. // There's only the one batch of glyphs, so save ourselves
  1006. // a call:
  1007. pgp = pstro->pgp;
  1008. cGlyph = pstro->cGlyphs;
  1009. bMoreGlyphs = FALSE;
  1010. }
  1011. else
  1012. {
  1013. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  1014. }
  1015. if (cGlyph > 0)
  1016. {
  1017. if (pstro->ulCharInc == 0)
  1018. {
  1019. if (!bCachedProportionalText(ppdev, pcf, pgp, cGlyph))
  1020. return(FALSE);
  1021. }
  1022. else
  1023. {
  1024. if (!bCachedFixedText(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
  1025. return(FALSE);
  1026. }
  1027. }
  1028. } while (bMoreGlyphs);
  1029. }
  1030. else
  1031. {
  1032. if (!bCachedClippedText(ppdev, pcf, pstro, pco))
  1033. return(FALSE);
  1034. }
  1035. }
  1036. else
  1037. {
  1038. DISPDBG((5, "Text too big to cache: %li x %li",
  1039. pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
  1040. vGeneralText(ppdev, pstro, pco);
  1041. }
  1042. }
  1043. else
  1044. {
  1045. // We're drawing to a DFB we've converted to a DIB, so just call GDI
  1046. // to handle it:
  1047. return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra, prclOpaque,
  1048. pboFore, pboOpaque, pptlBrush, mix));
  1049. }
  1050. return(TRUE);
  1051. }
  1052. /******************************Public*Routine******************************\
  1053. * VOID DrvDestroyFont
  1054. *
  1055. * We're being notified that the given font is being deallocated; clean up
  1056. * anything we've stashed in the 'pvConsumer' field of the 'pfo'.
  1057. *
  1058. \**************************************************************************/
  1059. VOID DrvDestroyFont(
  1060. FONTOBJ* pfo)
  1061. {
  1062. CACHEDFONT* pcf;
  1063. pcf = pfo->pvConsumer;
  1064. if (pcf != NULL)
  1065. {
  1066. vFreeCachedFont(pcf);
  1067. pfo->pvConsumer = NULL;
  1068. }
  1069. }
  1070. /******************************Public*Routine******************************\
  1071. * BOOL bEnableText
  1072. *
  1073. * Performs the necessary setup for the text drawing subcomponent.
  1074. *
  1075. \**************************************************************************/
  1076. BOOL bEnableText(
  1077. PDEV* ppdev)
  1078. {
  1079. // Our text algorithms require no initialization. If we were to
  1080. // do glyph caching, we would probably want to allocate off-screen
  1081. // memory and do a bunch of other stuff here.
  1082. return(TRUE);
  1083. }
  1084. /******************************Public*Routine******************************\
  1085. * VOID vDisableText
  1086. *
  1087. * Performs the necessary clean-up for the text drawing subcomponent.
  1088. *
  1089. \**************************************************************************/
  1090. VOID vDisableText(PDEV* ppdev)
  1091. {
  1092. // Here we free any stuff allocated in 'bEnableText'.
  1093. }
  1094. /******************************Public*Routine******************************\
  1095. * VOID vAssertModeText
  1096. *
  1097. * Disables or re-enables the text drawing subcomponent in preparation for
  1098. * full-screen entry/exit.
  1099. *
  1100. \**************************************************************************/
  1101. VOID vAssertModeText(
  1102. PDEV* ppdev,
  1103. BOOL bEnable)
  1104. {
  1105. // If we were to do off-screen glyph caching, we would probably want
  1106. // to invalidate our cache here, because it will get destroyed when
  1107. // we switch to full-screen.
  1108. }