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.

400 lines
14 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: TextOut.c
  3. *
  4. * Text
  5. *
  6. * Copyright (c) 1992 Microsoft Corporation
  7. *
  8. \**************************************************************************/
  9. #include "driver.h"
  10. BOOL vFastText(PDEV *, GLYPHPOS *, ULONG, PBYTE, ULONG, ULONG, RECTL *,
  11. RECTL *, INT, INT, ULONG);
  12. VOID lclFillRect(CLIPOBJ *, ULONG, PRECTL, PPDEV, INT);
  13. #define FIFTEEN_BITS ((1 << 15)-1)
  14. #define TAKING_ALLOC_STATS 0
  15. #if TAKING_ALLOC_STATS
  16. ULONG BufferHitInText = 0;
  17. ULONG BufferMissInText = 0;
  18. #endif
  19. /****************************************************************************
  20. * DrvTextOut
  21. ***************************************************************************/
  22. BOOL DrvTextOut(
  23. SURFOBJ* pso,
  24. STROBJ* pstro,
  25. FONTOBJ* pfo,
  26. CLIPOBJ* pco,
  27. RECTL* prclExtra,
  28. RECTL* prclOpaque,
  29. BRUSHOBJ* pboFore,
  30. BRUSHOBJ* pboOpaque,
  31. POINTL* pptlOrg,
  32. MIX mix)
  33. {
  34. BOOL b;
  35. PPDEV ppdev;
  36. INT iClip; // clip object's complexity
  37. ULONG iSolidForeColor; // Solid foreground color
  38. ULONG iSolidBkColor; // Solid background color
  39. RECTL arclTmp[4]; // Temp storage for portions of opaquing rect
  40. ULONG culRcl; // Temp rectangle count
  41. PVOID pvBuf; // pointer to buffer we'll use
  42. ULONG ulBufferWidthInBytes;
  43. ULONG ulBufferHeight;
  44. ULONG ulBufferBytes;
  45. BOOL bTextPerfectFit;
  46. ULONG fDrawFlags;
  47. ppdev = (PPDEV) pso->dhpdev;
  48. //---------------------------------------------------------------------
  49. // Get information about clip object.
  50. //---------------------------------------------------------------------
  51. iClip = DC_TRIVIAL;
  52. if (pco != NULL) {
  53. iClip = pco->iDComplexity;
  54. }
  55. //---------------------------------------------------------------------
  56. // Get text color.
  57. //---------------------------------------------------------------------
  58. iSolidForeColor = pboFore->iSolidColor;
  59. //---------------------------------------------------------------------
  60. // See if this is text we can handle faster with special-case code.
  61. //---------------------------------------------------------------------
  62. if (((ppdev->fl & DRIVER_PLANAR_CAPABLE) ||
  63. (prclOpaque == (PRECTL) NULL)) && // opaque only if planar for now
  64. // LATER implement fast non-planar
  65. // opaque
  66. (iClip == DC_TRIVIAL) && // no clipping for now
  67. ((pstro->rclBkGround.right & ~0x03) >
  68. ((pstro->rclBkGround.left + 3) & ~0x03)) &&
  69. // not if no full nibbles spanned
  70. // for now @@@
  71. (pstro->pgp != NULL) && // no glyph enumeration for now
  72. (prclExtra == NULL) && // no extra rects for now
  73. ((pstro->flAccel & (SO_HORIZONTAL | SO_VERTICAL | SO_REVERSED)) ==
  74. SO_HORIZONTAL)) { // only left-to-right text for now
  75. // It's the type of text we can special-case; see if the temp buffer is
  76. // big enough for the text.
  77. ulBufferWidthInBytes = ((((pstro->rclBkGround.right + 7) & ~0x07) -
  78. (pstro->rclBkGround.left & ~0x07)) >> 3);
  79. ulBufferHeight = pstro->rclBkGround.bottom - pstro->rclBkGround.top;
  80. ulBufferBytes = ulBufferWidthInBytes * ulBufferHeight;
  81. if ((ulBufferWidthInBytes > FIFTEEN_BITS) ||
  82. (ulBufferHeight > FIFTEEN_BITS))
  83. {
  84. // the math will have overflowed
  85. return(FALSE);
  86. }
  87. if (ulBufferBytes <= GLOBAL_BUFFER_SIZE)
  88. {
  89. #if TAKING_ALLOC_STATS
  90. BufferHitInText++;
  91. #endif
  92. pvBuf = ppdev->pvTmpBuf;
  93. }
  94. else
  95. {
  96. #if TAKING_ALLOC_STATS
  97. BufferMissInText++;
  98. #endif
  99. pvBuf = EngAllocUserMem(ulBufferBytes, ALLOC_TAG);
  100. if (!pvBuf)
  101. {
  102. goto no_special_case;
  103. }
  104. }
  105. // It's big enough; set up for the accelerator
  106. // Set fixed pitch, overlap, and top & bottom Y alignment flags
  107. fDrawFlags = ((pstro->ulCharInc != 0) ? 0x01 : 0) |
  108. (((pstro->flAccel & (SO_ZERO_BEARINGS |
  109. SO_FLAG_DEFAULT_PLACEMENT)) !=
  110. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT))
  111. ? 0x02 : 0) |
  112. (((pstro->flAccel & (SO_ZERO_BEARINGS |
  113. SO_FLAG_DEFAULT_PLACEMENT |
  114. SO_MAXEXT_EQUAL_BM_SIDE)) ==
  115. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  116. SO_MAXEXT_EQUAL_BM_SIDE)) ? 0x04 : 0);
  117. // If there's an opaque rectangle, we'll do as much opaquing as
  118. // possible as we do the text. If the opaque rectangle is larger
  119. // than the text rectangle, then we'll do the fringe areas right
  120. // now, and the text and associated background areas together,
  121. // later.
  122. if (prclOpaque != (PRECTL) NULL) {
  123. // This driver only handles solid brushes
  124. iSolidBkColor = pboOpaque->iSolidColor;
  125. // See if we have fringe areas to do. If so, build a list of
  126. // rectangles to fill, in rightdown order
  127. culRcl = 0;
  128. // Top fragment
  129. if (pstro->rclBkGround.top > prclOpaque->top) {
  130. arclTmp[culRcl].top = prclOpaque->top;
  131. arclTmp[culRcl].left = prclOpaque->left;
  132. arclTmp[culRcl].right = prclOpaque->right;
  133. arclTmp[culRcl++].bottom = pstro->rclBkGround.top;
  134. }
  135. // Left fragment
  136. if (pstro->rclBkGround.left > prclOpaque->left) {
  137. arclTmp[culRcl].top = pstro->rclBkGround.top;
  138. arclTmp[culRcl].left = prclOpaque->left;
  139. arclTmp[culRcl].right = pstro->rclBkGround.left;
  140. arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom;
  141. }
  142. // Right fragment
  143. if (pstro->rclBkGround.right < prclOpaque->right) {
  144. arclTmp[culRcl].top = pstro->rclBkGround.top;
  145. arclTmp[culRcl].right = prclOpaque->right;
  146. arclTmp[culRcl].left = pstro->rclBkGround.right;
  147. arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom;
  148. }
  149. // Bottom fragment
  150. if (pstro->rclBkGround.bottom < prclOpaque->bottom) {
  151. arclTmp[culRcl].bottom = prclOpaque->bottom;
  152. arclTmp[culRcl].left = prclOpaque->left;
  153. arclTmp[culRcl].right = prclOpaque->right;
  154. arclTmp[culRcl++].top = pstro->rclBkGround.bottom;
  155. }
  156. if (culRcl != 0) {
  157. if (iClip == DC_TRIVIAL) {
  158. vTrgBlt(ppdev, culRcl, arclTmp, R2_COPYPEN,
  159. *((RBRUSH_COLOR*) &iSolidBkColor), NULL);
  160. } else {
  161. lclFillRect(pco, culRcl, arclTmp, ppdev,
  162. iSolidBkColor);
  163. }
  164. }
  165. }
  166. // We're done with separate opaquing; any further opaquing will
  167. // happen as part of the text drawing
  168. // Clear the buffer if the text isn't going to set every bit
  169. bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
  170. SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
  171. SO_CHAR_INC_EQUAL_BM_BASE)) ==
  172. (SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
  173. SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
  174. if (!bTextPerfectFit) {
  175. vClearMemDword(pvBuf, (ulBufferBytes + 3) >> 2);
  176. }
  177. // Draw the text into the temp buffer, and thence to the screen
  178. vFastText(ppdev,
  179. pstro->pgp,
  180. pstro->cGlyphs,
  181. pvBuf,
  182. ulBufferWidthInBytes,
  183. pstro->ulCharInc,
  184. &pstro->rclBkGround,
  185. prclOpaque,
  186. iSolidForeColor,
  187. iSolidBkColor,
  188. fDrawFlags);
  189. // free any memory that was allocated
  190. if (ulBufferBytes > GLOBAL_BUFFER_SIZE)
  191. {
  192. // we had to have allocated memory
  193. EngFreeUserMem (pvBuf);
  194. }
  195. return(TRUE);
  196. }
  197. no_special_case:
  198. // Can't special-case; let the engine draw the text
  199. pso = ppdev->pSurfObj;
  200. // It may be that the opaquing rectangle is larger than the text rectangle,
  201. // so we'll want to use that to tell the bank manager which banks to
  202. // enumerate:
  203. pco = pcoBankStart(ppdev,
  204. (prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround,
  205. pso,
  206. pco);
  207. do {
  208. b = EngTextOut(pso,
  209. pstro,
  210. pfo,
  211. pco,
  212. prclExtra,
  213. prclOpaque,
  214. pboFore,
  215. pboOpaque,
  216. pptlOrg,
  217. mix);
  218. } while (b && bBankEnum(ppdev, pso, pco));
  219. return(b);
  220. }
  221. //--------------------------------------------------------------------------
  222. // Fills the specified rectangles on the specified surface with the
  223. // specified color, honoring the requested clipping. No more than four
  224. // rectangles should be passed in. Intended for drawing the areas of the
  225. // opaquing rectangle that extended beyond the text box. The rectangles must
  226. // be in left to right, top to bottom order. Assumes there is at least one
  227. // rectangle in the list.
  228. //--------------------------------------------------------------------------
  229. VOID lclFillRect(
  230. CLIPOBJ *pco,
  231. ULONG culRcl,
  232. PRECTL prcl,
  233. PPDEV ppdev,
  234. INT iColor)
  235. {
  236. BOOL bMore; // Flag for clip enumeration
  237. TEXTENUM txen; // Clip enumeration object
  238. ULONG i, j;
  239. RECTL arclTmp[4];
  240. ULONG culRclTmp;
  241. RECTL *prclTmp, *prclClipTmp;
  242. INT iLastBottom;
  243. RECTL *pClipRcl;
  244. INT iClip;
  245. iClip = DC_TRIVIAL;
  246. if (pco != NULL) {
  247. iClip = pco->iDComplexity;
  248. }
  249. switch ( iClip ) {
  250. case DC_TRIVIAL:
  251. vTrgBlt(ppdev, culRcl, prcl, R2_COPYPEN,
  252. *((RBRUSH_COLOR*) &iColor), NULL);
  253. break;
  254. case DC_RECT:
  255. prclTmp = &pco->rclBounds;
  256. // Generate a list of clipped rects
  257. for (culRclTmp=0, i=0; i<culRcl; i++, prcl++) {
  258. // Intersect fill and clip rectangles
  259. if (bIntersectRect(&arclTmp[culRclTmp], prcl, prclTmp)) {
  260. // Add to list if anything's left to draw
  261. culRclTmp++;
  262. }
  263. }
  264. // Draw the clipped rects
  265. if (culRclTmp != 0) {
  266. vTrgBlt(ppdev, culRclTmp, arclTmp, R2_COPYPEN,
  267. *((RBRUSH_COLOR*) &iColor), NULL);
  268. }
  269. break;
  270. case DC_COMPLEX:
  271. // Bottom of last rectangle to fill
  272. iLastBottom = prcl[culRcl-1].bottom;
  273. // Initialize the clip rectangle enumeration to rightdown so we can
  274. // take advantage of the rectangle list being rightdown
  275. CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN,
  276. TO_RECT_LIMIT);
  277. // Scan through all the clip rectangles, looking for intersects
  278. // of fill areas with region rectangles
  279. do {
  280. // Get a batch of region rectangles
  281. bMore = CLIPOBJ_bEnum(pco, (ULONG)sizeof(txen), (PVOID)&txen);
  282. // Clip the rect list to each region rect
  283. for (j = txen.c, pClipRcl = txen.arcl; j-- > 0; pClipRcl++) {
  284. // Since the rectangles and the region enumeration are both
  285. // rightdown, we can zip through the region until we reach
  286. // the first fill rect, and are done when we've passed the
  287. // last fill rect.
  288. if (pClipRcl->top >= iLastBottom) {
  289. // Past last fill rectangle; nothing left to do
  290. return;
  291. }
  292. // Do intersection tests only if we've reached the top of
  293. // the first rectangle to fill
  294. if (pClipRcl->bottom > prcl->top) {
  295. // We've reached the top Y scan of the first rect, so
  296. // it's worth bothering checking for intersection
  297. // Generate a list of the rects clipped to this region
  298. // rect
  299. prclTmp = prcl;
  300. prclClipTmp = arclTmp;
  301. for (i = culRcl, culRclTmp=0; i-- > 0; prclTmp++) {
  302. // Intersect fill and clip rectangles
  303. if (bIntersectRect(prclClipTmp, prclTmp,
  304. pClipRcl)) {
  305. // Add to list if anything's left to draw
  306. culRclTmp++;
  307. prclClipTmp++;
  308. }
  309. }
  310. // Draw the clipped rects
  311. if (culRclTmp != 0) {
  312. vTrgBlt(ppdev, culRclTmp, arclTmp, R2_COPYPEN,
  313. *((RBRUSH_COLOR*) &iColor), NULL);
  314. }
  315. }
  316. }
  317. } while (bMore);
  318. break;
  319. }
  320. }