Leaked source code of windows server 2003
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.

1923 lines
58 KiB

  1. /**********************************Module*Header********************************\
  2. *
  3. * *******************
  4. * * GDI SAMPLE CODE *
  5. * *******************
  6. *
  7. * Module Name: textout.c
  8. *
  9. * Text rendering module.
  10. *
  11. * Uses glyph expansion method.
  12. *
  13. * There are three basic methods for drawing text with hardware
  14. * acceleration:
  15. *
  16. * 1) Glyph caching -- Glyph bitmaps are cached by the accelerator
  17. * (probably in off-screen memory), and text is drawn by
  18. * referring the hardware to the cached glyph locations.
  19. *
  20. * 2) Glyph expansion -- Each individual glyph is colour-expanded
  21. * directly to the screen from the monochrome glyph bitmap
  22. * supplied by GDI.
  23. *
  24. * 3) Buffer expansion -- The CPU is used to draw all the glyphs into
  25. * a 1bpp monochrome bitmap, and the hardware is then used
  26. * to colour-expand the result.
  27. *
  28. * The fastest method depends on a number of variables, such as the
  29. * colour expansion speed, bus speed, CPU speed, average glyph size,
  30. * and average string length.
  31. *
  32. * Currently we are using glyph expansion. We will revisit this in the
  33. * next several months measuring the performance of text on the latest
  34. * hardware and the latest benchmarks.
  35. *
  36. * Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
  37. * Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
  38. ******************************************************************************/
  39. #include "precomp.h"
  40. #include "gdi.h"
  41. #include "clip.h"
  42. #include "text.h"
  43. #include "log.h"
  44. #define ALLOC_TAG ALLOC_TAG_XT2P
  45. #define GLYPH_CACHE_HEIGHT 48 // Number of scans to allocate for glyph cache,
  46. // divided by pel size
  47. #define GLYPH_CACHE_CX 64 // Maximal width of glyphs that we'll consider
  48. // caching
  49. #define GLYPH_CACHE_CY 64 // Maximum height of glyphs that we'll consider
  50. // caching
  51. #define MAX_GLYPH_SIZE ((GLYPH_CACHE_CX * GLYPH_CACHE_CY + 31) / 8)
  52. // Maximum amount of off-screen memory required
  53. // to cache a glyph, in bytes
  54. #define GLYPH_ALLOC_SIZE 8100
  55. // Do all cached glyph memory allocations
  56. // in 8k chunks
  57. #define HGLYPH_SENTINEL ((ULONG) -1)
  58. // GDI will never give us a glyph with a
  59. // handle value of 0xffffffff, so we can
  60. // use this as a sentinel for the end of
  61. // our linked lists
  62. #define GLYPH_HASH_SIZE 256
  63. #define GLYPH_HASH_FUNC(x) ((x) & (GLYPH_HASH_SIZE - 1))
  64. typedef struct _CACHEDGLYPH CACHEDGLYPH;
  65. typedef struct _CACHEDGLYPH
  66. {
  67. CACHEDGLYPH* pcgNext; // Points to next glyph that was assigned
  68. // to the same hash table bucket
  69. HGLYPH hg; // Handles in the bucket-list are kept in
  70. // increasing order
  71. POINTL ptlOrigin; // Origin of glyph bits
  72. // Device specific fields below here:
  73. LONG cx; // Glyph width
  74. LONG cy; // Glyph height
  75. LONG cd; // Number of dwords to be transferred
  76. ULONG cycx;
  77. ULONG tag;
  78. ULONG ad[1]; // Start of glyph bits
  79. } CACHEDGLYPH; /* cg, pcg */
  80. typedef struct _GLYPHALLOC GLYPHALLOC;
  81. typedef struct _GLYPHALLOC
  82. {
  83. GLYPHALLOC* pgaNext; // Points to next glyph structure that
  84. // was allocated for this font
  85. CACHEDGLYPH acg[1]; // This array is a bit misleading, because
  86. // the CACHEDGLYPH structures are actually
  87. // variable sized
  88. } GLYPHAALLOC; /* ga, pga */
  89. typedef struct _CACHEDFONT CACHEDFONT;
  90. typedef struct _CACHEDFONT
  91. {
  92. CACHEDFONT* pcfNext; // Points to next entry in CACHEDFONT list
  93. CACHEDFONT* pcfPrev; // Points to previous entry in CACHEDFONT list
  94. GLYPHALLOC* pgaChain; // Points to start of allocated memory list
  95. CACHEDGLYPH* pcgNew; // Points to where in the current glyph
  96. // allocation structure a new glyph should
  97. // be placed
  98. LONG cjAlloc; // Bytes remaining in current glyph allocation
  99. // structure
  100. CACHEDGLYPH cgSentinel; // Sentinel entry of the end of our bucket
  101. // lists, with a handle of HGLYPH_SENTINEL
  102. CACHEDGLYPH* apcg[GLYPH_HASH_SIZE];
  103. // Hash table for glyphs
  104. } CACHEDFONT; /* cf, pcf */
  105. RECTL grclMax = { 0, 0, 0x8000, 0x8000 };
  106. // Maximal clip rectangle for trivial clipping
  107. BYTE gajBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
  108. // Converts bit index to set bit
  109. //-----------------------------Private-Routine----------------------------------
  110. // pcfAllocateCachedFont
  111. // ppdev (I) - PDev pointer
  112. //
  113. // Initializes our font data structure.
  114. //
  115. //------------------------------------------------------------------------------
  116. CACHEDFONT* pcfAllocateCachedFont(
  117. PDev* ppdev)
  118. {
  119. CACHEDFONT* pcf;
  120. CACHEDGLYPH** ppcg;
  121. LONG i;
  122. pcf = (CACHEDFONT*) ENGALLOCMEM(FL_ZERO_MEMORY, sizeof(CACHEDFONT), ALLOC_TAG);
  123. if (pcf != NULL)
  124. {
  125. //
  126. // Note that we rely on FL_ZERO_MEMORY to zero 'pgaChain' and
  127. // 'cjAlloc':
  128. //
  129. pcf->cgSentinel.hg = HGLYPH_SENTINEL;
  130. //
  131. // Initialize the hash table entries to all point to our sentinel:
  132. //
  133. for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
  134. {
  135. *ppcg = &pcf->cgSentinel;
  136. }
  137. }
  138. return(pcf);
  139. }
  140. //-----------------------------Private-Routine----------------------------------
  141. // vTrimAndBitpackGlyph
  142. // pjBuf (I) - where to stick the trimmed and bit-packed glyph
  143. // pjGlyph (I) - points to the glyphs bits as given by GDI
  144. // pcxGlyph (O) - returns the trimmed width of the glyph
  145. // pcyGlyph (O) - returns the trimmed height of the glyph
  146. // pptlOrigin (O) - returns the trimmed origin of the glyph
  147. // pcj (O) - returns the number of bytes in the trimmed glyph
  148. //
  149. // This routine takes a GDI byte-aligned glyphbits definition, trims off
  150. // any unused pixels on the sides, and creates a bit-packed result that
  151. // is a natural for the S3's monochrome expansion capabilities.
  152. // "Bit-packed" is where a small monochrome bitmap is packed with no
  153. // unused bits between strides. So if GDI gives us a 16x16 bitmap to
  154. // represent '.' that really only has a 2x2 array of lit pixels, we would
  155. // trim the result to give a single byte value of 0xf0.
  156. //
  157. // Use this routine if your monochrome expansion hardware can do bit-packed
  158. // expansion (this is the fastest method). If your hardware requires byte-,
  159. // word-, or dword-alignment on monochrome expansions, use
  160. // vTrimAndPackGlyph().
  161. //
  162. //------------------------------------------------------------------------------
  163. VOID vTrimAndBitpackGlyph(
  164. BYTE* pjBuf, // Note: Routine may touch preceding byte!
  165. BYTE* pjGlyph,
  166. LONG* pcxGlyph,
  167. LONG* pcyGlyph,
  168. POINTL* pptlOrigin,
  169. LONG* pcj) // For returning the count of bytes of the result
  170. {
  171. LONG cxGlyph;
  172. LONG cyGlyph;
  173. POINTL ptlOrigin;
  174. LONG cAlign;
  175. LONG lDelta;
  176. BYTE* pj;
  177. BYTE jBit;
  178. LONG cjSrcWidth;
  179. LONG lSrcSkip;
  180. LONG lDstSkip;
  181. LONG cRem;
  182. BYTE* pjSrc;
  183. BYTE* pjDst;
  184. LONG i;
  185. LONG j;
  186. BYTE jSrc;
  187. LONG cj;
  188. ///////////////////////////////////////////////////////////////
  189. // Trim the glyph
  190. cyGlyph = *pcyGlyph;
  191. cxGlyph = *pcxGlyph;
  192. ptlOrigin = *pptlOrigin;
  193. cAlign = 0;
  194. lDelta = (cxGlyph + 7) >> 3;
  195. //
  196. // Trim off any zero rows at the bottom of the glyph:
  197. //
  198. pj = pjGlyph + cyGlyph * lDelta; // One past last byte in glyph
  199. while (cyGlyph > 0)
  200. {
  201. i = lDelta;
  202. do {
  203. if (*(--pj) != 0)
  204. goto Done_Bottom_Trim;
  205. } while (--i != 0);
  206. // The entire last row has no lit pixels, so simply skip it:
  207. cyGlyph--;
  208. }
  209. ASSERTDD(cyGlyph == 0, "cyGlyph should only be zero here");
  210. //
  211. // We found a space character. Set both dimensions to zero, so
  212. // that it's easy to special-case later:
  213. //
  214. cxGlyph = 0;
  215. Done_Bottom_Trim:
  216. //
  217. // If cxGlyph != 0, we know that the glyph has at least one non-zero
  218. // row and column. By exploiting this knowledge, we can simplify our
  219. // end-of-loop tests, because we don't have to check to see if we've
  220. // decremented either 'cyGlyph' or 'cxGlyph' to zero:
  221. //
  222. if (cxGlyph != 0)
  223. {
  224. //
  225. // Trim off any zero rows at the top of the glyph:
  226. //
  227. pj = pjGlyph; // First byte in glyph
  228. while (TRUE)
  229. {
  230. i = lDelta;
  231. do {
  232. if (*(pj++) != 0)
  233. goto Done_Top_Trim;
  234. } while (--i != 0);
  235. //
  236. // The entire first row has no lit pixels, so simply skip it:
  237. //
  238. cyGlyph--;
  239. ptlOrigin.y++;
  240. pjGlyph = pj;
  241. }
  242. Done_Top_Trim:
  243. //
  244. // Trim off any zero columns at the right edge of the glyph:
  245. //
  246. while (TRUE)
  247. {
  248. j = cxGlyph - 1;
  249. pj = pjGlyph + (j >> 3); // Last byte in first row of glyph
  250. jBit = gajBit[j & 0x7];
  251. i = cyGlyph;
  252. do {
  253. if ((*pj & jBit) != 0)
  254. goto Done_Right_Trim;
  255. pj += lDelta;
  256. } while (--i != 0);
  257. //
  258. // The entire last column has no lit pixels, so simply skip it:
  259. //
  260. cxGlyph--;
  261. }
  262. Done_Right_Trim:
  263. //
  264. // Trim off any zero columns at the left edge of the glyph:
  265. //
  266. while (TRUE)
  267. {
  268. pj = pjGlyph; // First byte in first row of glyph
  269. jBit = gajBit[cAlign];
  270. i = cyGlyph;
  271. do {
  272. if ((*pj & jBit) != 0)
  273. goto Done_Left_Trim;
  274. pj += lDelta;
  275. } while (--i != 0);
  276. //
  277. // The entire first column has no lit pixels, so simply skip it:
  278. //
  279. ptlOrigin.x++;
  280. cxGlyph--;
  281. cAlign++;
  282. if (cAlign >= 8)
  283. {
  284. cAlign = 0;
  285. pjGlyph++;
  286. }
  287. }
  288. }
  289. Done_Left_Trim:
  290. ///////////////////////////////////////////////////////////////
  291. // Pack the glyph
  292. cjSrcWidth = (cxGlyph + cAlign + 7) >> 3;
  293. lSrcSkip = lDelta - cjSrcWidth;
  294. lDstSkip = ((cxGlyph + 7) >> 3) - cjSrcWidth - 1;
  295. cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
  296. pjSrc = pjGlyph;
  297. pjDst = pjBuf;
  298. //
  299. // Zero the buffer, because we're going to 'or' stuff into it:
  300. //
  301. memset(pjBuf, 0, (cxGlyph * cyGlyph + 7) >> 3);
  302. //
  303. // cAlign used to indicate which bit in the first byte of the unpacked
  304. // glyph was the first non-zero pixel column. Now, we flip it to
  305. // indicate which bit in the packed byte will receive the next non-zero
  306. // glyph bit:
  307. //
  308. cAlign = (-cAlign) & 0x7;
  309. if (cAlign > 0)
  310. {
  311. //
  312. // It would be bad if our trimming calculations were wrong, because
  313. // we assume any bits to the left of the 'cAlign' bit will be zero.
  314. // As a result of this decrement, we will 'or' those zero bits into
  315. // whatever byte precedes the glyph bits array:
  316. //
  317. pjDst--;
  318. ASSERTDD((*pjSrc >> cAlign) == 0, "Trimmed off too many bits");
  319. }
  320. for (i = cyGlyph; i != 0; i--)
  321. {
  322. for (j = cjSrcWidth; j != 0; j--)
  323. {
  324. //
  325. // Note that we may modify a byte past the end of our
  326. // destination buffer, which is why we reserved an
  327. // extra byte:
  328. //
  329. jSrc = *pjSrc;
  330. *(pjDst) |= (jSrc >> (cAlign));
  331. *(pjDst + 1) |= (jSrc << (8 - cAlign));
  332. pjSrc++;
  333. pjDst++;
  334. }
  335. pjSrc += lSrcSkip;
  336. pjDst += lDstSkip;
  337. cAlign += cRem;
  338. if (cAlign >= 8)
  339. {
  340. cAlign -= 8;
  341. pjDst++;
  342. }
  343. }
  344. cj = ((cxGlyph * cyGlyph) + 7) >> 3;
  345. ///////////////////////////////////////////////////////////////
  346. // Post-process the packed results to account for the Permedia's
  347. // preference for big-endian data on dword transfers. If your
  348. // hardware doesn't need big-endian data, remove this step.
  349. for (pjSrc = pjBuf, i = (cj + 3) >> 2; i != 0; pjSrc += 4, i--)
  350. {
  351. jSrc = *(pjSrc);
  352. *(pjSrc) = *(pjSrc + 3);
  353. *(pjSrc + 3) = jSrc;
  354. jSrc = *(pjSrc + 1);
  355. *(pjSrc + 1) = *(pjSrc + 2);
  356. *(pjSrc + 2) = jSrc;
  357. }
  358. ///////////////////////////////////////////////////////////////
  359. // Return results
  360. *pcxGlyph = cxGlyph;
  361. *pcyGlyph = cyGlyph;
  362. *pptlOrigin = ptlOrigin;
  363. *pcj = cj;
  364. }
  365. //-----------------------------Private-Routine----------------------------------
  366. // cjPutGlyphInCache
  367. // ppdev (I) - pointer to physical device object
  368. // pcg (I) - our cache structure for this glyph
  369. // pgb (I) - GDI's glyph bits
  370. //
  371. // Figures out where to stick a glyph in the cache, copies it
  372. // there, and fills in any other data we'll need to display the glyph.
  373. //
  374. // This routine is rather device-specific, and will have to be extensively
  375. // modified for other display adapters.
  376. //
  377. // Returns the number of bytes taken by the cached glyph bits.
  378. //
  379. //------------------------------------------------------------------------------
  380. LONG cjPutGlyphInCache(
  381. PDev* ppdev,
  382. CACHEDGLYPH* pcg,
  383. GLYPHBITS* pgb)
  384. {
  385. BYTE* pjGlyph;
  386. LONG cxGlyph;
  387. LONG cyGlyph;
  388. POINTL ptlOrigin;
  389. BYTE* pjSrc;
  390. ULONG* pulDst;
  391. LONG i;
  392. LONG cPels;
  393. ULONG ulGlyphThis;
  394. ULONG ulGlyphNext;
  395. ULONG ul;
  396. ULONG ulStart;
  397. LONG cj;
  398. pjGlyph = pgb->aj;
  399. cyGlyph = pgb->sizlBitmap.cy;
  400. cxGlyph = pgb->sizlBitmap.cx;
  401. ptlOrigin = pgb->ptlOrigin;
  402. vTrimAndBitpackGlyph((BYTE*) &pcg->ad, pjGlyph, &cxGlyph, &cyGlyph,
  403. &ptlOrigin, &cj);
  404. ///////////////////////////////////////////////////////////////
  405. // Initialize the glyph fields
  406. pcg->cd = (cj + 3) >> 2;
  407. // We send an extra long to reset the BitMaskPattern register if we
  408. // have any unused bits in the last long.
  409. if(((cxGlyph * cyGlyph) & 0x1f) != 0)
  410. pcg->cd++;
  411. pcg->ptlOrigin = ptlOrigin;
  412. pcg->cx = cxGlyph;
  413. pcg->cy = cyGlyph;
  414. pcg->cycx = (cyGlyph << 16) | cxGlyph;
  415. pcg->tag = ((pcg->cd - 1) << 16) | __Permedia2TagBitMaskPattern;
  416. return(cj);
  417. }
  418. //-----------------------------Private-Routine----------------------------------
  419. // pcgNew
  420. // ppdev (I) - pointer to physical device object
  421. // pcf (I) - our cache structure for this font
  422. // pgp (I) - GDI's glyph position
  423. //
  424. // Creates a new CACHEDGLYPH structure for keeping track of the glyph in
  425. // off-screen memory. bPutGlyphInCache is called to actually put the glyph
  426. // in off-screen memory.
  427. //
  428. // This routine should be reasonably device-independent, as bPutGlyphInCache
  429. // will contain most of the code that will have to be modified for other
  430. // display adapters.
  431. //
  432. //------------------------------------------------------------------------------
  433. CACHEDGLYPH* pcgNew(
  434. PDev* ppdev,
  435. CACHEDFONT* pcf,
  436. GLYPHPOS* pgp)
  437. {
  438. GLYPHBITS* pgb;
  439. GLYPHALLOC* pga;
  440. CACHEDGLYPH* pcg;
  441. LONG cjCachedGlyph;
  442. HGLYPH hg;
  443. LONG iHash;
  444. CACHEDGLYPH* pcgFind;
  445. LONG cjGlyphRow;
  446. LONG cj;
  447. //
  448. // First, calculate the amount of storage we'll need for this glyph:
  449. //
  450. pgb = pgp->pgdf->pgb;
  451. //
  452. // The glyphs are 'word-packed':
  453. //
  454. cjGlyphRow = ((pgb->sizlBitmap.cx + 15) & ~15) >> 3;
  455. cjCachedGlyph = sizeof(CACHEDGLYPH) + (pgb->sizlBitmap.cy * cjGlyphRow);
  456. //
  457. // Reserve an extra byte at the end for temporary usage by our pack
  458. // routine:
  459. //
  460. cjCachedGlyph++;
  461. if (cjCachedGlyph > pcf->cjAlloc)
  462. {
  463. //
  464. // Have to allocate a new glyph allocation structure:
  465. //
  466. pga = (GLYPHALLOC*) ENGALLOCMEM(FL_ZERO_MEMORY, GLYPH_ALLOC_SIZE, ALLOC_TAG);
  467. if (pga == NULL)
  468. {
  469. //
  470. // It's safe to return at this time because we haven't
  471. // fatally altered any of our data structures:
  472. //
  473. return(NULL);
  474. }
  475. //
  476. // Add this allocation to the front of the allocation linked list,
  477. // so that we can free it later:
  478. //
  479. pga->pgaNext = pcf->pgaChain;
  480. pcf->pgaChain = pga;
  481. //
  482. // Now we've got a chunk of memory where we can store our cached
  483. // glyphs:
  484. //
  485. pcf->pcgNew = &pga->acg[0];
  486. pcf->cjAlloc = GLYPH_ALLOC_SIZE - (sizeof(*pga) - sizeof(pga->acg[0]));
  487. // Hack: we want to be able to safely read past the glyph data by
  488. // one DWORD. We ensure we can do this by not allocating
  489. // the last DWORD out of the glyph cache block. This is needed
  490. // by glyphs which have unused bits in the last DWORD causing
  491. // us to have to send an extra DWORD to reset the mask register.
  492. pcf->cjAlloc -= sizeof(DWORD);
  493. //
  494. // It would be bad if we let in any glyphs that would be bigger
  495. // than our basic allocation size:
  496. //
  497. ASSERTDD(cjCachedGlyph <= GLYPH_ALLOC_SIZE, "Woah, this is one big glyph!");
  498. }
  499. pcg = pcf->pcgNew;
  500. ///////////////////////////////////////////////////////////////
  501. // Insert the glyph, in-order, into the list hanging off our hash
  502. // bucket:
  503. hg = pgp->hg;
  504. pcg->hg = hg;
  505. iHash = GLYPH_HASH_FUNC(hg);
  506. pcgFind = pcf->apcg[iHash];
  507. if (pcgFind->hg > hg)
  508. {
  509. pcf->apcg[iHash] = pcg;
  510. pcg->pcgNext = pcgFind;
  511. }
  512. else
  513. {
  514. //
  515. // The sentinel will ensure that we never fall off the end of
  516. // this list:
  517. //
  518. while (pcgFind->pcgNext->hg < hg)
  519. pcgFind = pcgFind->pcgNext;
  520. //
  521. // 'pcgFind' now points to the entry to the entry after which
  522. // we want to insert our new node:
  523. //
  524. pcg->pcgNext = pcgFind->pcgNext;
  525. pcgFind->pcgNext = pcg;
  526. }
  527. cj = cjPutGlyphInCache(ppdev, pcg, pgp->pgdf->pgb);
  528. ///////////////////////////////////////////////////////////////
  529. // We now know the size taken up by the packed and trimmed glyph;
  530. // adjust the pointer to the next glyph accordingly. We only need
  531. // to ensure 'dword' alignment:
  532. cjCachedGlyph = sizeof(CACHEDGLYPH) + ((cj + 7) & ~7);
  533. pcf->pcgNew = (CACHEDGLYPH*) ((BYTE*) pcg + cjCachedGlyph);
  534. pcf->cjAlloc -= cjCachedGlyph;
  535. return(pcg);
  536. }
  537. //------------------------------------------------------------------------------
  538. // bCachedProportionalText
  539. //
  540. // Renders an array of proportional glyphs using the glyph cache
  541. //
  542. // ppdev-----pointer to physical device object
  543. // pgp-------array of glyphs to render (all members of the pcf font)
  544. // cGlyph----number of glyphs to render
  545. //
  546. // Returns TRUE if the glyphs were rendered
  547. //------------------------------------------------------------------------------
  548. BOOL bCachedProportionalText(
  549. PDev* ppdev,
  550. CACHEDFONT* pcf,
  551. GLYPHPOS* pgp,
  552. LONG cGlyph)
  553. {
  554. HGLYPH hg;
  555. CACHEDGLYPH* pcg;
  556. LONG x;
  557. LONG cy;
  558. ULONG i;
  559. ULONG* pd;
  560. ULONG* pBuffer;
  561. ULONG* pReservationEnd;
  562. ULONG* pBufferEnd;
  563. BOOL bRet = TRUE; // assume success
  564. InputBufferStart(ppdev, 2, &pBuffer, &pBufferEnd, &pReservationEnd);
  565. // Reset BitMaskPattern in case there are some unused bits from
  566. // a previous command.
  567. //@@BEGIN_DDKSPLIT
  568. // TODO: fix all other uses of SYNC_ON_BIT_MASK so that we don't
  569. // need to always do this here
  570. //@@END_DDKSPLIT
  571. pBuffer[0] = __Permedia2TagBitMaskPattern;
  572. //@@BEGIN_DDKSPLIT
  573. // TODO: remove the setting of pBuffer[1] (it can be garbage) when
  574. // we implement the scratch buffer for handling the non-DMA
  575. // case.
  576. //@@END_DDKSPLIT
  577. pBuffer[1] = 0;
  578. pBuffer = pReservationEnd;
  579. do {
  580. //
  581. // First lookup the glyph in our cache
  582. //
  583. hg = pgp->hg;
  584. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  585. while (pcg->hg < hg)
  586. pcg = pcg->pcgNext; // Traverse collision list, if any
  587. if (pcg->hg > hg)
  588. {
  589. //
  590. // This will hopefully not be the common case (that is,
  591. // we will have a high cache hit rate), so if I were
  592. // writing this in Asm I would have this out-of-line
  593. // to avoid the jump around for the common case.
  594. // But the Pentium has branch prediction, so what the
  595. // heck.
  596. //
  597. pcg = pcgNew(ppdev, pcf, pgp);
  598. if (pcg == NULL)
  599. {
  600. bRet= FALSE;
  601. goto done;
  602. }
  603. }
  604. //
  605. // Space glyphs are trimmed to a height of zero, and we don't
  606. // even have to touch the hardware for them:
  607. //
  608. cy = pcg->cy;
  609. if (cy > 0)
  610. {
  611. ASSERTDD((pcg->cd <= (MAX_P2_FIFO_ENTRIES - 5)) &&
  612. (MAX_GLYPH_SIZE / 4) <= (MAX_P2_FIFO_ENTRIES - 5),
  613. "Ack, glyph too large for FIFO!");
  614. //
  615. // NOTE: We send an extra bit mask pattern to reset the register.
  616. // If we don't do this then a subsequent SYNC_ON_BIT_MASK
  617. // will use these unused bits.
  618. //
  619. //@@BEGIN_DDKSPLIT
  620. // TODO: We could further optimize this by noting that we only
  621. // have to send the extra bit mask pattern DWORD if there
  622. // are unused bits. We could also play with the height
  623. // width to make it so that this case becomes more common
  624. //
  625. //@@END_DDKSPLIT
  626. ULONG ulLongs = 7 + pcg->cd;
  627. InputBufferContinue(ppdev, ulLongs, &pBuffer, &pBufferEnd, &pReservationEnd);
  628. pBuffer[0] = __Permedia2TagRectangleOrigin;
  629. pBuffer[1] = ((pgp->ptl.y + pcg->ptlOrigin.y) << 16) |
  630. (pgp->ptl.x + pcg->ptlOrigin.x);
  631. pBuffer[2] = __Permedia2TagRectangleSize;
  632. pBuffer[3] = pcg->cycx;
  633. pBuffer[4] = __Permedia2TagRender;
  634. pBuffer[5] = __RENDER_RECTANGLE_PRIMITIVE | __RENDER_SYNC_ON_BIT_MASK
  635. | __RENDER_INCREASE_X | __RENDER_INCREASE_Y;
  636. pBuffer[6] = pcg->tag;
  637. pBuffer += 7;
  638. pd = &pcg->ad[0];
  639. do
  640. {
  641. *pBuffer++ = *pd++;
  642. } while(pBuffer < pReservationEnd);
  643. }
  644. pgp++;
  645. } while (--cGlyph != 0);
  646. done:
  647. InputBufferCommit(ppdev, pBuffer);
  648. return(bRet);
  649. }
  650. //------------------------------------------------------------------------------
  651. // bCachedProportionalText
  652. //
  653. // Renders an array of clipped glyphs using the glyph cache
  654. //
  655. // ppdev----------pointer to physical device object
  656. // pcf------------pointer to cached font structure
  657. // pgpOriginal----array of glyphs to render (all members of the pcf font)
  658. // cGlyphOriginal-number of glyphs to render
  659. // ulCharInc------increment for fixed space fonts
  660. // pco------------clip object
  661. //
  662. // Returns TRUE if the glyphs were rendered
  663. //------------------------------------------------------------------------------
  664. BOOL bCachedClippedText(
  665. PDev* ppdev,
  666. CACHEDFONT* pcf,
  667. GLYPHPOS* pgpOriginal,
  668. LONG cGlyphOriginal,
  669. ULONG ulCharInc,
  670. CLIPOBJ* pco)
  671. {
  672. BOOL bRet;
  673. BYTE* pjMmBase;
  674. BOOL bClippingSet;
  675. LONG cGlyph;
  676. GLYPHPOS* pgp;
  677. LONG xGlyph;
  678. LONG yGlyph;
  679. LONG x;
  680. LONG y;
  681. LONG xRight;
  682. LONG cy;
  683. BOOL bMore;
  684. ClipEnum ce;
  685. RECTL* prclClip;
  686. HGLYPH hg;
  687. CACHEDGLYPH* pcg;
  688. BYTE iDComplexity;
  689. ULONG i;
  690. ULONG* pd;
  691. ULONG* pBuffer;
  692. PERMEDIA_DECL; // Declare and initialize local variables like
  693. // 'permediaInfo' and 'pPermedia'
  694. bRet = TRUE;
  695. iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
  696. if (cGlyphOriginal > 0)
  697. {
  698. if (iDComplexity != DC_COMPLEX)
  699. {
  700. //
  701. // We could call 'cEnumStart' and 'bEnum' when the clipping is
  702. // DC_RECT, but the last time I checked, those two calls took
  703. // more than 150 instructions to go through GDI. Since
  704. // 'rclBounds' already contains the DC_RECT clip rectangle,
  705. // and since it's such a common case, we'll special case it:
  706. //
  707. bMore = FALSE;
  708. ce.c = 1;
  709. if (iDComplexity == DC_TRIVIAL)
  710. prclClip = &grclMax;
  711. else
  712. prclClip = &pco->rclBounds;
  713. goto SingleRectangle;
  714. }
  715. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
  716. do {
  717. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
  718. for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
  719. {
  720. SingleRectangle:
  721. //
  722. // We don't always simply set the clipping rectangle here
  723. // because it may actually end up that no text intersects
  724. // this clip rectangle, so it would be for naught. This
  725. // actually happens a lot when there is complex clipping.
  726. //
  727. bClippingSet = FALSE;
  728. pgp = pgpOriginal;
  729. cGlyph = cGlyphOriginal;
  730. xGlyph = pgp->ptl.x;
  731. yGlyph = pgp->ptl.y;
  732. //
  733. // Loop through all the glyphs for this rectangle:
  734. //
  735. while (TRUE)
  736. {
  737. hg = pgp->hg;
  738. pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
  739. while (pcg->hg < hg)
  740. pcg = pcg->pcgNext;
  741. if (pcg->hg > hg)
  742. {
  743. //
  744. // This will hopefully not be the common case (that is,
  745. // we will have a high cache hit rate), so if I were
  746. // writing this in Asm I would have this out-of-line
  747. // to avoid the jump around for the common case.
  748. // But the Pentium has branch prediction, so what the
  749. // heck.
  750. //
  751. pcg = pcgNew(ppdev, pcf, pgp);
  752. if (pcg == NULL)
  753. {
  754. bRet = FALSE;
  755. goto AllDone;
  756. }
  757. }
  758. //
  759. // Space glyphs are trimmed to a height of zero, and we don't
  760. // even have to touch the hardware for them:
  761. //
  762. cy = pcg->cy;
  763. if (cy > 0)
  764. {
  765. y = pcg->ptlOrigin.y + yGlyph;
  766. x = pcg->ptlOrigin.x + xGlyph;
  767. xRight = pcg->cx + x;
  768. //
  769. // Do trivial rejection:
  770. //
  771. if ((prclClip->right > x) &&
  772. (prclClip->bottom > y) &&
  773. (prclClip->left < xRight) &&
  774. (prclClip->top < y + cy))
  775. {
  776. //
  777. // Lazily set the hardware clipping:
  778. //
  779. if ((iDComplexity != DC_TRIVIAL) && (!bClippingSet))
  780. {
  781. bClippingSet = TRUE;
  782. InputBufferReserve(ppdev, 6, &pBuffer);
  783. pBuffer[0] = __Permedia2TagScissorMode;
  784. pBuffer[1] = USER_SCISSOR_ENABLE |
  785. SCREEN_SCISSOR_DEFAULT;
  786. pBuffer[2] = __Permedia2TagScissorMinXY;
  787. pBuffer[3] = (prclClip->top << 16) | prclClip->left;
  788. pBuffer[4] = __Permedia2TagScissorMaxXY;
  789. pBuffer[5] = (prclClip->bottom << 16) | prclClip->right;
  790. pBuffer += 6;
  791. InputBufferCommit(ppdev, pBuffer);
  792. }
  793. InputBufferReserve(ppdev, 10, &pBuffer);
  794. pBuffer[0] = __Permedia2TagCount;
  795. pBuffer[1] = cy;
  796. pBuffer[2] = __Permedia2TagStartY;
  797. pBuffer[3] = INTtoFIXED(y);
  798. pBuffer[4] = __Permedia2TagStartXDom;
  799. pBuffer[5] = INTtoFIXED(x);
  800. pBuffer[6] = __Permedia2TagStartXSub;
  801. pBuffer[7] = INTtoFIXED(xRight);
  802. pBuffer[8] = __Permedia2TagRender;
  803. pBuffer[9] = __RENDER_TRAPEZOID_PRIMITIVE
  804. | __RENDER_SYNC_ON_BIT_MASK;
  805. pBuffer += 10;
  806. InputBufferCommit(ppdev, pBuffer);
  807. InputBufferReserve(ppdev, pcg->cd + 1, &pBuffer);
  808. *pBuffer++ = (pcg->cd - 1) << 16 | __Permedia2TagBitMaskPattern;
  809. pd = &pcg->ad[0];
  810. i = pcg->cd;
  811. do {
  812. *pBuffer++ = *pd;
  813. pd++;
  814. } while (--i != 0);
  815. InputBufferCommit(ppdev, pBuffer);
  816. }
  817. }
  818. if (--cGlyph == 0)
  819. break;
  820. //
  821. // Get ready for next glyph:
  822. //
  823. pgp++;
  824. if (ulCharInc == 0)
  825. {
  826. xGlyph = pgp->ptl.x;
  827. yGlyph = pgp->ptl.y;
  828. }
  829. else
  830. {
  831. xGlyph += ulCharInc;
  832. }
  833. }
  834. }
  835. } while (bMore);
  836. }
  837. AllDone:
  838. if (iDComplexity != DC_TRIVIAL)
  839. {
  840. //
  841. // Reset the clipping.
  842. //
  843. InputBufferReserve(ppdev, 2, &pBuffer);
  844. pBuffer[0] = __Permedia2TagScissorMode;
  845. pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
  846. pBuffer += 2;
  847. InputBufferCommit(ppdev, pBuffer);
  848. }
  849. return(bRet);
  850. }
  851. //-----------------------------Private-Routine----------------------------------
  852. // vClipSolid
  853. // ppdev (I) - pointer to physical device object
  854. // prcl (I) - number of rectangles
  855. // prcl (I) - array of rectangles
  856. // iColor (I) - the solid fill color
  857. // pco (I) - pointer to the clip region object
  858. //
  859. // Fill a series of opaquing rectangles clipped by pco with the given solid
  860. // color. This function should only be called when the clipping operation
  861. // is non-trivial.
  862. //
  863. //------------------------------------------------------------------------------
  864. VOID vClipSolid(
  865. PDev* ppdev,
  866. Surf * psurf,
  867. LONG crcl,
  868. RECTL* prcl,
  869. ULONG iColor,
  870. CLIPOBJ* pco)
  871. {
  872. BOOL bMore;
  873. ClipEnum ce;
  874. ULONG i;
  875. ULONG j;
  876. RECTL arclTmp[4];
  877. ULONG crclTmp;
  878. RECTL* prclTmp;
  879. RECTL* prclClipTmp;
  880. LONG iLastBottom;
  881. RECTL* prclClip;
  882. RBrushColor rbc;
  883. GFNPB pb;
  884. ASSERTDD((crcl > 0) && (crcl <= 4),
  885. "vClipSolid: expected 1 to 4 rectangles");
  886. ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
  887. "vClipColid: expected a non-null clip object");
  888. pb.ppdev = ppdev;
  889. pb.psurfDst = psurf;
  890. pb.solidColor = iColor;
  891. if (pco->iDComplexity == DC_RECT)
  892. {
  893. crcl = cIntersect(&pco->rclBounds, prcl, crcl);
  894. if (crcl != 0)
  895. {
  896. pb.lNumRects = crcl;
  897. pb.pRects = prcl;
  898. ppdev->pgfnSolidFill(&pb);
  899. }
  900. }
  901. else // iDComplexity == DC_COMPLEX
  902. {
  903. // Bottom of last rectangle to fill
  904. iLastBottom = prcl[crcl - 1].bottom;
  905. // Initialize the clip rectangle enumeration to right-down so we can
  906. // take advantage of the rectangle list being right-down:
  907. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
  908. // Scan through all the clip rectangles, looking for intersects
  909. // of fill areas with region rectangles:
  910. do
  911. {
  912. // Get a batch of region rectangles:
  913. bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG *)&ce);
  914. // Clip the rect list to each region rect:
  915. for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
  916. {
  917. // Since the rectangles and the region enumeration are both
  918. // right-down, we can zip through the region until we reach
  919. // the first fill rect, and are done when we've passed the
  920. // last fill rect.
  921. if (prclClip->top >= iLastBottom)
  922. {
  923. // Past last fill rectangle; nothing left to do:
  924. return;
  925. }
  926. // Do intersection tests only if we've reached the top of
  927. // the first rectangle to fill:
  928. if (prclClip->bottom > prcl->top)
  929. {
  930. // We've reached the top Y scan of the first rect, so
  931. // it's worth bothering checking for intersection.
  932. // Generate a list of the rects clipped to this region
  933. // rect:
  934. prclTmp = prcl;
  935. prclClipTmp = arclTmp;
  936. for (i = crcl, crclTmp = 0; i-- != 0; prclTmp++)
  937. {
  938. // Intersect fill and clip rectangles
  939. if (bIntersect(prclTmp, prclClip, prclClipTmp))
  940. {
  941. // Add to list if anything's left to draw:
  942. crclTmp++;
  943. prclClipTmp++;
  944. }
  945. }
  946. // Draw the clipped rects
  947. if (crclTmp != 0)
  948. {
  949. pb.lNumRects = crclTmp;
  950. pb.pRects = &arclTmp[0];
  951. ppdev->pgfnSolidFill(&pb);
  952. }
  953. }
  954. }
  955. }
  956. while (bMore);
  957. }
  958. }// vClipSolid()
  959. //-----------------------------Public-Routine-----------------------------------
  960. // DrvTextOut
  961. // pso (I) - pointer to surface object to render to
  962. // pstro (I) - pointer to the string object to be rendered
  963. // pfo (I) - pointer to the font object
  964. // pco (I) - pointer to the clip region object
  965. // prclExtra (I) - If we had set GCAPS_HORIZSTRIKE, we would have to
  966. // fill these extra rectangles (it is used largely
  967. // for underlines). It's not a big performance win
  968. // (GDI will call our DrvBitBlt to draw these).
  969. // prclOpaque (I) - pointer to the opaque background rectangle
  970. // pboFore (I) - pointer to the foreground brush object
  971. // pboOpaque (I) - ptr to the brush for the opaque background rectangle
  972. // pptlBrush (I) - pointer to the brush origin, Always unused, unless
  973. // GCAPS_ARBRUSHOPAQUE set
  974. // mix (I) - should always be a COPY operation
  975. //
  976. // Returns TRUE if the text has been rendered
  977. //
  978. //------------------------------------------------------------------------------
  979. BOOL
  980. DrvTextOut(SURFOBJ* pso,
  981. STROBJ* pstro,
  982. FONTOBJ* pfo,
  983. CLIPOBJ* pco,
  984. RECTL* prclExtra,
  985. RECTL* prclOpaque,
  986. BRUSHOBJ* pboFore,
  987. BRUSHOBJ* pboOpaque,
  988. POINTL* pptlBrush,
  989. MIX mix)
  990. {
  991. PDev* ppdev;
  992. Surf* psurf;
  993. ULONG cGlyph;
  994. BOOL bMoreGlyphs;
  995. GLYPHPOS* pgp;
  996. BYTE iDComplexity;
  997. RECTL rclOpaque;
  998. BOOL bRet = TRUE;
  999. CACHEDFONT* pcf;
  1000. PULONG pBuffer;
  1001. ULONG ulColor;
  1002. psurf = (Surf*)pso->dhsurf;
  1003. ppdev = (PDev*)pso->dhpdev;
  1004. //@@BEGIN_DDKSPLIT
  1005. #if MULTITHREADED
  1006. if(ppdev->ulLockCount)
  1007. {
  1008. DBG_GDI((MT_LOG_LEVEL, "DrvTextOut: re-entry! %d", ppdev->ulLockCount));
  1009. }
  1010. EngAcquireSemaphore(ppdev->hsemLock);
  1011. ppdev->ulLockCount++;
  1012. #endif
  1013. //@@END_DDKSPLIT
  1014. vCheckGdiContext(ppdev);
  1015. //
  1016. // The DDI spec says we'll only ever get foreground and background mixes
  1017. // of R2_COPYPEN:
  1018. //
  1019. ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
  1020. ASSERTDD(pco != NULL, "Expect non-null pco");
  1021. ASSERTDD(psurf->flags & SF_VM, "expected video memory destination");
  1022. iDComplexity = pco->iDComplexity;
  1023. //
  1024. //glyph rendering initialisation
  1025. //
  1026. InputBufferReserve(ppdev, 16, &pBuffer);
  1027. pBuffer[0] = __Permedia2TagFBReadMode;
  1028. pBuffer[1] = PM_FBREADMODE_PARTIAL(psurf->ulPackedPP) |
  1029. PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE);
  1030. if(pfo->flFontType & FO_GRAY16)
  1031. pBuffer[1] |= PM_FBREADMODE_READDEST( __PERMEDIA_ENABLE);
  1032. pBuffer[2] = __Permedia2TagLogicalOpMode;
  1033. pBuffer[3] = __PERMEDIA_CONSTANT_FB_WRITE;
  1034. pBuffer[4] = __Permedia2TagFBWindowBase;
  1035. pBuffer[5] = psurf->ulPixOffset;
  1036. pBuffer += 6;
  1037. if ( prclOpaque != NULL )
  1038. {
  1039. //
  1040. // Opaque Initialization
  1041. //
  1042. if ( iDComplexity == DC_TRIVIAL )
  1043. {
  1044. DrawOpaqueRect:
  1045. //@@BEGIN_DDKSPLIT
  1046. // TODO: use color expansion macro
  1047. //@@END_DDKSPLIT
  1048. ulColor = pboOpaque->iSolidColor;
  1049. if ( ppdev->cPelSize < 2 )
  1050. {
  1051. ulColor |= ulColor << 16;
  1052. if ( ppdev->cPelSize == 0 )
  1053. {
  1054. ulColor |= ulColor << 8;
  1055. }
  1056. }
  1057. //
  1058. // Check the block colour
  1059. //
  1060. pBuffer[0] = __Permedia2TagFBBlockColor;
  1061. pBuffer[1] = ulColor;
  1062. pBuffer[2] = __Permedia2TagRectangleOrigin;
  1063. pBuffer[3] = RECTORIGIN_YX(prclOpaque->top,prclOpaque->left);
  1064. pBuffer[4] = __Permedia2TagRectangleSize;
  1065. pBuffer[5] = ((prclOpaque->bottom - prclOpaque->top) << 16) |
  1066. (prclOpaque->right - prclOpaque->left);
  1067. pBuffer[6] = __Permedia2TagRender;
  1068. pBuffer[7] = __RENDER_FAST_FILL_ENABLE
  1069. | __RENDER_RECTANGLE_PRIMITIVE
  1070. | __RENDER_INCREASE_X
  1071. | __RENDER_INCREASE_Y;
  1072. pBuffer += 8;
  1073. }
  1074. else if ( iDComplexity == DC_RECT )
  1075. {
  1076. if ( bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque) )
  1077. {
  1078. prclOpaque = &rclOpaque;
  1079. goto DrawOpaqueRect;
  1080. }
  1081. }
  1082. else
  1083. {
  1084. //
  1085. // vClipSolid modifies the rect list we pass in but prclOpaque
  1086. // is probably a GDI structure so don't change it. This is also
  1087. // necessary for multi-headed drivers.
  1088. //
  1089. RECTL tmpOpaque = *prclOpaque;
  1090. InputBufferCommit(ppdev, pBuffer);
  1091. vClipSolid(ppdev, psurf, 1, &tmpOpaque,
  1092. pboOpaque->iSolidColor, pco);
  1093. // restore logicalOpMode
  1094. //@@BEGIN_DDKSPLIT
  1095. // TODO: This is a hack, we can only assume that the state
  1096. // setup above is still valid except for logical op mode
  1097. // and the FBReadMode for the FO_GRAY16 case only.
  1098. //
  1099. // We should rethink how to deal with the Permedia2
  1100. // state throughout the code.
  1101. //@@END_DDKSPLIT
  1102. if(pfo->flFontType & FO_GRAY16)
  1103. {
  1104. InputBufferReserve(ppdev, 2, &pBuffer);
  1105. pBuffer[0] = __Permedia2TagFBReadMode;
  1106. pBuffer[1] = PM_FBREADMODE_PARTIAL(psurf->ulPackedPP) |
  1107. PM_FBREADMODE_PACKEDDATA(__PERMEDIA_DISABLE) |
  1108. PM_FBREADMODE_READDEST(__PERMEDIA_ENABLE);
  1109. pBuffer += 2;
  1110. InputBufferCommit(ppdev, pBuffer);
  1111. }
  1112. InputBufferReserve(ppdev, 4, &pBuffer);
  1113. pBuffer[0] = __Permedia2TagLogicalOpMode;
  1114. pBuffer[1] = __PERMEDIA_CONSTANT_FB_WRITE;
  1115. pBuffer += 2;
  1116. }
  1117. }
  1118. // if ( prclOpaque != NULL )
  1119. //
  1120. // Transparent Initialization
  1121. //
  1122. if(pfo->flFontType & FO_GRAY16)
  1123. {
  1124. ASSERTDD(ppdev->cPelSize != 0,
  1125. "DrvTextOut: unexpected aatext when in 8bpp");
  1126. ulColor = pboFore->iSolidColor;
  1127. if(ppdev->cPelSize == 1)
  1128. {
  1129. ULONG blue = (ulColor & 0x1f);
  1130. ULONG green = (ulColor >> 5) & 0x3f;
  1131. ULONG red = (ulColor >> 11) & 0x1f;
  1132. blue = (blue << 3) | (blue >> 2);
  1133. green = (green << 2) | (green >> 4);
  1134. red = (red << 3) | (red >> 2);
  1135. ulColor = (blue << 16) | (green << 8) | red;
  1136. }
  1137. else
  1138. {
  1139. ulColor = SWAP_BR(ulColor);
  1140. }
  1141. pBuffer[0] = __Permedia2TagConstantColor;
  1142. pBuffer[1] = 0xff000000 | ulColor;
  1143. pBuffer += 2;
  1144. }
  1145. else
  1146. {
  1147. //
  1148. // glyph foreground will be rendered using bitmask downloads
  1149. //
  1150. pBuffer[0] = __Permedia2TagFBWriteData;
  1151. pBuffer[1] = pboFore->iSolidColor;
  1152. pBuffer += 2;
  1153. }
  1154. InputBufferCommit(ppdev, pBuffer);
  1155. STROBJ_vEnumStart(pstro);
  1156. do
  1157. {
  1158. if ( pstro->pgp != NULL )
  1159. {
  1160. //
  1161. // There's only the one batch of glyphs, so save ourselves a
  1162. // call
  1163. //
  1164. pgp = pstro->pgp;
  1165. cGlyph = pstro->cGlyphs;
  1166. bMoreGlyphs = FALSE;
  1167. }
  1168. else
  1169. {
  1170. bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
  1171. }
  1172. if ( cGlyph > 0 )
  1173. {
  1174. //
  1175. // We only cache reasonable-sized glyphs:
  1176. //
  1177. if ( pfo->flFontType & FO_GRAY16)
  1178. {
  1179. bRet = bClippedAAText(ppdev, pgp, cGlyph,
  1180. pstro->ulCharInc, pco);
  1181. }
  1182. else if ( ( pfo->cxMax <= GLYPH_CACHE_CX ) &&
  1183. ( pstro->rclBkGround.bottom - pstro->rclBkGround.top
  1184. <= GLYPH_CACHE_CY ) )
  1185. {
  1186. pcf = (CACHEDFONT*) pfo->pvConsumer;
  1187. if (pcf == NULL)
  1188. {
  1189. pcf = pcfAllocateCachedFont(ppdev);
  1190. if (pcf == NULL)
  1191. {
  1192. DBG_GDI((0, "failing to allocate cached font"));
  1193. InputBufferFlush(ppdev);
  1194. //@@BEGIN_DDKSPLIT
  1195. #if MULTITHREADED
  1196. ppdev->ulLockCount--;
  1197. EngReleaseSemaphore(ppdev->hsemLock);
  1198. #endif
  1199. //@@END_DDKSPLIT
  1200. return(FALSE);
  1201. }
  1202. pfo->pvConsumer = pcf;
  1203. }
  1204. //
  1205. // We special case trivially clipped proportional text because
  1206. // that happens so frequently, and route everything else
  1207. // the generic clipped routine. I used to also special case
  1208. // trivially clipped, fixed text, but it happens so
  1209. // infrequently there's no point.
  1210. //
  1211. if ( (iDComplexity == DC_TRIVIAL ) && ( pstro->ulCharInc == 0 ) )
  1212. {
  1213. bRet = bCachedProportionalText(ppdev, pcf, pgp, cGlyph);
  1214. }
  1215. else
  1216. {
  1217. bRet = bCachedClippedText(ppdev, pcf, pgp, cGlyph,
  1218. pstro->ulCharInc, pco);
  1219. }
  1220. }
  1221. else
  1222. {
  1223. bRet = bClippedText(ppdev, pgp, cGlyph,
  1224. pstro->ulCharInc, pco);
  1225. }
  1226. }
  1227. } while ( bMoreGlyphs && bRet );
  1228. InputBufferFlush(ppdev);
  1229. //@@BEGIN_DDKSPLIT
  1230. #if MULTITHREADED
  1231. ppdev->ulLockCount--;
  1232. EngReleaseSemaphore(ppdev->hsemLock);
  1233. #endif
  1234. //@@END_DDKSPLIT
  1235. return (bRet);
  1236. }// DrvTextOut()
  1237. //-----------------------------Public-Routine-----------------------------------
  1238. // bEnableText
  1239. // ppdev (I) - pointer to physical device object
  1240. //
  1241. // Always true for success.
  1242. //
  1243. // Peform any necessary initialization of PPDEV state or hardware state
  1244. // to enable accelerated text.
  1245. //
  1246. // If we were using a glyph cache, we would initialize the necessary data
  1247. // structures here.
  1248. //
  1249. //------------------------------------------------------------------------------
  1250. BOOL
  1251. bEnableText(PDev* ppdev)
  1252. {
  1253. DBG_GDI((6, "bEnableText"));
  1254. return (TRUE);
  1255. }// bEnableText()
  1256. //-----------------------------Public-Routine-----------------------------------
  1257. // vDisableText
  1258. // ppdev (I) - pointer to physical device object
  1259. //
  1260. //
  1261. // Disable hardware text accelerations. This may require changes to hardware
  1262. // state. We should also free any resources allocated in bEnableText and
  1263. // make the neccesary changes to the PPDEV state to reflect that text
  1264. // accelerations have been disabled.
  1265. //
  1266. //------------------------------------------------------------------------------
  1267. VOID
  1268. vDisableText(PDev* ppdev)
  1269. {
  1270. DBG_GDI((6, "vDisableText"));
  1271. }// vDisableText()
  1272. //-----------------------------Public*Routine-----------------------------------
  1273. // vAssertModeText
  1274. // ppdev (I) - pointer to physical device object
  1275. // bEnable (I) - TRUE to enable accelerated text, FALSE to disable
  1276. // accelerated test.
  1277. //
  1278. // Called when going to/from full screen mode.
  1279. //
  1280. //@@BEGIN_DDKSPLIT
  1281. // TODO: check to see if this is also called when setting modes.
  1282. //@@END_DDKSPLIT
  1283. //
  1284. //------------------------------------------------------------------------------
  1285. VOID vAssertModeText(PDev* ppdev, BOOL bEnable)
  1286. {
  1287. DBG_GDI((5, "vAssertModeText"));
  1288. if (!bEnable)
  1289. vDisableText(ppdev);
  1290. else
  1291. {
  1292. bEnableText(ppdev);
  1293. }
  1294. }// vAssertModeText()
  1295. //-----------------------------Public-Routine-----------------------------------
  1296. // DrvDestroyFont
  1297. // pfo (I) - pointer to the font object
  1298. // pco (I) - pointer to the clip region object
  1299. // prclExtra (I) - If we had set GCAPS_HORIZSTRIKE, we would have to
  1300. // fill these extra rectangles (it is used largely
  1301. // for underlines). It's not a big performance win
  1302. // (GDI will call our DrvBitBlt to draw these).
  1303. // prclOpaque (I) - pointer to the opaque background rectangle
  1304. // pboFore (I) - pointer to the foreground brush object
  1305. // pboOpaque (I) - ptr to the brush for the opaque background rectangle
  1306. // pptlBrush (I) - pointer to the brush origin, Always unused, unless
  1307. // GCAPS_ARBRUSHOPAQUE set
  1308. // mix (I) - should always be a COPY operation
  1309. //
  1310. // Frees any cached information we've stored with the font. This routine
  1311. // is relevant only when caching glyphs.
  1312. //
  1313. // We're being notified that the given font is being deallocated; clean up
  1314. // anything we've stashed in the 'pvConsumer' field of the 'pfo'.
  1315. //
  1316. // Note: Don't forget to export this call in 'enable.c', otherwise you'll
  1317. // get some pretty big memory leaks!
  1318. //
  1319. //------------------------------------------------------------------------------
  1320. VOID DrvDestroyFont(FONTOBJ* pfo)
  1321. {
  1322. CACHEDFONT* pcf;
  1323. pcf = (CACHEDFONT*) pfo->pvConsumer;
  1324. if (pcf != NULL)
  1325. {
  1326. GLYPHALLOC* pga;
  1327. GLYPHALLOC* pgaNext;
  1328. pga = pcf->pgaChain;
  1329. while (pga != NULL)
  1330. {
  1331. pgaNext = pga->pgaNext;
  1332. ENGFREEMEM(pga);
  1333. pga = pgaNext;
  1334. }
  1335. ENGFREEMEM(pcf);
  1336. pfo->pvConsumer = NULL;
  1337. }
  1338. }// DrvDestroyFont()
  1339. // Work in progress
  1340. VOID
  1341. vCheckGdiContext(PPDev ppdev)
  1342. {
  1343. HwDataPtr permediaInfo = ppdev->permediaInfo;
  1344. ASSERTDD(ppdev->bEnabled,
  1345. "vCheckContext(): expect the device to be enabled");
  1346. if(permediaInfo->pCurrentCtxt != permediaInfo->pGDICtxt)
  1347. {
  1348. P2SwitchContext(ppdev, permediaInfo->pGDICtxt);
  1349. }
  1350. }
  1351. void FASTCALL InputBufferSwap(PPDev ppdev)
  1352. {
  1353. ASSERTDD(ppdev->bGdiContext, "InputBufferSwap: not in gdi context");
  1354. //@@BEGIN_DDKSPLIT
  1355. ASSERTLOCK(ppdev, InputBufferSwap);
  1356. //@@END_DDKSPLIT
  1357. if(ppdev->dmaBufferVirtualAddress != NULL)
  1358. {
  1359. LONG lUsed = (LONG)(ppdev->pulInFifoPtr - ppdev->pulInFifoStart);
  1360. while(READ_REGISTER_ULONG(ppdev->pulInputDmaCount) != 0)
  1361. {
  1362. // do nothing
  1363. }
  1364. LONG offset = (LONG)((LONG_PTR)ppdev->pulInFifoStart - (LONG_PTR)ppdev->dmaBufferVirtualAddress);
  1365. LONG address = ppdev->dmaBufferPhysicalAddress.LowPart + offset;
  1366. WRITE_REGISTER_ULONG(ppdev->pulInputDmaAddress, address);
  1367. MEMORY_BARRIER();
  1368. WRITE_REGISTER_ULONG(ppdev->pulInputDmaCount,lUsed);
  1369. MEMORY_BARRIER();
  1370. if(ppdev->pulInFifoStart == ppdev->dmaBufferVirtualAddress)
  1371. ppdev->pulInFifoStart += (INPUT_BUFFER_SIZE>>3);
  1372. else
  1373. ppdev->pulInFifoStart = ppdev->dmaBufferVirtualAddress;
  1374. ppdev->pulInFifoEnd = ppdev->pulInFifoStart + (INPUT_BUFFER_SIZE>>3);
  1375. ppdev->pulInFifoPtr = ppdev->pulInFifoStart;
  1376. }
  1377. else
  1378. {
  1379. ULONG* pul = ppdev->pulInFifoStart;
  1380. ULONG available = 0;
  1381. while(pul < ppdev->pulInFifoPtr)
  1382. {
  1383. while(available == 0)
  1384. {
  1385. available = READ_REGISTER_ULONG(ppdev->pulInputFifoCount);
  1386. if(available == 0)
  1387. {
  1388. StallExecution(ppdev->hDriver, 1);
  1389. }
  1390. }
  1391. WRITE_REGISTER_ULONG(ppdev->pulFifo, *pul++);
  1392. MEMORY_BARRIER();
  1393. available--;
  1394. }
  1395. ppdev->pulInFifoPtr = ppdev->pulInFifoStart;
  1396. }
  1397. }
  1398. void FASTCALL InputBufferFlush(PPDev ppdev)
  1399. {
  1400. ASSERTDD(ppdev->bGdiContext, "InputBufferFlush: not in gdi context");
  1401. //@@BEGIN_DDKSPLIT
  1402. ASSERTLOCK(ppdev, InputBufferFlush);
  1403. //@@END_DDKSPLIT
  1404. ppdev->bNeedSync = TRUE;
  1405. if(ppdev->dmaBufferVirtualAddress != NULL)
  1406. {
  1407. if(READ_REGISTER_ULONG(ppdev->pulInputDmaCount) == 0)
  1408. InputBufferSwap(ppdev);
  1409. }
  1410. else
  1411. {
  1412. InputBufferSwap(ppdev);
  1413. }
  1414. }
  1415. //
  1416. // Used for debugging purposes to record whether the driver had to
  1417. // bail out of the while loop inside InputBufferSync
  1418. //
  1419. ULONG gSyncInfiniteLoopCount = 0;
  1420. VOID
  1421. InputBufferSync(PPDev ppdev)
  1422. {
  1423. ASSERTDD(ppdev->bGdiContext, "InputBufferSync: not in gdi context");
  1424. //@@BEGIN_DDKSPLIT
  1425. ASSERTLOCK(ppdev, InputBufferSync);
  1426. //@@END_DDKSPLIT
  1427. ULONG * pBuffer;
  1428. if(ppdev->bNeedSync)
  1429. {
  1430. DBG_GDI((6, "InputBufferSync()"));
  1431. InputBufferReserve(ppdev, 6, &pBuffer);
  1432. pBuffer[0] = __Permedia2TagFilterMode;
  1433. pBuffer[1] = 0x400;
  1434. pBuffer[2] = __Permedia2TagSync;
  1435. pBuffer[3] = 0L;
  1436. pBuffer[4] =__Permedia2TagFilterMode;
  1437. pBuffer[5] = 0x0;
  1438. pBuffer += 6;
  1439. InputBufferCommit(ppdev, pBuffer);
  1440. InputBufferSwap(ppdev);
  1441. if(ppdev->dmaBufferVirtualAddress != NULL)
  1442. {
  1443. while(READ_REGISTER_ULONG(ppdev->pulInputDmaCount) != 0)
  1444. {
  1445. StallExecution(ppdev->hDriver, 1);
  1446. }
  1447. }
  1448. while(1)
  1449. {
  1450. ULONG ulStallCount = 0;
  1451. while(READ_REGISTER_ULONG(ppdev->pulOutputFifoCount) == 0)
  1452. {
  1453. StallExecution(ppdev->hDriver, 1);
  1454. // If we are stuck here for one seconds then break
  1455. // out of the loop. We have noticed that we will
  1456. // occasionally hit this case and are able to
  1457. // continue without futher problems. This really
  1458. // should never happen but we have been unable to
  1459. // find the cause of these occasional problems.
  1460. if(++ulStallCount == 1000000)
  1461. {
  1462. DBG_GDI((6, "InputBufferSync(): infinite loop detected"));
  1463. gSyncInfiniteLoopCount++;
  1464. goto bail;
  1465. }
  1466. }
  1467. ULONG data = READ_REGISTER_ULONG(ppdev->pulFifo);
  1468. if(data != __Permedia2TagSync)
  1469. {
  1470. DBG_GDI((0, "Data other then sync found at output fifo"));
  1471. }
  1472. else
  1473. {
  1474. break;
  1475. }
  1476. }
  1477. bail:
  1478. ppdev->bNeedSync = FALSE;
  1479. }
  1480. }
  1481. #if DBG
  1482. void InputBufferStart(
  1483. PPDev ppdev,
  1484. ULONG ulLongs,
  1485. PULONG* ppulBuffer,
  1486. PULONG* ppulBufferEnd,
  1487. PULONG* ppulReservationEnd)
  1488. {
  1489. ASSERTDD(ppdev->bGdiContext, "InputBufferStart: not in gdi context");
  1490. ASSERTDD(ppdev->ulReserved == 0,
  1491. "InputBufferStart: called with outstanding reservation");
  1492. //@@BEGIN_DDKSPLIT
  1493. ASSERTLOCK(ppdev, InputBufferStart);
  1494. //@@END_DDKSPLIT
  1495. *(ppulBuffer) = ppdev->pulInFifoPtr;
  1496. *(ppulReservationEnd) = *(ppulBuffer) + ulLongs;
  1497. *(ppulBufferEnd) = ppdev->pulInFifoEnd;
  1498. if(*(ppulReservationEnd) > *(ppulBufferEnd))
  1499. {
  1500. InputBufferSwap(ppdev);
  1501. *(ppulBuffer) = ppdev->pulInFifoPtr;
  1502. *(ppulReservationEnd) = *(ppulBuffer) + ulLongs;
  1503. *(ppulBufferEnd) = ppdev->pulInFifoEnd;
  1504. }
  1505. for(int index = 0; index < (int) ulLongs; index++)
  1506. ppdev->pulInFifoPtr[index] = 0xDEADBEEF;
  1507. ppdev->ulReserved = ulLongs;
  1508. }
  1509. void InputBufferContinue(
  1510. PPDev ppdev,
  1511. ULONG ulLongs,
  1512. PULONG* ppulBuffer,
  1513. PULONG* ppulBufferEnd,
  1514. PULONG* ppulReservationEnd)
  1515. {
  1516. ASSERTDD(ppdev->bGdiContext, "InputBufferContinue: not in gdi context");
  1517. //@@BEGIN_DDKSPLIT
  1518. ASSERTLOCK(ppdev, InputBufferContinue);
  1519. //@@END_DDKSPLIT
  1520. LONG lUsed = (LONG)(*(ppulBuffer) - ppdev->pulInFifoPtr);
  1521. if(lUsed > (LONG) ppdev->ulReserved)
  1522. {
  1523. DebugPrint(0, "InputBuffeContinue: exceeded reservation %d (%d)",
  1524. ppdev->ulReserved, lUsed);
  1525. EngDebugBreak();
  1526. }
  1527. for(int index = 0; index < lUsed; index++)
  1528. if(ppdev->pulInFifoPtr[index] == 0xDEADBEEF)
  1529. {
  1530. DebugPrint(0, "InputBufferContinue: buffer entry %d not set", index);
  1531. EngDebugBreak();
  1532. }
  1533. ppdev->pulInFifoPtr = *(ppulBuffer);
  1534. *(ppulReservationEnd) = *(ppulBuffer) + ulLongs;
  1535. if(*(ppulReservationEnd) > *(ppulBufferEnd))
  1536. {
  1537. InputBufferSwap(ppdev);
  1538. *(ppulBuffer) = ppdev->pulInFifoPtr;
  1539. *(ppulReservationEnd) = *(ppulBuffer) + ulLongs;
  1540. *(ppulBufferEnd) = ppdev->pulInFifoEnd;
  1541. }
  1542. for(index = 0; index < (int) ulLongs; index++)
  1543. ppdev->pulInFifoPtr[index] = 0xDEADBEEF;
  1544. ppdev->ulReserved = ulLongs;
  1545. }
  1546. void InputBufferReserve(
  1547. PPDev ppdev,
  1548. ULONG ulLongs,
  1549. PULONG* ppulBuffer)
  1550. {
  1551. ASSERTDD(ppdev->bGdiContext, "InputBufferReserve: not in gdi context");
  1552. ASSERTDD(ppdev->ulReserved == 0,
  1553. "InputBufferReserve: called with outstanding reservation");
  1554. //@@BEGIN_DDKSPLIT
  1555. ASSERTLOCK(ppdev, InputBufferReserve);
  1556. //@@END_DDKSPLIT
  1557. if(ppdev->pulInFifoPtr + ulLongs > ppdev->pulInFifoEnd)
  1558. {
  1559. InputBufferSwap(ppdev);
  1560. }
  1561. *(ppulBuffer) = ppdev->pulInFifoPtr;
  1562. for(int index = 0; index < (int) ulLongs; index++)
  1563. ppdev->pulInFifoPtr[index] = 0xDEADBEEF;
  1564. ppdev->ulReserved = ulLongs;
  1565. }
  1566. void InputBufferCommit(
  1567. PPDev ppdev,
  1568. PULONG pulBuffer)
  1569. {
  1570. ASSERTDD(ppdev->bGdiContext, "InputBufferCommit: not in gdi context");
  1571. //@@BEGIN_DDKSPLIT
  1572. ASSERTLOCK(ppdev, InputBufferCommit);
  1573. //@@END_DDKSPLIT
  1574. LONG lUsed = (LONG)(pulBuffer - ppdev->pulInFifoPtr);
  1575. if(lUsed > (LONG) ppdev->ulReserved)
  1576. {
  1577. DebugPrint(0, "InputBuffeCommit: exceeded reservation %d (%d)",
  1578. ppdev->ulReserved, lUsed);
  1579. EngDebugBreak();
  1580. }
  1581. ppdev->ulReserved = 0;
  1582. for(int index = 0; index < lUsed; index++)
  1583. if(ppdev->pulInFifoPtr[index] == 0xDEADBEEF)
  1584. {
  1585. DebugPrint(0, "InputBuffer Commit: buffer entry %d not set", index);
  1586. EngDebugBreak();
  1587. }
  1588. ppdev->pulInFifoPtr = pulBuffer;
  1589. }
  1590. #endif